From f8c4b98b7b8759b518fe4fc5e52429d36e2e40bc Mon Sep 17 00:00:00 2001 From: Max Patiiuk Date: Sun, 23 Jun 2024 07:56:34 -0700 Subject: [PATCH 1/4] chore: update to prettier 3 --- specifyweb/frontend/js_src/.prettierignore | 14 +- specifyweb/frontend/js_src/package-lock.json | 247 +++++++++++++----- specifyweb/frontend/js_src/package.json | 7 +- specifyweb/frontend/js_src/prettier.config.js | 23 ++ 4 files changed, 214 insertions(+), 77 deletions(-) create mode 100644 specifyweb/frontend/js_src/prettier.config.js diff --git a/specifyweb/frontend/js_src/.prettierignore b/specifyweb/frontend/js_src/.prettierignore index bba6a529dea..7fec54fbb52 100644 --- a/specifyweb/frontend/js_src/.prettierignore +++ b/specifyweb/frontend/js_src/.prettierignore @@ -1,4 +1,16 @@ /lib/tests/fixtures/ /lib/tests/ajax/static -/lib/components/DataModel/*.js *.snap +/../templates/ +/../../context/data/ +/../../../.git/ +/../../../config/ +/../static/img/ +/../../specify/fixtures/ +# Uses case sensitive markdown - incompatible with our Prettier config +/../../../.github/ISSUE_TEMPLATE/ +# Skipping in case people don't want line wrapping in this file +/../../../CHANGELOG.md +/../../../release-notes/ +# Prettier fails to parse the syntax in Dockerfile +/../../../Dockerfile diff --git a/specifyweb/frontend/js_src/package-lock.json b/specifyweb/frontend/js_src/package-lock.json index 9af8a1c88f1..4343491a49a 100644 --- a/specifyweb/frontend/js_src/package-lock.json +++ b/specifyweb/frontend/js_src/package-lock.json @@ -51,9 +51,9 @@ "@babel/preset-env": "^7.18.9", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", + "@maxpatiiuk/prettier-config": "^2.0.0", "@maxxxxxdlp/eslint-config": "^5.0.0", "@maxxxxxdlp/eslint-config-react": "^3.0.0", - "@maxxxxxdlp/prettier-config": "^1.0.4", "@tailwindcss/forms": "^0.5.7", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.3.0", @@ -95,7 +95,7 @@ "postcss": "^8.4.14", "postcss-loader": "^8.1.0", "postcss-preset-env": "^7.7.2", - "prettier": "^2.7.1", + "prettier": "^3.4.1", "regenerator-runtime": "^0.13.9", "style-loader": "^3.3.4", "tailwindcss": "^3.4.1", @@ -3290,6 +3290,21 @@ "@lezer/lr": "^1.0.0" } }, + "node_modules/@maxpatiiuk/prettier-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@maxpatiiuk/prettier-config/-/prettier-config-2.0.0.tgz", + "integrity": "sha512-mwP2YswIkJ6wr+IIpVntTHcPvbhuGKv8ys+624rQaKIUFk7fIer/gc8MRjNNqtQp0hpBquR2scw1/3VQ0OSekQ==", + "dev": true, + "dependencies": { + "@prettier/plugin-xml": "^3.4.1", + "prettier-plugin-package": "^1.4.0", + "prettier-plugin-sh": "^0.14.0", + "prettier-plugin-tailwindcss": "^0.6.5" + }, + "peerDependencies": { + "prettier": ">= 3" + } + }, "node_modules/@maxxxxxdlp/eslint-config": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@maxxxxxdlp/eslint-config/-/eslint-config-5.0.0.tgz", @@ -3337,22 +3352,6 @@ "eslint": ">= 7" } }, - "node_modules/@maxxxxxdlp/prettier-config": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@maxxxxxdlp/prettier-config/-/prettier-config-1.0.4.tgz", - "integrity": "sha512-8uPAK/XVEK+LL91Z3DfoFCcDojMWKGfHynegJuHbJ0rM9nNh5h3sWCqofs9P1atkYzqku/VIyPt1FI5PZH8X/g==", - "dev": true, - "dependencies": { - "@prettier/plugin-xml": "^2.2.0", - "prettier-plugin-firebase-database": "^1.0.1", - "prettier-plugin-package": "^1.3.0", - "prettier-plugin-sh": "^0.12.6", - "prettier-plugin-tailwindcss": "^0.1.12" - }, - "peerDependencies": { - "prettier": ">= 2" - } - }, "node_modules/@microsoft/tsdoc": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", @@ -3433,12 +3432,15 @@ "dev": true }, "node_modules/@prettier/plugin-xml": { - "version": "2.2.0", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-3.4.1.tgz", + "integrity": "sha512-Uf/6/+9ez6z/IvZErgobZ2G9n1ybxF5BhCd7eMcKqfoWuOzzNUxBipNo3QAP8kRC1VD18TIo84no7LhqtyDcTg==", "dev": true, - "license": "MIT", "dependencies": { - "@xml-tools/parser": "^1.0.11", - "prettier": ">=2.4.0" + "@xml-tools/parser": "^1.0.11" + }, + "peerDependencies": { + "prettier": "^3.0.0" } }, "node_modules/@remix-run/router": { @@ -13625,63 +13627,124 @@ } }, "node_modules/prettier": { - "version": "2.7.1", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-plugin-firebase-database": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier": "^2.3.0" - } - }, "node_modules/prettier-plugin-package": { - "version": "1.3.0", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-package/-/prettier-plugin-package-1.4.0.tgz", + "integrity": "sha512-jy8UjgHadyznzWfunyjPQPqE2Y92TVF3Q0O829X6pk/ARoKn0vtSu+mtKIsmikZYb2N50mV6vRIqCf19XdOdIg==", "dev": true, - "license": "MPL-2.0", "engines": { "node": ">=10.13.0" }, "peerDependencies": { - "prettier": "^2.0.0" + "prettier": "^2.0.0 || ^3.0.0" } }, "node_modules/prettier-plugin-sh": { - "version": "0.12.6", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.14.0.tgz", + "integrity": "sha512-hfXulj5+zEl/ulrO5kMuuTPKmXvOg0bnLHY1hKFNN/N+/903iZbNp8NyZBTsgI8dtkSgFfAEIQq0IQTyP1ZVFQ==", "dev": true, - "license": "MIT", "dependencies": { - "mvdan-sh": "^0.10.1" + "mvdan-sh": "^0.10.1", + "sh-syntax": "^0.4.1" }, "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": ">=16.0.0" }, "funding": { "url": "https://opencollective.com/unts" }, "peerDependencies": { - "prettier": "^2.0.0" + "prettier": "^3.0.3" } }, "node_modules/prettier-plugin-tailwindcss": { - "version": "0.1.12", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.5.tgz", + "integrity": "sha512-axfeOArc/RiGHjOIy9HytehlC0ZLeMaqY09mm8YCkMzznKiDkwFzOpBvtuhuv3xG5qB73+Mj7OCe2j/L1ryfuQ==", "dev": true, "engines": { - "node": ">=12.17.0" + "node": ">=14.21.3" }, "peerDependencies": { - "prettier": ">=2.2.0" + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig-melody": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "@zackad/prettier-plugin-twig-melody": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + } } }, "node_modules/pretty-format": { @@ -14553,6 +14616,27 @@ "node": ">=0.10.0" } }, + "node_modules/sh-syntax": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.4.2.tgz", + "integrity": "sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg==", + "dev": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/sh-syntax/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/shallow-clone": { "version": "3.0.1", "dev": true, @@ -19118,6 +19202,18 @@ "@lezer/lr": "^1.0.0" } }, + "@maxpatiiuk/prettier-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@maxpatiiuk/prettier-config/-/prettier-config-2.0.0.tgz", + "integrity": "sha512-mwP2YswIkJ6wr+IIpVntTHcPvbhuGKv8ys+624rQaKIUFk7fIer/gc8MRjNNqtQp0hpBquR2scw1/3VQ0OSekQ==", + "dev": true, + "requires": { + "@prettier/plugin-xml": "^3.4.1", + "prettier-plugin-package": "^1.4.0", + "prettier-plugin-sh": "^0.14.0", + "prettier-plugin-tailwindcss": "^0.6.5" + } + }, "@maxxxxxdlp/eslint-config": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@maxxxxxdlp/eslint-config/-/eslint-config-5.0.0.tgz", @@ -19158,19 +19254,6 @@ "eslint-plugin-testing-library": "^5.9.1" } }, - "@maxxxxxdlp/prettier-config": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@maxxxxxdlp/prettier-config/-/prettier-config-1.0.4.tgz", - "integrity": "sha512-8uPAK/XVEK+LL91Z3DfoFCcDojMWKGfHynegJuHbJ0rM9nNh5h3sWCqofs9P1atkYzqku/VIyPt1FI5PZH8X/g==", - "dev": true, - "requires": { - "@prettier/plugin-xml": "^2.2.0", - "prettier-plugin-firebase-database": "^1.0.1", - "prettier-plugin-package": "^1.3.0", - "prettier-plugin-sh": "^0.12.6", - "prettier-plugin-tailwindcss": "^0.1.12" - } - }, "@microsoft/tsdoc": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", @@ -19235,11 +19318,12 @@ "dev": true }, "@prettier/plugin-xml": { - "version": "2.2.0", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-3.4.1.tgz", + "integrity": "sha512-Uf/6/+9ez6z/IvZErgobZ2G9n1ybxF5BhCd7eMcKqfoWuOzzNUxBipNo3QAP8kRC1VD18TIo84no7LhqtyDcTg==", "dev": true, "requires": { - "@xml-tools/parser": "^1.0.11", - "prettier": ">=2.4.0" + "@xml-tools/parser": "^1.0.11" } }, "@remix-run/router": { @@ -26370,30 +26454,32 @@ "dev": true }, "prettier": { - "version": "2.7.1", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true }, - "prettier-plugin-firebase-database": { - "version": "1.0.1", - "dev": true, - "requires": { - "prettier": "^2.3.0" - } - }, "prettier-plugin-package": { - "version": "1.3.0", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-package/-/prettier-plugin-package-1.4.0.tgz", + "integrity": "sha512-jy8UjgHadyznzWfunyjPQPqE2Y92TVF3Q0O829X6pk/ARoKn0vtSu+mtKIsmikZYb2N50mV6vRIqCf19XdOdIg==", "dev": true, "requires": {} }, "prettier-plugin-sh": { - "version": "0.12.6", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.14.0.tgz", + "integrity": "sha512-hfXulj5+zEl/ulrO5kMuuTPKmXvOg0bnLHY1hKFNN/N+/903iZbNp8NyZBTsgI8dtkSgFfAEIQq0IQTyP1ZVFQ==", "dev": true, "requires": { - "mvdan-sh": "^0.10.1" + "mvdan-sh": "^0.10.1", + "sh-syntax": "^0.4.1" } }, "prettier-plugin-tailwindcss": { - "version": "0.1.12", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.5.tgz", + "integrity": "sha512-axfeOArc/RiGHjOIy9HytehlC0ZLeMaqY09mm8YCkMzznKiDkwFzOpBvtuhuv3xG5qB73+Mj7OCe2j/L1ryfuQ==", "dev": true, "requires": {} }, @@ -27013,6 +27099,23 @@ } } }, + "sh-syntax": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.4.2.tgz", + "integrity": "sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg==", + "dev": true, + "requires": { + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, "shallow-clone": { "version": "3.0.1", "dev": true, diff --git a/specifyweb/frontend/js_src/package.json b/specifyweb/frontend/js_src/package.json index 9d72cd7cfcf..7ea5fcc4e1c 100644 --- a/specifyweb/frontend/js_src/package.json +++ b/specifyweb/frontend/js_src/package.json @@ -71,9 +71,9 @@ "@babel/preset-env": "^7.18.9", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", + "@maxpatiiuk/prettier-config": "^2.0.0", "@maxxxxxdlp/eslint-config": "^5.0.0", "@maxxxxxdlp/eslint-config-react": "^3.0.0", - "@maxxxxxdlp/prettier-config": "^1.0.4", "@tailwindcss/forms": "^0.5.7", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.3.0", @@ -115,7 +115,7 @@ "postcss": "^8.4.14", "postcss-loader": "^8.1.0", "postcss-preset-env": "^7.7.2", - "prettier": "^2.7.1", + "prettier": "^3.4.1", "regenerator-runtime": "^0.13.9", "style-loader": "^3.3.4", "tailwindcss": "^3.4.1", @@ -143,6 +143,5 @@ }, "directories": { "test": "tests" - }, - "prettier": "@maxxxxxdlp/prettier-config" + } } diff --git a/specifyweb/frontend/js_src/prettier.config.js b/specifyweb/frontend/js_src/prettier.config.js new file mode 100644 index 00000000000..99fb13d8f0d --- /dev/null +++ b/specifyweb/frontend/js_src/prettier.config.js @@ -0,0 +1,23 @@ +import base from '@maxpatiiuk/prettier-config'; + +/** + * @see https://prettier.io/docs/en/configuration.html + * @type {import("prettier").Config} + */ +export default { + ...base, + /** + * Using the default value Prettier had in v2. + * We can change to the new default ("all" in v3) in the future - avoiding that + * for now to reduce merge conflicts with other pull requests. + */ + trailingComma: 'es5', + plugins: base.plugins?.filter( + (plugin) => + /* + * The plugin doesn't handle well multi-line classname strings with ${} in + * them - it turns them into one very long line, which is not readable. + */ + plugin !== 'prettier-plugin-tailwindcss' + ), +}; From a403515783b3ee703f477a2dbe4c503f5804bf2c Mon Sep 17 00:00:00 2001 From: Max Patiiuk Date: Sun, 23 Jun 2024 07:56:59 -0700 Subject: [PATCH 2/4] fix: remove duplicate key in Citation.cff --- CITATION.cff | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 2c4a7ea96fd..9f07def758c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,15 +9,11 @@ keywords: - open source identifiers: - type: url - value: 'https://www.specifysoftware.org/' + value: "https://www.specifysoftware.org/" description: Specify Collections Consortium abstract: >- - The Specify Collections Consortium research repositories - produce software platforms that process species and - specimen data. -keywords: - - collections management software - - open source + The Specify Collections Consortium research repositories produce software + platforms that process species and specimen data. license: GPL-2.0-only repository-code: specify/specify7 repository: "https://github.com/specify/specify7" From edd3504f688f9ecdde5c465bee92642bb73c40aa Mon Sep 17 00:00:00 2001 From: Max Patiiuk Date: Sun, 23 Jun 2024 08:02:54 -0700 Subject: [PATCH 3/4] refactor(l10n): update utils to Prettier 3 --- specifyweb/frontend/js_src/lib/localization/utils/updateFile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/frontend/js_src/lib/localization/utils/updateFile.ts b/specifyweb/frontend/js_src/lib/localization/utils/updateFile.ts index fda9b44c510..d8fff90255e 100644 --- a/specifyweb/frontend/js_src/lib/localization/utils/updateFile.ts +++ b/specifyweb/frontend/js_src/lib/localization/utils/updateFile.ts @@ -50,7 +50,7 @@ async function updateLocalFile( `$
${JSON.stringify(strings, null, 2)}$`
   );
   const config = (await resolvePrettierConfig()) ?? {};
-  const formatted = prettier.format(newContent, {
+  const formatted = await prettier.format(newContent, {
     ...config,
     parser: 'babel-ts',
   });

From 4c55cd0ccfb933de66a8561a82cce60a81f1b5da Mon Sep 17 00:00:00 2001
From: Max Patiiuk 
Date: Sat, 30 Nov 2024 08:27:38 -0800
Subject: [PATCH 4/4] refactor: reformat all files with Prettier 3

---
 .dockerignore                                 |   2 +-
 .github/pull-request-template.md              |   4 +-
 .github/workflows/docker.yml                  |  22 +-
 .gitignore                                    |   5 -
 .pre-commit-config.yaml                       |   6 +-
 CITATION.cff                                  |   6 +-
 CONTRIBUTING.md                               |  81 ++-
 README.md                                     | 305 ++++++------
 SECURITY.md                                   |  28 +-
 docker-entrypoint.sh                          |   6 -
 .../businessrules/uniqueness_rules.json       | 464 +++++++++---------
 specifyweb/frontend/js_src/.prettierignore    |   3 -
 specifyweb/frontend/js_src/css/main.css       |   4 +-
 specifyweb/frontend/js_src/css/workbench.css  |   7 +-
 .../AppResources/EditorComponents.tsx         |   8 +-
 .../AppResources/codeMirrorLinters.ts         |   4 +-
 .../components/AppResources/filtersHelpers.ts |  12 +-
 .../js_src/lib/components/Atoms/DataEntry.tsx |  20 +-
 .../js_src/lib/components/Atoms/wrapper.ts    |   2 +-
 .../lib/components/Attachments/index.tsx      |  18 +-
 .../AttachmentsBulkImport/Datasets.tsx        |   8 +-
 .../AttachmentsBulkImport/Upload.tsx          |   9 +-
 .../components/AttachmentsBulkImport/types.ts |  25 +-
 .../AttachmentsBulkImport/useEagerDataset.ts  |   4 +-
 .../components/AttachmentsBulkImport/utils.ts |  48 +-
 .../lib/components/DataEntryTables/Edit.tsx   |   4 +-
 .../DataModel/__tests__/resourceApi.test.ts   |  10 +-
 .../components/DataModel/addMissingFields.ts  |  14 +-
 .../components/DataModel/businessRuleDefs.ts  |   8 +-
 .../lib/components/DataModel/businessRules.ts |   4 +-
 .../lib/components/DataModel/collection.ts    |  20 +-
 .../lib/components/DataModel/helperTypes.ts   |  44 +-
 .../lib/components/DataModel/helpers.ts       |  18 +-
 .../lib/components/DataModel/legacyTypes.ts   |  32 +-
 .../lib/components/DataModel/resource.ts      |   2 +-
 .../lib/components/DataModel/resourceApi.ts   |  25 +-
 .../lib/components/DataModel/saveBlockers.tsx |  12 +-
 .../js_src/lib/components/DataModel/schema.ts |   4 +-
 .../lib/components/DataModel/schemaExtras.ts  |   2 +-
 .../lib/components/DataModel/scoping.ts       |   2 +-
 .../lib/components/DataModel/specifyField.ts  |  16 +-
 .../lib/components/DataModel/specifyTable.ts  |   2 +-
 .../js_src/lib/components/DataModel/tables.ts |   6 +-
 .../components/DataModel/treeBusinessRules.ts |   4 +-
 .../components/DataModel/uniquenessRules.ts   |   8 +-
 .../lib/components/Errors/ErrorBoundary.tsx   |   2 +-
 .../lib/components/Errors/FormatError.tsx     |   2 +-
 .../lib/components/Errors/JsonError.tsx       |   4 +-
 .../lib/components/Errors/interceptLogs.ts    |   2 +-
 .../lib/components/Errors/logContext.ts       |   4 +-
 .../js_src/lib/components/FormCells/index.tsx |  14 +-
 .../lib/components/FormCommands/index.tsx     |   2 +-
 .../lib/components/FormEditor/createView.ts   |   4 +-
 .../lib/components/FormEditor/index.tsx       |   2 +-
 .../lib/components/FormFields/Field.tsx       |   4 +-
 .../js_src/lib/components/FormParse/cells.ts  |  18 +-
 .../lib/components/FormParse/commands.ts      |   4 +-
 .../js_src/lib/components/FormParse/fields.ts |   4 +-
 .../js_src/lib/components/FormParse/index.ts  |  13 +-
 .../FormParse/postProcessFormDef.ts           |   4 +-
 .../lib/components/FormPlugins/DateInput.tsx  |  20 +-
 .../FormPlugins/DatePrecisionPicker.tsx       |   2 +-
 .../lib/components/FormPlugins/LatLongUi.tsx  |  10 +-
 .../lib/components/FormPlugins/Leaflet.tsx    |   5 +-
 .../lib/components/FormPlugins/useMoment.tsx  |   4 +-
 .../lib/components/Formatters/Components.tsx  |   6 +-
 .../lib/components/Formatters/Element.tsx     |   2 +-
 .../js_src/lib/components/Formatters/List.tsx |   2 +-
 .../lib/components/Formatters/Types.tsx       |   4 +-
 .../lib/components/Formatters/formatters.ts   |  14 +-
 .../lib/components/Formatters/index.tsx       |  14 +-
 .../lib/components/Forms/BaseResourceView.tsx |  18 +-
 .../lib/components/Forms/DeleteBlocked.tsx    |  12 +-
 .../lib/components/Forms/DeleteButton.tsx     |   2 +-
 .../lib/components/Forms/ShowResource.tsx     |   6 +-
 .../lib/components/Forms/dataObjFormatters.ts |  12 +-
 .../Forms/generateFormDefinition.ts           |  42 +-
 .../components/Header/ChooseCollection.tsx    |   2 +-
 .../components/Header/ExpressSearchHooks.tsx  |  13 +-
 .../js_src/lib/components/Header/index.tsx    |  12 +-
 .../lib/components/HomePage/TaxonTiles.tsx    |   2 +-
 .../components/HomePage/taxonTileHelpers.ts   |   2 +-
 .../lib/components/InitialContext/icons.ts    |   2 +-
 .../InitialContext/legacyUiLocalization.ts    |   2 +-
 .../components/InitialContext/remotePrefs.ts  |  12 +-
 .../components/InitialContext/treeRanks.ts    |  16 +-
 .../Interactions/InteractionDialog.tsx        |   4 +-
 .../Interactions/InteractionsDialog.tsx       |   8 +-
 .../components/Interactions/PrepDialogRow.tsx |   4 +-
 .../lib/components/Interactions/helpers.ts    |   2 +-
 .../js_src/lib/components/Leaflet/addOns.ts   |   4 +-
 .../Leaflet/localityRecordDataExtractor.ts    |   4 +-
 .../lib/components/Merging/CompareSubView.tsx |   2 +-
 .../lib/components/Merging/autoMerge.ts       |   8 +-
 .../lib/components/Molecules/AutoComplete.tsx |  73 ++-
 .../lib/components/Molecules/Dialog.tsx       |   8 +-
 .../Molecules/GenericSortedDataViewer.tsx     |   2 +-
 .../lib/components/Molecules/Paginator.tsx    |   2 +-
 .../lib/components/Molecules/ResourceLink.tsx |   2 +-
 .../lib/components/Molecules/Sorting.tsx      |   2 +-
 .../lib/components/Molecules/SvgIcon.tsx      |   4 +-
 .../lib/components/Molecules/TableIcon.tsx    |   4 +-
 .../components/Permissions/FormatError.tsx    |   6 +-
 .../Permissions/PermissionDenied.tsx          |  14 +-
 .../lib/components/Permissions/helpers.ts     |  18 +-
 .../lib/components/Permissions/index.ts       |  16 +-
 .../components/PickLists/FieldsPickList.tsx   |   4 +-
 .../PickLists/TreeLevelPickList.tsx           |  16 +-
 .../js_src/lib/components/PickLists/fetch.ts  |   6 +-
 .../js_src/lib/components/PickLists/index.tsx |  12 +-
 .../Preferences/BasePreferences.tsx           |   8 +-
 .../QueryBuilder/AuditLogFormatter.tsx        |  10 +-
 .../lib/components/QueryBuilder/Context.tsx   |   4 +-
 .../lib/components/QueryBuilder/Export.tsx    |  37 +-
 .../lib/components/QueryBuilder/Fields.tsx    |   4 +-
 .../lib/components/QueryBuilder/Line.tsx      |  26 +-
 .../QueryBuilder/QueryLineTools.tsx           |  12 +-
 .../lib/components/QueryBuilder/Results.tsx   |   4 +-
 .../components/QueryBuilder/ResultsTable.tsx  |   6 +-
 .../lib/components/QueryBuilder/fieldSpec.ts  |  54 +-
 .../lib/components/QueryBuilder/fromTree.ts   |   5 +-
 .../lib/components/QueryBuilder/helpers.ts    |  10 +-
 .../lib/components/QueryComboBox/helpers.ts   |   4 +-
 .../lib/components/QueryComboBox/index.tsx    |  57 +--
 .../js_src/lib/components/Reports/Report.tsx  |   2 +-
 .../js_src/lib/components/Router/Router.tsx   |   4 +-
 .../lib/components/Router/RouterUtils.tsx     |   4 +-
 .../lib/components/SchemaConfig/Field.tsx     |   2 +-
 .../lib/components/SchemaConfig/Format.tsx    |   6 +-
 .../lib/components/SchemaConfig/Hooks.tsx     |   6 +-
 .../lib/components/SchemaViewer/Fields.tsx    |   4 +-
 .../components/SchemaViewer/Relationships.tsx |  12 +-
 .../lib/components/SchemaViewer/Table.tsx     |   4 +-
 .../lib/components/SchemaViewer/TableList.tsx |   2 +-
 .../lib/components/SearchDialog/index.tsx     |  26 +-
 .../components/Security/AdminStatusPlugin.tsx |   8 +-
 .../components/Security/CollectionHooks.tsx   |   2 +-
 .../lib/components/Security/LibraryRole.tsx   |   2 +-
 .../lib/components/Security/Policies.tsx      |   4 +-
 .../components/Security/PreviewComponents.tsx |  10 +-
 .../lib/components/Security/PreviewTables.tsx |   4 +-
 .../lib/components/Security/RoleTemplate.tsx  |   2 +-
 .../js_src/lib/components/Security/User.tsx   |  68 +--
 .../components/Security/UserCollections.tsx   |   4 +-
 .../components/Security/UserComponents.tsx    |   4 +-
 .../lib/components/Security/UserHooks.tsx     |   2 +-
 .../components/Security/UserPolicyHooks.tsx   |  32 +-
 .../components/Security/policyConverter.ts    |  18 +-
 .../lib/components/Security/registry.ts       |  26 +-
 .../lib/components/SpecifyNetwork/Overlay.tsx |   4 +-
 .../lib/components/Statistics/Categories.tsx  |  38 +-
 .../lib/components/Statistics/StatItems.tsx   |   4 +-
 .../lib/components/Statistics/StatsSpec.tsx   |   4 +-
 .../Statistics/__tests__/layout.tests.ts      |   4 +-
 .../lib/components/Statistics/hooks.tsx       |   2 +-
 .../lib/components/Statistics/index.tsx       |   4 +-
 .../Syncer/__tests__/syncers.test.ts          |  18 +-
 .../lib/components/Syncer/formatXmlNode.ts    |   4 +-
 .../components/Syncer/fromSimpleXmlNode.ts    |   8 +-
 .../js_src/lib/components/Syncer/index.ts     |   2 +-
 .../js_src/lib/components/Syncer/syncers.ts   |  16 +-
 .../js_src/lib/components/Syncer/xmlToJson.ts |  18 +-
 .../lib/components/Toolbar/Language.tsx       |   4 +-
 .../lib/components/Toolbar/WbsDialog.tsx      |   6 +-
 .../lib/components/TreeView/Actions.tsx       | 112 +++--
 .../lib/components/TreeView/CreateTree.tsx    |   2 +-
 .../js_src/lib/components/TreeView/Row.tsx    |  28 +-
 .../js_src/lib/components/TreeView/Tree.tsx   |   4 +-
 .../js_src/lib/components/TreeView/helpers.ts |   5 +-
 .../lib/components/WbActions/WbUpload.tsx     |   4 +-
 .../lib/components/WbActions/WbValidate.tsx   |   4 +-
 .../js_src/lib/components/WbActions/index.tsx |  12 +-
 .../lib/components/WbPlanView/Components.tsx  |   3 +-
 .../WbPlanView/CustomSelectElement.tsx        |  10 +-
 .../components/WbPlanView/LineComponents.tsx  |  23 +-
 .../lib/components/WbPlanView/autoMapper.ts   |   6 +-
 .../components/WbPlanView/mappingPreview.ts   |   8 +-
 .../lib/components/WbPlanView/navigator.ts    |   6 +-
 .../components/WbPlanView/navigatorSpecs.ts   |   2 +-
 .../WbToolkit/CoordinateConverter.tsx         |  12 +-
 .../lib/components/WbToolkit/GeoLocate.tsx    |   4 +-
 .../js_src/lib/components/WbUtils/Utils.ts    |  70 +--
 .../lib/components/WebLinks/Definition.tsx    |  24 +-
 .../js_src/lib/components/WebLinks/index.tsx  |  16 +-
 .../js_src/lib/components/WebLinks/spec.ts    |  20 +-
 .../lib/components/WorkBench/CellMeta.ts      |   2 +-
 .../lib/components/WorkBench/Results.tsx      |   2 +-
 .../lib/components/WorkBench/WbValidation.tsx |   2 +-
 .../frontend/js_src/lib/declarations.d.ts     |   2 +-
 .../frontend/js_src/lib/hooks/store.tsx       |   4 +-
 .../js_src/lib/hooks/useBooleanState.tsx      |   2 +-
 .../js_src/lib/hooks/useCachedState.tsx       |   2 +-
 .../js_src/lib/hooks/useCollection.tsx        |   2 +-
 .../js_src/lib/hooks/useResourceValue.tsx     |  15 +-
 .../lib/hooks/useSerializedCollection.tsx     |   2 +-
 .../schema-localization/traversal.ts          |   7 +-
 .../localization/schema-localization/xml.ts   |   2 +-
 .../js_src/lib/localization/utils/config.ts   |   2 +-
 .../js_src/lib/localization/utils/index.tsx   |   2 +-
 .../js_src/lib/localization/utils/sync.ts     |   2 +-
 .../lib/localization/utils/validateWeblate.ts |   4 +-
 .../frontend/js_src/lib/tests/reactUtils.tsx  |   2 +-
 .../js_src/lib/tests/testBusinessRules.js     |   2 +-
 .../frontend/js_src/lib/tests/testForms.js    |  42 +-
 .../frontend/js_src/lib/utils/ajax/helpers.ts |   8 +-
 .../js_src/lib/utils/cache/definitions.ts     |  14 +-
 .../frontend/js_src/lib/utils/cache/index.ts  |   4 +-
 .../js_src/lib/utils/parser/definitions.ts    |  10 +-
 specifyweb/frontend/js_src/lib/utils/types.ts |  12 +-
 specifyweb/frontend/js_src/lib/utils/utils.ts |  32 +-
 specifyweb/frontend/locale/README.md          |  21 +-
 specifyweb/hibernateboolsbackend/readme.md    |   5 +-
 .../templates/report_template.xml             |  60 +--
 .../workbench/templates/upload_new.html       |   5 +-
 .../workbench/templates/validate_row.html     |   5 +-
 215 files changed, 1581 insertions(+), 1589 deletions(-)

diff --git a/.dockerignore b/.dockerignore
index 5c56029317a..fe100552c6d 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -10,4 +10,4 @@ specifyweb/frontend/js_src/node_modules
 specifyweb/frontend/testBuild
 specifyweb/frontend/static/js
 # Prevent *.env files from being included in a container (for security)
-*.env
\ No newline at end of file
+*.env
diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md
index 5e467e975b2..9fa50a2153a 100644
--- a/.github/pull-request-template.md
+++ b/.github/pull-request-template.md
@@ -6,8 +6,8 @@ Fixes #
 
 ### Checklist
 
-- [ ] Self-review the PR after opening it to make sure the changes look good
-      and self-explanatory (or properly documented)
+- [ ] Self-review the PR after opening it to make sure the changes look good and
+      self-explanatory (or properly documented)
 - [ ] Add automated tests
 - [ ] Add relevant issue to release milestone
 
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index b07b1b818b7..45c3cd938a5 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -58,25 +58,25 @@ jobs:
           echo "version=${VERSION}" >> $GITHUB_OUTPUT
           echo "tags=${TAGS}" >> $GITHUB_OUTPUT
           echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
-      
+
       - name: Docker meta
         id: meta
         uses: docker/metadata-action@v5
         with:
           images: ${{ env.REGISTRY_IMAGE }}
-      
+
       - name: Set up QEMU
         uses: docker/setup-qemu-action@v3
-      
+
       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v3
-      
+
       - name: Login to Docker Hub
         uses: docker/login-action@v3
         with:
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
-      
+
       - name: Build and push by digest
         id: build
         uses: docker/build-push-action@v6
@@ -93,7 +93,7 @@ jobs:
           mkdir -p /tmp/digests
           digest="${{ steps.build.outputs.digest }}"
           touch "/tmp/digests/${digest#sha256:}"
-      
+
       - name: Upload digest
         uses: actions/upload-artifact@v4
         with:
@@ -113,28 +113,28 @@ jobs:
           path: /tmp/digests
           pattern: digests-*
           merge-multiple: true
-      
+
       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v3
-      
+
       - name: Docker meta
         id: meta
         uses: docker/metadata-action@v5
         with:
           images: ${{ env.REGISTRY_IMAGE }}
-      
+
       - name: Login to Docker Hub
         uses: docker/login-action@v3
         with:
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
-      
+
       - name: Create manifest list and push
         working-directory: /tmp/digests
         run: |
           docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
             $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
-      
+
       - name: Inspect image
         run: |
           docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}
diff --git a/.gitignore b/.gitignore
index 56de19b20c9..c392ed07bab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,17 +10,12 @@ venv/
 ve/
 seed-database
 *.env
-
 /specifyweb/settings/local_settings.py
 /specifyweb/settings/local_specify_settings.py
 /specifyweb/settings/local_logging_settings.py
 /specifyweb/settings/debug.py
 /specifyweb/settings/secret_key.py
 /specifyweb/settings/ldap_settings.py
-
-
-
-# Build artifacts:
 /.mypy_cache
 /specifyweb/frontend/locale/**/*.mo
 /specifyweb/settings/build_version.py
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f6a80c3fdea..ab2c77057fd 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -32,7 +32,9 @@ repos:
       - id: mypy
         name: mypy
         description: Python mypy typechecker
-        entry: /bin/bash -c "docker exec --tty specify7_specify7_1 bash -c 'VIRTUAL_ENV=./ve make typecheck'"
+        entry:
+          /bin/bash -c "docker exec --tty specify7_specify7_1 bash -c
+          'VIRTUAL_ENV=./ve make typecheck'"
         language: script
         types: [python]
         pass_filenames: false
@@ -115,7 +117,7 @@ repos:
       - id: prettier
         additional_dependencies:
           - prettier@2.5.0
-          - "@prettier/plugin-xml@^0.13.1"
+          - '@prettier/plugin-xml@^0.13.1'
           - prettier-plugin-package@^1.3.0
           - prettier-plugin-sh@^0.8.1
           - prettier-plugin-tailwind-css@^1.5.0
diff --git a/CITATION.cff b/CITATION.cff
index 9f07def758c..7794b3daf81 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -1,5 +1,5 @@
 cff-version: 1.2.0
-message: "If you use this software in your research, please cite it as:"
+message: 'If you use this software in your research, please cite it as:'
 authors:
   - name: Specify Collections Consortium & Contributors
     email: support@specifysoftware.org
@@ -9,11 +9,11 @@ keywords:
   - open source
 identifiers:
   - type: url
-    value: "https://www.specifysoftware.org/"
+    value: 'https://www.specifysoftware.org/'
     description: Specify Collections Consortium
 abstract: >-
   The Specify Collections Consortium research repositories produce software
   platforms that process species and specimen data.
 license: GPL-2.0-only
 repository-code: specify/specify7
-repository: "https://github.com/specify/specify7"
+repository: 'https://github.com/specify/specify7'
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e21cf14625b..676cb450bd5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -36,27 +36,25 @@ together to achieve our mission._
 
 ## Getting Started
 
-Preferred way to do Specify 7 development is though our development
-composition.
+Preferred way to do Specify 7 development is though our development composition.
 
-[Documentation for getting development Docker composition
-working](https://github.com/specify/specify7/wiki/Docker-Workflow-for-Development)
+[Documentation for getting development Docker composition working](https://github.com/specify/specify7/wiki/Docker-Workflow-for-Development)
 
 ## Issue Tracking
 
 All feature requests and bugs are tracked on GitHub. Each issue is sorted into a
-project. Each project represents a major Specify 7
-component. [A list of all projects](https://github.com/specify/specify7/projects?type=classic)
+project. Each project represents a major Specify 7 component.
+[A list of all projects](https://github.com/specify/specify7/projects?type=classic)
 
 If you found a bug, feel free to open a GitHub issue. Similarly, if you are
-interested in fixing some issue or adding new feature, feel free to do so!
-If you want to work on a larger feature, it would be best if you [get in touch
-with us](mailto:support@specifysoftware.org) first so that we can make sure the
-process is smooth and efficient.
+interested in fixing some issue or adding new feature, feel free to do so! If
+you want to work on a larger feature, it would be best if you
+[get in touch with us](mailto:support@specifysoftware.org) first so that we can
+make sure the process is smooth and efficient.
 
 Our entire workflow for reporting bugs, trianging them, prioritizing the fixes,
-testing them and releasing the
-fixes - https://github.com/specify/specify7/wiki/Issue-Workflow
+testing them and releasing the fixes -
+https://github.com/specify/specify7/wiki/Issue-Workflow
 
 You don't have to read every part of that document, but some of the sections in
 that document would be relevant
@@ -66,12 +64,12 @@ Example workflow:
 1. Go through GitHub Projects
 2. Find a ticket that you are interested in resolving
 3. Fix it in a local fork of Specify 7
-4. Open a pull request in Specify 7 repository. In the pull request, mention
-   the issue you are solving by putting `Fixes #1234` in the description, where
+4. Open a pull request in Specify 7 repository. In the pull request, mention the
+   issue you are solving by putting `Fixes #1234` in the description, where
    `1234` is a number of GitHub issue
 5. We will review the changes and merge them into next release. You will receive
    credit in the release notes!
-   
+
 ### First Steps
 
 It's recomended to start with issues that are labled with
@@ -85,32 +83,33 @@ would prepare you for taking on larger GitHub issues.
 
 On the front-end, we are using TypeScript, React and Tailwind CSS.
 
-Front-end root directory is
-in [./specifyweb/frontend/js_src](https://github.com/specify/specify7/tree/testability/specifyweb/frontend/js_src)
+Front-end root directory is in
+[./specifyweb/frontend/js_src](https://github.com/specify/specify7/tree/testability/specifyweb/frontend/js_src)
 
 Each folder and sub-folder has a README.md file that describes the role of that
 directory and provides other meta information.
 
-We have a [video of a full front-end code overview from January 2023 available here](https://drive.google.com/file/d/11TDHSz54EhQ5eQPNyaogHOODO8_8Q9yg/view).
+We have a
+[video of a full front-end code overview from January 2023 available here](https://drive.google.com/file/d/11TDHSz54EhQ5eQPNyaogHOODO8_8Q9yg/view).
 
 ## Back-End
 
 Back-end uses Python and Django. It also works closely with a MySQL/MariaDB
 database both though Django ORM and though SQLAlchemy.
 
-Back-end root directory
-is [./specifyweb/](https://github.com/specify/specify7/tree/production/specifyweb)
+Back-end root directory is
+[./specifyweb/](https://github.com/specify/specify7/tree/production/specifyweb)
 
 [We have a video of a full back-end overview from January 2023 available here](https://drive.google.com/file/d/1OW60g99aiPw1Y8uHdCUxZCiVnLbFhObG/view?usp=sharing)
 
 ## IDE Setup
 
 No special IDE configuration is required, but some optional plugins would
-improve developer
-experience - https://github.com/specify/specify7/tree/production/specifyweb/frontend/js_src#js_src
+improve developer experience -
+https://github.com/specify/specify7/tree/production/specifyweb/frontend/js_src#js_src
 
-That document includes a short list. For a full list,
-see https://github.com/specifysystems/code-principles
+That document includes a short list. For a full list, see
+https://github.com/specifysystems/code-principles
 
 In the browser, you can install React Devtools extension to make debugging React
 components easier.
@@ -118,9 +117,8 @@ components easier.
 ## Code-Style
 
 We prefer functional programming paradigm. In our opinion, perfect code\*
-consist
-of small and pure functions that have clear unit tests, and can be combined
-together to solve a complex task.
+consist of small and pure functions that have clear unit tests, and can be
+combined together to solve a complex task.
 
 > \*no code is perfect, but you can still strive for it
 
@@ -129,8 +127,8 @@ formatting to make code less buggy and more consistent.
 
 Additionally, ESLint goes beyond that to provide close to a thousand of static
 analysis checks and quick fixes, all in a name of clear and bug-free code. Our
-ESLint configuration is located
-in [@maxxxxxdlp/eslint-config-react](https://www.npmjs.com/package/@maxxxxxdlp/eslint-config-react)
+ESLint configuration is located in
+[@maxxxxxdlp/eslint-config-react](https://www.npmjs.com/package/@maxxxxxdlp/eslint-config-react)
 
 ## Test Panel
 
@@ -149,22 +147,21 @@ quickly deploy an older version of Specify to compare behavior.
 
 ## Support
 
-A great deal of user-facing documentation is available at
-our [Discourse forum](https://discourse.specifysoftware.org/). Most of it is
-available to users from member institutions only, thus [consider joining the
-Specify Software Consortium](https://www.specifysoftware.org/membership-levels/)
+A great deal of user-facing documentation is available at our
+[Discourse forum](https://discourse.specifysoftware.org/). Most of it is
+available to users from member institutions only, thus
+[consider joining the Specify Software Consortium](https://www.specifysoftware.org/membership-levels/)
 if you are interested in becoming a power user of Specify 7.
 
 Besides the README.md files in most folders in this repository, there is also
-some developer facing documentation in
-our [GitHub Wiki](https://github.com/specify/specify7/wiki).
-
-If you are stuck and need help, consider emailing our support
-at [support@specifysoftware.org](mailto:support@specifysoftware.org),
-opening a [GitHub issue](https://github.com/specify/specify7/issues/new/choose)
-or posting a question on
-our [Discourse forum](https://discourse.specifysoftware.org/)
-as appropriate.
+some developer facing documentation in our
+[GitHub Wiki](https://github.com/specify/specify7/wiki).
+
+If you are stuck and need help, consider emailing our support at
+[support@specifysoftware.org](mailto:support@specifysoftware.org), opening a
+[GitHub issue](https://github.com/specify/specify7/issues/new/choose) or posting
+a question on our [Discourse forum](https://discourse.specifysoftware.org/) as
+appropriate.
 
 | Contact Option  | Link                                                                  |
 | --------------- | --------------------------------------------------------------------- |
diff --git a/README.md b/README.md
index 478d707150f..de00dc90553 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,56 @@
-
 # [Specify 7](https://www.specifysoftware.org/products/specify-7/)
 
 The [Specify Collections Consortium](https://www.specifysoftware.org) is pleased
 to offer Specify 7, the web implementation of our biological collections data
 management platform.
 
-We encourage members to use
-our [Dockerized compositions](https://github.com/specify/docker-compositions) of
+We encourage members to use our
+[Dockerized compositions](https://github.com/specify/docker-compositions) of
 Specify 7. You can choose a version, make the necessary adjustments and then run
 a single command to get everything working. It is very simple and can be easily
-updated when new versions are released. Members can contact us
-at [support@specifysoftware.org](mailto:support@specifysoftware.org) to gain
-access to this repository.
+updated when new versions are released. Members can contact us at
+[support@specifysoftware.org](mailto:support@specifysoftware.org) to gain access
+to this repository.
 
 The new generation of Specify combines the interface design components and data
 management foundation of Specify 6 with the efficiency and ease-of-use of
-web-based data access and cloud computing. Specify 7 uses
-the same interface layout language as Specify 6, so any user interface
-customization made in one platform is mirrored in the other. Also Specify 6 and
-Specify 7 use the same data model and can work from the same Specify MySQL or MariaDB
-database, which means 6 and 7 can be run simultaneously with any Specify
-collection. Specify 7 helps
-transition Specify 6 collections to cloud computing. It is also a great starting
-platform for institutions that prefer zero workstation software installation and
-ubiquitous web browser access.
-
-Specify 7’s architecture supports collaborative digitization projects and remote hosting of specimen databases. Without the need for a local area or campus network
-to connect to the MySQL data server, Specify 7 gives you and your collaborators
-access to a shared specimen database through any web browser. Finding it challenging to obtain IT support to maintain a local secure database server? With the Specify 7 server
-software supported on generic Linux servers, museums can utilize a server
-hosting service to provide support for the technical complexities of systems
-administration, security management, and backing-up. Want to create a joint
-database for a collaborative digitizing effort? No
-problem! Host, hire a hosting service or use
-our [Specify Cloud](https://www.specifysoftware.org/products/cloud/) service for
+web-based data access and cloud computing. Specify 7 uses the same interface
+layout language as Specify 6, so any user interface customization made in one
+platform is mirrored in the other. Also Specify 6 and Specify 7 use the same
+data model and can work from the same Specify MySQL or MariaDB database, which
+means 6 and 7 can be run simultaneously with any Specify collection. Specify 7
+helps transition Specify 6 collections to cloud computing. It is also a great
+starting platform for institutions that prefer zero workstation software
+installation and ubiquitous web browser access.
+
+Specify 7’s architecture supports collaborative digitization projects and remote
+hosting of specimen databases. Without the need for a local area or campus
+network to connect to the MySQL data server, Specify 7 gives you and your
+collaborators access to a shared specimen database through any web browser.
+Finding it challenging to obtain IT support to maintain a local secure database
+server? With the Specify 7 server software supported on generic Linux servers,
+museums can utilize a server hosting service to provide support for the
+technical complexities of systems administration, security management, and
+backing-up. Want to create a joint database for a collaborative digitizing
+effort? No problem! Host, hire a hosting service or use our
+[Specify Cloud](https://www.specifysoftware.org/products/cloud/) service for
 your Specify database, set up accounts and go. We provide the same efficient
-user interface, report and labels customization and help desk
-support for Specify 7 as we do for Specify 6.
+user interface, report and labels customization and help desk support for
+Specify 7 as we do for Specify 6.
 
-**Secure.**
-Support for Single Sign-On (SSO) integrates Specify 7 with a campus or
-institutional identity providers. It supports all identity providers (IdPs) that
-have an OpenID endpoints.
+**Secure.** Support for Single Sign-On (SSO) integrates Specify 7 with a campus
+or institutional identity providers. It supports all identity providers (IdPs)
+that have an OpenID endpoints.
 
 The Security and Accounts tool allows administrators to give access based on
 roles and policies. Create, edit, and copy roles among collections and
 databases. Administrators can give users as many or few permissions as desired,
 from guest accounts to collection managers.
 
-**Accessible.**
-It is important that web applications work for people with disabilities. Specify
-7 is developed with this top of mind, not only meeting international
-accessibility standards but also providing a better experience for everyone.
+**Accessible.** It is important that web applications work for people with
+disabilities. Specify 7 is developed with this top of mind, not only meeting
+international accessibility standards but also providing a better experience for
+everyone.
 
 Specify 7 is largely compliant with the main WWW accessibility standard – **WCAG
 2.1 (AA)**. It supports screen readers and allows each user to customize their
@@ -62,13 +61,12 @@ formats, language, theme, and animations.
 
 ---
 
-The Specify Collections Consortium is funded by its member
-institutions. The Consortium web site is:
-https://specifysoftware.org
+The Specify Collections Consortium is funded by its member institutions. The
+Consortium web site is: https://specifysoftware.org
 
-Specify 7 Copyright © 2024 Specify Collections Consortium. Specify
-comes with ABSOLUTELY NO WARRANTY. This is free software licensed
-under GNU General Public License 2 (GPL2).
+Specify 7 Copyright © 2024 Specify Collections Consortium. Specify comes with
+ABSOLUTELY NO WARRANTY. This is free software licensed under GNU General Public
+License 2 (GPL2).
 
     Specify Collections Consortium
     Biodiversity Institute
@@ -129,52 +127,47 @@ for evaluation purposes.
 
 ### Specify Collections Consortium (SCC) Members:
 
-We encourage members to use
-our  [Dockerized compositions](https://github.com/specify/docker-compositions)
-of Specify 7. You can choose your desired version, make the necessary
-adjustments and then run a single command to get everything
-working. It is very simple and can be easily updated when new versions are
-released. Documentation for deploying Specify
-using Docker is available within the repository.
+We encourage members to use our
+[Dockerized compositions](https://github.com/specify/docker-compositions) of
+Specify 7. You can choose your desired version, make the necessary adjustments
+and then run a single command to get everything working. It is very simple and
+can be easily updated when new versions are released. Documentation for
+deploying Specify using Docker is available within the repository.
 
-[**📨 Click here to request
-access**](mailto:support@specifysoftware.org?subject=Requesting%20Docker%20Repository%20Access&body=My%20GitHub%20username%20is%3A%20%0D%0AMy%20Specify%20Member%20Institution%20is%3A%20%0D%0AAdditional%20Questions%20or%20Notes%3A%20)
-or email  [support@specifysoftware.org](mailto:support@specifysoftware.org)
-with your GitHub username, member
-institution or collection, and any additional questions you have for us.
+[**📨 Click here to request access**](mailto:support@specifysoftware.org?subject=Requesting%20Docker%20Repository%20Access&body=My%20GitHub%20username%20is%3A%20%0D%0AMy%20Specify%20Member%20Institution%20is%3A%20%0D%0AAdditional%20Questions%20or%20Notes%3A%20)
+or email [support@specifysoftware.org](mailto:support@specifysoftware.org) with
+your GitHub username, member institution or collection, and any additional
+questions you have for us.
 
 ### Non-Members:
 
 If your institution is not a member of the Specify Collections Consortium, you
-can follow
-the [local installation instructions](#local-installation) below or
+can follow the [local installation instructions](#local-installation) below or
 contact [membership@specifysoftware.org](mailto:membership@specifysoftware.org)
-to learn more about joining the SCC to
-receiving configuration assistance, support, and hosting services if you are
-interested.
+to learn more about joining the SCC to receiving configuration assistance,
+support, and hosting services if you are interested.
 
 ## Local Installation
 
-After completing these instructions you will be able to run the test
-server and interact with the Django based Specify webapp in your
-browser on your local machine.
+After completing these instructions you will be able to run the test server and
+interact with the Django based Specify webapp in your browser on your local
+machine.
 
 Instructions for deployment follow.
 
-**Note:** If updating from a previous version, some of the python
-dependencies have changed. It is recommended to place the new version
-in a separate directory next to the previous version and install all
-the new dependencies in a Python virtualenv as described below. That
-will avoid version conflicts and allow the previous version to
-continue working while the new version is being set up. When the new
-version is working satisfactorily using the test server, the Apache
-conf can be changed to point to it (or changed back to the old
-version, if problems arise).
+**Note:** If updating from a previous version, some of the python dependencies
+have changed. It is recommended to place the new version in a separate directory
+next to the previous version and install all the new dependencies in a Python
+virtualenv as described below. That will avoid version conflicts and allow the
+previous version to continue working while the new version is being set up. When
+the new version is working satisfactorily using the test server, the Apache conf
+can be changed to point to it (or changed back to the old version, if problems
+arise).
 
 ### Installing system dependencies
 
-Specify 7 requires Python 3.8. Ubuntu 20.04 LTS is recommended. For
-other distributions these instructions will have to be adapted.
+Specify 7 requires Python 3.8. Ubuntu 20.04 LTS is recommended. For other
+distributions these instructions will have to be adapted.
 
 Ubuntu 20.04 LTS:
 
@@ -222,11 +215,11 @@ node -v
 
 ### Installing Specify 6
 
-A copy of the most recent Specify 6 release is required on the server
-as Specify 7 makes use of resource files. A Java runtime is required
-to execute the Specify 6 installer, but is not needed to run
-Specify 7. It is possible to copy the Specify 6 install from another
-Linux system to avoid the need to install Java on the server.
+A copy of the most recent Specify 6 release is required on the server as Specify
+7 makes use of resource files. A Java runtime is required to execute the Specify
+6 installer, but is not needed to run Specify 7. It is possible to copy the
+Specify 6 install from another Linux system to avoid the need to install Java on
+the server.
 
 ```shell
 wget https://update.specifysoftware.org/Specify_unix_64.sh
@@ -242,8 +235,7 @@ Clone this repository.
 git clone https://github.com/specify/specify7.git
 ```
 
-You will now have a specify7 directory containing the source
-tree.
+You will now have a specify7 directory containing the source tree.
 
 Note, by default, `git clone` checks out the `production` branch of Specify 7.
 That branch contains the latest tested features and bug fixes. If you prefer a
@@ -263,16 +255,15 @@ the latest stable release.
 
 In the directory `specify7/specifyweb/settings` you will find the
 `specify_settings.py` file. Make a copy of this file as
-`local_specify_settings.py` and edit it. The file contains comments
-explaining the various settings.
+`local_specify_settings.py` and edit it. The file contains comments explaining
+the various settings.
 
 ### Setting up Python Virtual Environment
 
 Using a Python
 [virtual environment](https://docs.python-guide.org/en/latest/dev/virtualenvs/)
-will avoid version conflicts with other Python libraries on your
-system. Also, it avoids having to use a superuser account to install
-the Python dependencies.
+will avoid version conflicts with other Python libraries on your system. Also,
+it avoids having to use a superuser account to install the Python dependencies.
 
 ```shell
 python3.8 -m venv specify7/ve
@@ -301,8 +292,8 @@ Runs all necessary build steps.
 
 #### `make frontend`
 
-Installs or updates Javascript dependencies and builds the Javascript
-modules only.
+Installs or updates Javascript dependencies and builds the Javascript modules
+only.
 
 #### `make clean`
 
@@ -316,12 +307,11 @@ Install or updates Python dependencies.
 
 #### `make django_migrations`
 
-Applies Specify schema changes to the database named in the
-settings. This step may fail if the master user configured in the
-settings does not have DDL privileges. Changing the `MASTER_NAME` and
-`MASTER_PASSWORD` settings to the MySQL root user will allow the
-changes to be applied. Afterward, the master user settings can be
-restored.
+Applies Specify schema changes to the database named in the settings. This step
+may fail if the master user configured in the settings does not have DDL
+privileges. Changing the `MASTER_NAME` and `MASTER_PASSWORD` settings to the
+MySQL root user will allow the changes to be applied. Afterward, the master user
+settings can be restored.
 
 #### `make runserver`
 
@@ -329,14 +319,14 @@ A shortcut for running the Django development server.
 
 #### `make webpack_watch`
 
-Run webpack in watch mode so that changes to the frontend source code
-will be automatically compiled. Useful during the development process.
+Run webpack in watch mode so that changes to the frontend source code will be
+automatically compiled. Useful during the development process.
 
 ### Turning on debugging
 
-For development purposes, Django debugging should be turned on. It
-will enable stack traces in responses that encounter exceptions, and
-allow operation with the unoptimized Javascript files.
+For development purposes, Django debugging should be turned on. It will enable
+stack traces in responses that encounter exceptions, and allow operation with
+the unoptimized Javascript files.
 
 Debugging can be enabled by creating the file
 `specify7/specifyweb/settings/debug.py` with the contents, `DEBUG = True`.
@@ -354,11 +344,10 @@ source ve/bin/activate
 make runserver
 ```
 
-This will start a development server for testing purposes on
-`localhost:8000`.
+This will start a development server for testing purposes on `localhost:8000`.
 
-When the server starts up, it will issue a warning that some
-migrations have not been applied:
+When the server starts up, it will issue a warning that some migrations have not
+been applied:
 
 ```
 You have 11 unapplied migration(s). Your project may not work
@@ -367,40 +356,42 @@ contenttypes, sessions.  Run 'python manage.py migrate' to apply them.
 ```
 
 Specify 7 makes use of functions from the listed Django apps (auth,
-contenttypes, and sessions) but does not need the corresponding tables
-to be added to the database. Running `make django_migrations` will
-apply only those migrations needed for Specify 7 to operate.
+contenttypes, and sessions) but does not need the corresponding tables to be
+added to the database. Running `make django_migrations` will apply only those
+migrations needed for Specify 7 to operate.
 
 ### The Specify 7 Worker
 
-Starting from version `v7.6.0`, the Specify WorkBench utilizes this 
-dedicated worker process to handle the upload and validation operations. 
+Starting from version `v7.6.0`, the Specify WorkBench utilizes this dedicated
+worker process to handle the upload and validation operations.
 
-Starting from version `v7.9.0`, the record merging functionality employs the worker to handle all record merging activities.
+Starting from version `v7.9.0`, the record merging functionality employs the
+worker to handle all record merging activities.
 
-This worker process utilizes [Celery](https://docs.celeryproject.org/en/master/index.html), a job queue 
-management system, with [Redis](https://docs.celeryproject.org/en/master/getting-started/backends-and-brokers/redis.html) 
+This worker process utilizes
+[Celery](https://docs.celeryproject.org/en/master/index.html), a job queue
+management system, with
+[Redis](https://docs.celeryproject.org/en/master/getting-started/backends-and-brokers/redis.html)
 serving as the broker.
 
-The worker process can be started from the commandline
-by executing:
+The worker process can be started from the commandline by executing:
 
 ```shell
 cd specify7
 celery -A specifyweb worker -l INFO --concurrency=1
 ```
 
-For deployment purposes it is recommended to configure a systemd unit
-to automatically start the Specify 7 worker process on system start up
-by executing the above command within the installation directory. It
-is possible to run Redis and worker process on a separate server and
-to provision multiple worker processes for high volume
-scenarios. Contact the Specify team about these use cases.
+For deployment purposes it is recommended to configure a systemd unit to
+automatically start the Specify 7 worker process on system start up by executing
+the above command within the installation directory. It is possible to run Redis
+and worker process on a separate server and to provision multiple worker
+processes for high volume scenarios. Contact the Specify team about these use
+cases.
 
 ### Installing production requirements
 
-For production environments, Specify7 can be hosted by Apache. The
-following packages are needed:
+For production environments, Specify7 can be hosted by Apache. The following
+packages are needed:
 
 - Apache
 - mod-wsgi to connect Python to Apache
@@ -417,17 +408,16 @@ CentOS / Red Hat:
 yum install httpd python3-mod_wsgi
 ```
 
-Warning: This will replace the Python 2.7 version of mod-wsgi that was
-used by Specify 7.4.0 and prior. If executed on a production server
-running one of those versions, Specify 7 will stop working until the
-new deployment is configured.
+Warning: This will replace the Python 2.7 version of mod-wsgi that was used by
+Specify 7.4.0 and prior. If executed on a production server running one of those
+versions, Specify 7 will stop working until the new deployment is configured.
 
 ### Setting up Apache
 
-In the `specify7` directory you will find the `specifyweb_apache.conf`
-file. Make a copy of the file as `local_specifyweb_apache.conf` and
-edit the contents to reflect the location of Specify6 and Specify7 on
-your system. There are comments showing what to change.
+In the `specify7` directory you will find the `specifyweb_apache.conf` file.
+Make a copy of the file as `local_specifyweb_apache.conf` and edit the contents
+to reflect the location of Specify6 and Specify7 on your system. There are
+comments showing what to change.
 
 Then remove the default Apache welcome page and make a link to your
 `local_specifyweb_apache.conf` file.
@@ -463,24 +453,24 @@ sudo systemctl restart httpd.service
 
 ### Nginx configuration
 
-Specify 7 is web-server agnostic.
-Example [nginx.conf](https://github.com/specify/specify7/blob/production/nginx.conf)
+Specify 7 is web-server agnostic. Example
+[nginx.conf](https://github.com/specify/specify7/blob/production/nginx.conf)
 (note, you would have to adjust the host names and enable HTTPs).
 
 ## Updating Specify 7
 
-Specify 7.4.0 and prior versions were based on Python 2.7. If updating
-from one of these versions, it will be necessary to install Python 3.8
-by running the `apt-get` commands in the
+Specify 7.4.0 and prior versions were based on Python 2.7. If updating from one
+of these versions, it will be necessary to install Python 3.8 by running the
+`apt-get` commands in the
 [Install system dependencies](#install-system-dependencies) and the
-[Production requirements](#production-requirements) steps. Then
-proceed as follows:
+[Production requirements](#production-requirements) steps. Then proceed as
+follows:
 
-0. Backup your Specify database using MySQL dump or the Specify backup
-   and restore tool.
+0. Backup your Specify database using MySQL dump or the Specify backup and
+   restore tool.
 
-1. Clone or download a new copy of this repository in a directory next
-   to your existing installation.
+1. Clone or download a new copy of this repository in a directory next to your
+   existing installation.
 
    `git clone https://github.com/specify/specify7.git specify7-new-version`
 
@@ -489,38 +479,36 @@ proceed as follows:
    `cp specify7/specifyweb/settings/local* specify7-new-version/specifyweb/settings/`
 
 3. Make sure to update the `THICK_CLIENT_LOCATION` setting in
-   `local_specify_settings.py`, if you are updating the Specify 6
-   version.
+   `local_specify_settings.py`, if you are updating the Specify 6 version.
 
-4. Update the system level dependencies by executing the _apt-get_
-   command in the [Installing system
-   dependencies](#installing-system-dependencies) section.
+4. Update the system level dependencies by executing the _apt-get_ command in
+   the [Installing system dependencies](#installing-system-dependencies)
+   section.
 
 5. Create a new virtualenv for the new installation by following the
-   [Python Virtual Environment](#python-virtual-environment) section
-   for the new directory.
+   [Python Virtual Environment](#python-virtual-environment) section for the new
+   directory.
 
 6. [Build](#building) the new version of Specify 7.
 
 7. Test it out with the [development server](#the-development-server).
 
-8. Deploy the new version by updating your Apache config to replace
-   the old installation paths with the new ones and restarting Apache.
+8. Deploy the new version by updating your Apache config to replace the old
+   installation paths with the new ones and restarting Apache.
 
-9. Configure the Specify 7 worker process to execute at system start
-   up as described in [The Specify 7 worker](#the-specify-7-worker) section.
+9. Configure the Specify 7 worker process to execute at system start up as
+   described in [The Specify 7 worker](#the-specify-7-worker) section.
 
 ## Updating the database (Specify 6) version
 
-The Specify database is updated from one version to the next by the
-Specify 6 application. To update the database version connect to the
-database with a new version of Specify 6 and follow the Specify 6
-update procedures.
+The Specify database is updated from one version to the next by the Specify 6
+application. To update the database version connect to the database with a new
+version of Specify 6 and follow the Specify 6 update procedures.
 
-Once the database version is updated, a corresponding copy of Specify
-6 must be provided to the Specify 7 server by repeating
-the [Installing Specify 6](#installing-specify-6) section of this guide for the
-new version of Specify 6.
+Once the database version is updated, a corresponding copy of Specify 6 must be
+provided to the Specify 7 server by repeating the
+[Installing Specify 6](#installing-specify-6) section of this guide for the new
+version of Specify 6.
 
 [![analytics](https://www.google-analytics.com/collect?v=1&t=pageview&dl=https%3A%2F%2Fgithub.com%2Fspecify%2Fspecify7&uid=readme&tid=UA-169822764-3)]()
 
@@ -529,6 +517,5 @@ new version of Specify 6.
 Specify 7 interface is localized to a few languages out of the box. We welcome
 contributions of new translations. We are using
 [Weblate](https://hosted.weblate.org/projects/specify-7/) continuous
-localization
-platform.
+localization platform.
 [Instructions on how you can contribute](https://discourse.specifysoftware.org/t/get-started-with-specify-7-localization/956)
diff --git a/SECURITY.md b/SECURITY.md
index 61400af3d02..b7fc838b8bd 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -9,19 +9,19 @@ provide customer support.
 For non-security issues, our [support team](mailto:support@specifysoftware.org)
 is always available to help with troubleshooting and answer any questions. We
 also have a large online community of users who are willing to share their
-experiences and help each other out. You can visit
-the [Specify Community Forum](https://discourse.specifysoftware.org/) to ask any
+experiences and help each other out. You can visit the
+[Specify Community Forum](https://discourse.specifysoftware.org/) to ask any
 questions you may have about configuration or deployment.
 
 | Version | Supported          |
 | ------- | ------------------ |
 | 7.9.x   | :white_check_mark: |
 | 7.8.x   | :white_check_mark: |
-| < 7.8   | :x: |
+| < 7.8   | :x:                |
 
 We support the latest version of Specify 6 only. You can report vulnerabilities
-or other issues for that application on
-the [Specify 6 GitHub repository](https://github.com/specify/specify6/issues/).
+or other issues for that application on the
+[Specify 6 GitHub repository](https://github.com/specify/specify6/issues/).
 
 ## Reporting a Vulnerability
 
@@ -29,8 +29,8 @@ the [Specify 6 GitHub repository](https://github.com/specify/specify6/issues/).
 
 Please contact [support@specifysoftware.org](mailto:support@specifysoftware.org)
 immediately if you encounter any security vulnerability in Specify 7 in addition
-to creating
-a [new bug report](https://github.com/specify/specify7/issues/new?assignees=&labels=type%3Abug%2C+pri%3Aunknown&template=bug_report.md&title=)
+to creating a
+[new bug report](https://github.com/specify/specify7/issues/new?assignees=&labels=type%3Abug%2C+pri%3Aunknown&template=bug_report.md&title=)
 in the GitHub repository where it will be reviewed by the development team
 within 24 hours.
 
@@ -41,8 +41,8 @@ provide an explanation as to why it was not accepted.
 
 #### Vulnerability in Docker
 
-If you encounter a security issue in Docker, the best place to start is
-the [Docker Security page](https://www.docker.com/security). This page provides
+If you encounter a security issue in Docker, the best place to start is the
+[Docker Security page](https://www.docker.com/security). This page provides
 information on reporting security issues, as well as links to the Docker
 Security Advisory Board (DSAB) and the Docker Security Research Team.
 
@@ -50,11 +50,11 @@ Security Advisory Board (DSAB) and the Docker Security Research Team.
 
 - **MySQL**
 
-  If you encounter a security issue in MySQL, you can report it to
-  the [MySQL issue tracking system](http://bugs.mysql.com).
+  If you encounter a security issue in MySQL, you can report it to the
+  [MySQL issue tracking system](http://bugs.mysql.com).
 
 - **MariaDB**
 
-  If you encounter a security issue in MariaDB, you should report it to
-  their [security team](security@mariadb.org). The security team will review
-  your report and contact you with an update on the status of the vulnerability.
+  If you encounter a security issue in MariaDB, you should report it to their
+  [security team](security@mariadb.org). The security team will review your
+  report and contact you with an update on the status of the vulnerability.
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index f760b60dde3..1978b5b5f1f 100755
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -1,20 +1,14 @@
-#!/bin/bash
 set -e
-
 if [ -z "$(ls -A /volumes/static-files/specify-config)" ]; then
   mkdir -p /volumes/static-files/specify-config/config/
   rsync -a config/ /volumes/static-files/specify-config/config/
 fi
-
 if [ "$1" = 've/bin/gunicorn' ] || [ "$1" = 've/bin/python' ]; then
   echo "Updating static files in /volumes/static-files/."
   rsync -a --delete specifyweb/frontend/static/ /volumes/static-files/frontend-static
   cd /opt/specify7
   echo "Applying Django migrations."
   set +e
-  # The following command is prone to failing
-  # See https://github.com/specify/specify7/issues/789
-  # and https://github.com/specify/docker-compositions/issues/7
   ve/bin/python manage.py base_specify_migration
   ve/bin/python manage.py migrate
   set -e
diff --git a/specifyweb/businessrules/uniqueness_rules.json b/specifyweb/businessrules/uniqueness_rules.json
index 2b826666f10..637184c8b51 100644
--- a/specifyweb/businessrules/uniqueness_rules.json
+++ b/specifyweb/businessrules/uniqueness_rules.json
@@ -1,234 +1,234 @@
 {
-    "Accession": [
-        {
-            "rule": [["accessionNumber"], ["division"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Accessionagent": [
-        {
-            "rule": [["role", "agent"], ["accession"]],
-            "isDatabaseConstraint": true
-        },
-        {
-            "rule": [["role", "agent"], ["repositoryagreement"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Appraisal": [
-        {
-            "rule": [["appraisalNumber"], ["accession"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Author": [
-        {
-            "rule": [["agent"], ["referenceWork"]],
-            "isDatabaseConstraint": true
-        },
-        {
-            "rule": [["orderNumber"], ["referenceWork"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Borrowagent": [
-        {
-            "rule": [["role", "agent"], ["borrow"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Collection": [
-        {
-            "rule": [["collectionName"], ["discipline"]],
-            "isDatabaseConstraint": false
-        },
-        {
-            "rule": [["code"], ["discipline"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Collectingevent": [
-        {
-            "rule": [["uniqueIdentifier"], []],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Collectionobject": [
-        {
-            "rule": [["catalogNumber"], ["collection"]],
-            "isDatabaseConstraint": true
-        },
-        {
-            "rule": [["uniqueIdentifier"], []],
-            "isDatabaseConstraint": true
-        },
-        {
-            "rule": [["guid"], []],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "CollectionObjectGroupJoin": [
-        {
-            "rule": [["childCo"], []],
-            "isDatabaseConstraint": true
-        },
-        {
-            "rule": [["childCog"], []],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Collector": [
-        {
-            "rule": [["agent"], ["collectingEvent"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Determiner": [
-        {
-            "rule": [["agent"], ["determination"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Discipline": [
-        {
-            "rule": [["name"], ["division"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Disposalagent": [
-        {
-            "rule": [["role", "agent"], ["disposal"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Division": [
-        {
-            "rule": [["name"], ["institution"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Extractor": [
-        {
-            "rule": [["agent"], ["dnaSequence"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Fundingagent": [
-        {
-            "rule": [["agent"], ["collectingTrip"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Gift": [
-        {
-            "rule": [["giftNumber"], ["discipline"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Giftagent": [
-        {
-            "rule": [["role", "agent"], ["gift"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Groupperson": [
-        {
-            "rule": [["member"], ["group"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Institution": [
-        {
-            "rule": [["name"], []],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Loan": [
-        {
-            "rule": [["loanNumber"], ["discipline"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Loanagent": [
-        {
-            "rule": [["role", "agent"], ["loan"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Locality": [
-        {
-            "rule": [["uniqueIdentifier"], []],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Localitycitation": [
-        {
-            "rule": [["referenceWork"], ["locality"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Pcrperson": [
-        {
-            "rule": [["agent"], ["dnaSequence"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Permit": [
-        {
-            "rule": [["permitNumber"], []],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Picklist": [
-        {
-            "rule": [["name"], ["collection"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Preparation": [
-        {
-            "rule": [["barCode"], ["collectionobject__collection"]],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Preptype": [
-        {
-            "rule": [["name"], ["collection"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Repositoryagreement": [
-        {
-            "rule": [["repositoryAgreementNumber"], ["division"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Spappresourcedata": [
-        {
-            "rule": [["spAppResource"], []],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Specifyuser": [
-        {
-            "rule": [["name"], []],
-            "isDatabaseConstraint": true
-        }
-    ],
-    "Taxontreedef": [
-        {
-            "rule": [["name"], ["discipline"]],
-            "isDatabaseConstraint": false
-        }
-    ],
-    "Taxontreedefitem": [
-        {
-            "rule": [["name"], ["treeDef"]],
-            "isDatabaseConstraint": false
-        },
-        {
-            "rule": [["title"], ["treeDef"]],
-            "isDatabaseConstraint": false
-        }
-    ]
+  "Accession": [
+    {
+      "rule": [["accessionNumber"], ["division"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Accessionagent": [
+    {
+      "rule": [["role", "agent"], ["accession"]],
+      "isDatabaseConstraint": true
+    },
+    {
+      "rule": [["role", "agent"], ["repositoryagreement"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Appraisal": [
+    {
+      "rule": [["appraisalNumber"], ["accession"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Author": [
+    {
+      "rule": [["agent"], ["referenceWork"]],
+      "isDatabaseConstraint": true
+    },
+    {
+      "rule": [["orderNumber"], ["referenceWork"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Borrowagent": [
+    {
+      "rule": [["role", "agent"], ["borrow"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Collection": [
+    {
+      "rule": [["collectionName"], ["discipline"]],
+      "isDatabaseConstraint": false
+    },
+    {
+      "rule": [["code"], ["discipline"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Collectingevent": [
+    {
+      "rule": [["uniqueIdentifier"], []],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Collectionobject": [
+    {
+      "rule": [["catalogNumber"], ["collection"]],
+      "isDatabaseConstraint": true
+    },
+    {
+      "rule": [["uniqueIdentifier"], []],
+      "isDatabaseConstraint": true
+    },
+    {
+      "rule": [["guid"], []],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "CollectionObjectGroupJoin": [
+    {
+      "rule": [["childCo"], []],
+      "isDatabaseConstraint": true
+    },
+    {
+      "rule": [["childCog"], []],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Collector": [
+    {
+      "rule": [["agent"], ["collectingEvent"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Determiner": [
+    {
+      "rule": [["agent"], ["determination"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Discipline": [
+    {
+      "rule": [["name"], ["division"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Disposalagent": [
+    {
+      "rule": [["role", "agent"], ["disposal"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Division": [
+    {
+      "rule": [["name"], ["institution"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Extractor": [
+    {
+      "rule": [["agent"], ["dnaSequence"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Fundingagent": [
+    {
+      "rule": [["agent"], ["collectingTrip"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Gift": [
+    {
+      "rule": [["giftNumber"], ["discipline"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Giftagent": [
+    {
+      "rule": [["role", "agent"], ["gift"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Groupperson": [
+    {
+      "rule": [["member"], ["group"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Institution": [
+    {
+      "rule": [["name"], []],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Loan": [
+    {
+      "rule": [["loanNumber"], ["discipline"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Loanagent": [
+    {
+      "rule": [["role", "agent"], ["loan"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Locality": [
+    {
+      "rule": [["uniqueIdentifier"], []],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Localitycitation": [
+    {
+      "rule": [["referenceWork"], ["locality"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Pcrperson": [
+    {
+      "rule": [["agent"], ["dnaSequence"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Permit": [
+    {
+      "rule": [["permitNumber"], []],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Picklist": [
+    {
+      "rule": [["name"], ["collection"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Preparation": [
+    {
+      "rule": [["barCode"], ["collectionobject__collection"]],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Preptype": [
+    {
+      "rule": [["name"], ["collection"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Repositoryagreement": [
+    {
+      "rule": [["repositoryAgreementNumber"], ["division"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Spappresourcedata": [
+    {
+      "rule": [["spAppResource"], []],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Specifyuser": [
+    {
+      "rule": [["name"], []],
+      "isDatabaseConstraint": true
+    }
+  ],
+  "Taxontreedef": [
+    {
+      "rule": [["name"], ["discipline"]],
+      "isDatabaseConstraint": false
+    }
+  ],
+  "Taxontreedefitem": [
+    {
+      "rule": [["name"], ["treeDef"]],
+      "isDatabaseConstraint": false
+    },
+    {
+      "rule": [["title"], ["treeDef"]],
+      "isDatabaseConstraint": false
+    }
+  ]
 }
diff --git a/specifyweb/frontend/js_src/.prettierignore b/specifyweb/frontend/js_src/.prettierignore
index 7fec54fbb52..a0078ceff76 100644
--- a/specifyweb/frontend/js_src/.prettierignore
+++ b/specifyweb/frontend/js_src/.prettierignore
@@ -7,10 +7,7 @@
 /../../../config/
 /../static/img/
 /../../specify/fixtures/
-# Uses case sensitive markdown - incompatible with our Prettier config
 /../../../.github/ISSUE_TEMPLATE/
-# Skipping in case people don't want line wrapping in this file
 /../../../CHANGELOG.md
 /../../../release-notes/
-# Prettier fails to parse the syntax in Dockerfile
 /../../../Dockerfile
diff --git a/specifyweb/frontend/js_src/css/main.css b/specifyweb/frontend/js_src/css/main.css
index efc7ff4a690..985f7723388 100644
--- a/specifyweb/frontend/js_src/css/main.css
+++ b/specifyweb/frontend/js_src/css/main.css
@@ -161,7 +161,9 @@
     @apply text-center;
   }
 
-  .button:is([aria-pressed='true'], [aria-selected='true'], [aria-current]):not(.aria-handled) {
+  .button:is([aria-pressed='true'], [aria-selected='true'], [aria-current]):not(
+      .aria-handled
+    ) {
     @apply ring-[color:var(--accent-color-300)] brightness-[1.2] dark:brightness-[1.5];
   }
 
diff --git a/specifyweb/frontend/js_src/css/workbench.css b/specifyweb/frontend/js_src/css/workbench.css
index f7839c71071..43c39e0ac9f 100644
--- a/specifyweb/frontend/js_src/css/workbench.css
+++ b/specifyweb/frontend/js_src/css/workbench.css
@@ -50,7 +50,12 @@
 /* Cell navigation */
 
 .wbs-form
-  :is(.wb-no-match-cell, .wb-modified-cell, .htCommentCell, .wb-search-match-cell),
+  :is(
+    .wb-no-match-cell,
+    .wb-modified-cell,
+    .htCommentCell,
+    .wb-search-match-cell
+  ),
 .wb-navigation-section {
   @apply !bg-[color:var(--accent-color)];
 }
diff --git a/specifyweb/frontend/js_src/lib/components/AppResources/EditorComponents.tsx b/specifyweb/frontend/js_src/lib/components/AppResources/EditorComponents.tsx
index e0ca54ebcfa..2e61fc63d87 100644
--- a/specifyweb/frontend/js_src/lib/components/AppResources/EditorComponents.tsx
+++ b/specifyweb/frontend/js_src/lib/components/AppResources/EditorComponents.tsx
@@ -246,10 +246,10 @@ export function useCodeMirrorExtensions(
       mode === 'json'
         ? [json(), jsonLinter(handleLinted)]
         : mode === 'properties'
-        ? [StreamLanguage.define(properties)]
-        : mode === 'jrxml' || mode === 'xml'
-        ? [xml(), xmlLinter(xmlSpec?.())(handleLinted)]
-        : [];
+          ? [StreamLanguage.define(properties)]
+          : mode === 'jrxml' || mode === 'xml'
+            ? [xml(), xmlLinter(xmlSpec?.())(handleLinted)]
+            : [];
     setExtensions([
       ...language,
       ...(lineWrap ? [EditorView.lineWrapping] : []),
diff --git a/specifyweb/frontend/js_src/lib/components/AppResources/codeMirrorLinters.ts b/specifyweb/frontend/js_src/lib/components/AppResources/codeMirrorLinters.ts
index 7243130df79..27107000db0 100644
--- a/specifyweb/frontend/js_src/lib/components/AppResources/codeMirrorLinters.ts
+++ b/specifyweb/frontend/js_src/lib/components/AppResources/codeMirrorLinters.ts
@@ -50,8 +50,8 @@ export const xmlLinter = (
     return typeof parsed === 'string'
       ? [formatXmlError(state.doc, parsed)]
       : typeof spec === 'object'
-      ? parseXmlUsingSpec(spec, parsed, string)
-      : [];
+        ? parseXmlUsingSpec(spec, parsed, string)
+        : [];
   });
 
 function parseXmlUsingSpec(
diff --git a/specifyweb/frontend/js_src/lib/components/AppResources/filtersHelpers.ts b/specifyweb/frontend/js_src/lib/components/AppResources/filtersHelpers.ts
index 94e2e1c1ec8..446eb29de05 100644
--- a/specifyweb/frontend/js_src/lib/components/AppResources/filtersHelpers.ts
+++ b/specifyweb/frontend/js_src/lib/components/AppResources/filtersHelpers.ts
@@ -48,10 +48,10 @@ export const filterAppResources = (
     filters.appResources.length === 0
       ? []
       : isAllAppResourceTypes(filters.appResources)
-      ? resources.appResources
-      : resources.appResources.filter((resource) =>
-          filters.appResources.includes(getAppResourceType(resource))
-        ),
+        ? resources.appResources
+        : resources.appResources.filter((resource) =>
+            filters.appResources.includes(getAppResourceType(resource))
+          ),
 });
 
 export const getResourceType = (
@@ -65,8 +65,8 @@ export const getAppResourceType = (
 ): keyof typeof appResourceSubTypes =>
   resource.name === 'preferences' && (resource.mimeType ?? '') === ''
     ? 'otherPropertiesResource'
-    : Object.entries(appResourceSubTypes).find(([_key, { name, mimeType }]) =>
+    : (Object.entries(appResourceSubTypes).find(([_key, { name, mimeType }]) =>
         name === undefined
           ? mimeType === resource.mimeType
           : name === resource.name
-      )?.[KEY] ?? 'otherAppResources';
+      )?.[KEY] ?? 'otherAppResources');
diff --git a/specifyweb/frontend/js_src/lib/components/Atoms/DataEntry.tsx b/specifyweb/frontend/js_src/lib/components/Atoms/DataEntry.tsx
index b475a0036e2..dec9e514efd 100644
--- a/specifyweb/frontend/js_src/lib/components/Atoms/DataEntry.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Atoms/DataEntry.tsx
@@ -97,9 +97,9 @@ export const DataEntry = {
     'div',
     {
       readonly colSpan: number;
-      readonly align: typeof cellAlign[number];
+      readonly align: (typeof cellAlign)[number];
       readonly visible: boolean;
-      readonly verticalAlign: typeof cellVerticalAlign[number];
+      readonly verticalAlign: (typeof cellVerticalAlign)[number];
     }
   >(
     'DataEntry.Cell',
@@ -115,18 +115,18 @@ export const DataEntry = {
           align === 'right'
             ? 'flex-end'
             : align === 'center'
-            ? 'center'
-            : undefined,
+              ? 'center'
+              : undefined,
         alignSelf:
           verticalAlign === 'stretch'
             ? 'stretch'
             : verticalAlign === 'center'
-            ? 'self-center'
-            : verticalAlign === 'start'
-            ? 'self-start'
-            : verticalAlign === 'end'
-            ? 'self-end'
-            : undefined,
+              ? 'self-center'
+              : verticalAlign === 'start'
+                ? 'self-start'
+                : verticalAlign === 'end'
+                  ? 'self-end'
+                  : undefined,
         ...props.style,
       },
     })
diff --git a/specifyweb/frontend/js_src/lib/components/Atoms/wrapper.ts b/specifyweb/frontend/js_src/lib/components/Atoms/wrapper.ts
index e536b92d26d..617bbfb9788 100644
--- a/specifyweb/frontend/js_src/lib/components/Atoms/wrapper.ts
+++ b/specifyweb/frontend/js_src/lib/components/Atoms/wrapper.ts
@@ -47,7 +47,7 @@ export function wrap<
    * For example, can make some optional props be required, forbid passing
    * children, or mutate extra props using mergeProps callback
    */
-  EXTRA_PROPS extends IR = RR
+  EXTRA_PROPS extends IR = RR,
 >(
   // Would be shown in React DevTools
   name: string,
diff --git a/specifyweb/frontend/js_src/lib/components/Attachments/index.tsx b/specifyweb/frontend/js_src/lib/components/Attachments/index.tsx
index 8090f1ee5d2..be312b3528f 100644
--- a/specifyweb/frontend/js_src/lib/components/Attachments/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Attachments/index.tsx
@@ -139,15 +139,15 @@ function Attachments({
           filter.type === 'unused'
             ? backendFilter('tableId').isNull()
             : filter.type === 'byTable'
-            ? {
-                tableId: genericTables[filter.tableName].tableId,
-              }
-            : allTablesWithAttachments().length ===
-              tablesWithAttachments().length
-            ? {}
-            : backendFilter('tableId').isIn(
-                tablesWithAttachments().map(({ tableId }) => tableId)
-              )
+              ? {
+                  tableId: genericTables[filter.tableName].tableId,
+                }
+              : allTablesWithAttachments().length ===
+                  tablesWithAttachments().length
+                ? {}
+                : backendFilter('tableId').isIn(
+                    tablesWithAttachments().map(({ tableId }) => tableId)
+                  )
         ),
       [order, filter]
     )
diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Datasets.tsx b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Datasets.tsx
index 81e51a85e47..be75e27484e 100644
--- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Datasets.tsx
+++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Datasets.tsx
@@ -119,8 +119,8 @@ export function AttachmentsImportOverlay(): JSX.Element | null {
             sortConfig.sortField === 'timestampCreated'
               ? dataset.timestampcreated
               : sortConfig.sortField === 'timestampModified'
-              ? dataset.timestampmodified
-              : dataset.name
+                ? dataset.timestampmodified
+                : dataset.name
           ),
     [unsortedDatasets, applySortConfig, sortConfig]
   );
@@ -200,9 +200,9 @@ export function AttachmentsImportOverlay(): JSX.Element | null {
                       label
                       name={
                         attachmentDataSet.uploadplan?.staticPathKey
-                          ? staticAttachmentImportPaths[
+                          ? (staticAttachmentImportPaths[
                               attachmentDataSet.uploadplan.staticPathKey
-                            ]?.baseTable ?? 'Workbench'
+                            ]?.baseTable ?? 'Workbench')
                           : 'Workbench'
                       }
                     />
diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Upload.tsx b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Upload.tsx
index 654d2bbe6a1..d4e8d6ce3c1 100644
--- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Upload.tsx
+++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Upload.tsx
@@ -334,10 +334,11 @@ async function uploadFileWrapped({
    */
   const attachmentUpload =
     uploadableFile.attachmentFromPreviousTry ??
-    (await (uploadableFile.uploadTokenSpec === undefined
-      ? Promise.resolve(undefined)
-      : // Connection could be lost here, so silencing errors
-        fetchAssetToken(uploadAttachmentSpec?.attachmentLocation!, true)
+    (await (
+      uploadableFile.uploadTokenSpec === undefined
+        ? Promise.resolve(undefined)
+        : // Connection could be lost here, so silencing errors
+          fetchAssetToken(uploadAttachmentSpec?.attachmentLocation!, true)
     )
       .then(async (token) =>
         /*
diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/types.ts b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/types.ts
index 0d9d37988cb..b39a0addb72 100644
--- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/types.ts
+++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/types.ts
@@ -119,19 +119,18 @@ export type AttachmentDataSet = AttachmentDatasetBrief &
     };
   };
 
-export type FetchedDataSet =
-  | AttachmentDataSet &
-      (
-        | { readonly uploaderstatus: 'main' }
-        | ({
-            readonly uploaderstatus: 'deleting' | 'uploading';
-            readonly rows: RA;
-          } & {
-            readonly uploadplan: {
-              readonly staticPathKey: keyof typeof staticAttachmentImportPaths;
-            };
-          })
-      );
+export type FetchedDataSet = AttachmentDataSet &
+  (
+    | { readonly uploaderstatus: 'main' }
+    | ({
+        readonly uploaderstatus: 'deleting' | 'uploading';
+        readonly rows: RA;
+      } & {
+        readonly uploadplan: {
+          readonly staticPathKey: keyof typeof staticAttachmentImportPaths;
+        };
+      })
+  );
 
 export type WrappedActionProps = {
   readonly uploadableFile: PartialUploadableFileSpec;
diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/useEagerDataset.ts b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/useEagerDataset.ts
index aae5d2ba20c..437bb9c25dc 100644
--- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/useEagerDataset.ts
+++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/useEagerDataset.ts
@@ -84,8 +84,8 @@ export function useEagerDataSet(baseDataSet: AttachmentDataSet): {
       baseDataSet.uploaderstatus === 'uploading'
         ? 'uploadInterrupted'
         : baseDataSet.uploaderstatus === 'deleting'
-        ? 'deletingInterrupted'
-        : 'main',
+          ? 'deletingInterrupted'
+          : 'main',
     needsSaved: baseDataSet.uploaderstatus !== 'main',
     rows: baseDataSet.rows ?? [],
     save: false,
diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/utils.ts b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/utils.ts
index a9cb8c07eb7..8693c397fc3 100644
--- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/utils.ts
+++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/utils.ts
@@ -53,14 +53,14 @@ const resolveAttachmentMatch = (
   matchedId.length === 0
     ? { type: 'invalid', reason: 'noMatch' }
     : matchedId.length > 1 && disambiguated === undefined
-    ? {
-        type: 'invalid',
-        reason: 'multipleMatches',
-      }
-    : {
-        type: 'matched',
-        id: disambiguated ?? matchedId[0],
-      };
+      ? {
+          type: 'invalid',
+          reason: 'multipleMatches',
+        }
+      : {
+          type: 'matched',
+          id: disambiguated ?? matchedId[0],
+        };
 
 export function resolveAttachmentRecord(
   matchedId: RA | undefined,
@@ -422,17 +422,17 @@ export const inferUploadedAttachments = (
         typeof foundInQueryResult === 'object'
           ? ({ type: 'success', successType: 'uploaded' } as const)
           : uploadable.status.type === 'matched'
-          ? //
-            /*
-             *BUG: Handle case where attachment location is set to null or resource no longer exists better.
-             * Currently, it will incorrectly inform it to be interrupted. That is fine since trying to upload
-             * the dataset will automatically correctly regenerate tokens / show match error
-             */
-            ({
-              type: 'cancelled',
-              reason: 'uploadInterruption',
-            } as const)
-          : uploadable.status,
+            ? //
+              /*
+               *BUG: Handle case where attachment location is set to null or resource no longer exists better.
+               * Currently, it will incorrectly inform it to be interrupted. That is fine since trying to upload
+               * the dataset will automatically correctly regenerate tokens / show match error
+               */
+              ({
+                type: 'cancelled',
+                reason: 'uploadInterruption',
+              } as const)
+            : uploadable.status,
     };
   });
 
@@ -454,11 +454,11 @@ export const inferDeletedAttachments = (
         foundInQueryResult === undefined
           ? ({ type: 'success', successType: 'deleted' } as const)
           : deletable.status.type === 'matched'
-          ? ({
-              type: 'cancelled',
-              reason: 'rollbackInterruption',
-            } as const)
-          : deletable.status,
+            ? ({
+                type: 'cancelled',
+                reason: 'rollbackInterruption',
+              } as const)
+            : deletable.status,
     };
   });
 
diff --git a/specifyweb/frontend/js_src/lib/components/DataEntryTables/Edit.tsx b/specifyweb/frontend/js_src/lib/components/DataEntryTables/Edit.tsx
index 663d9dc27b4..b12154b8fa7 100644
--- a/specifyweb/frontend/js_src/lib/components/DataEntryTables/Edit.tsx
+++ b/specifyweb/frontend/js_src/lib/components/DataEntryTables/Edit.tsx
@@ -95,8 +95,8 @@ export function useFormTables(
     tables === 'legacy'
       ? []
       : tables.length === 0
-      ? filterArray(defaultVisibleForms[type].map(getTable))
-      : tables.map(getTableById);
+        ? filterArray(defaultVisibleForms[type].map(getTable))
+        : tables.map(getTableById);
   const accessibleTables = visibleTables.filter(({ name }) =>
     hasTablePermission(name, 'read')
   );
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/__tests__/resourceApi.test.ts b/specifyweb/frontend/js_src/lib/components/DataModel/__tests__/resourceApi.test.ts
index af8bab872c9..e594c6b55e7 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/__tests__/resourceApi.test.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/__tests__/resourceApi.test.ts
@@ -209,9 +209,8 @@ describe('rgetCollection', () => {
       id: collectionObjectId,
     });
     const firstDeterminations = await resource.rgetCollection('determinations');
-    const secondDeterminations = await resource.rgetCollection(
-      'determinations'
-    );
+    const secondDeterminations =
+      await resource.rgetCollection('determinations');
     expect(firstDeterminations.toJSON()).toEqual(determinationsResponse);
     expect(secondDeterminations.toJSON()).toEqual(determinationsResponse);
     expect(firstDeterminations).toBe(secondDeterminations);
@@ -412,9 +411,8 @@ describe('placeInSameHierarchy', () => {
       id: 5,
     });
     const locality = new tables.Locality.Resource();
-    const hierarchyResource = await locality.placeInSameHierarchy(
-      collectionObject
-    );
+    const hierarchyResource =
+      await locality.placeInSameHierarchy(collectionObject);
     expect(hierarchyResource?.url()).toBe(getResourceApiUrl('Discipline', 3));
     expect(locality.get('discipline')).toBe(getResourceApiUrl('Discipline', 3));
   });
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/addMissingFields.ts b/specifyweb/frontend/js_src/lib/components/DataModel/addMissingFields.ts
index a9ce67885fe..982ae6f4ec4 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/addMissingFields.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/addMissingFields.ts
@@ -58,16 +58,16 @@ export function addMissingFields(
                 field.name,
                 field.isRelationship
                   ? handleRelationship(record, field, spec)
-                  : record[field.name as keyof typeof record] ??
+                  : (record[field.name as keyof typeof record] ??
                     (field.name === 'version'
                       ? 1
                       : (
-                          field.isRequired
-                            ? requiredFields === 'set'
-                            : optionalFields === 'set'
-                        )
-                      ? parserFromType(field.type).value
-                      : null),
+                            field.isRequired
+                              ? requiredFields === 'set'
+                              : optionalFields === 'set'
+                          )
+                        ? parserFromType(field.type).value
+                        : null)),
               ]
             : undefined
         )
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/businessRuleDefs.ts b/specifyweb/frontend/js_src/lib/components/DataModel/businessRuleDefs.ts
index a1b0c4b6747..0eeb3040f57 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/businessRuleDefs.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/businessRuleDefs.ts
@@ -115,8 +115,8 @@ export const businessRuleDefs: MappedBusinessRuleDefs = {
             ? returned > quantity
               ? quantity
               : returned > resolved
-              ? resolved
-              : returned
+                ? resolved
+                : returned
             : undefined;
         if (typeof adjustedReturned === 'number')
           borrowMaterial.set('quantityReturned', adjustedReturned);
@@ -135,8 +135,8 @@ export const businessRuleDefs: MappedBusinessRuleDefs = {
             ? resolved > quantity
               ? quantity
               : resolved < returned
-              ? returned
-              : resolved
+                ? returned
+                : resolved
             : undefined;
 
         if (typeof adjustedResolved === 'number')
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts b/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts
index 1d674cda2a0..462bf2bd323 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts
@@ -496,8 +496,8 @@ export const runAllFieldChecks = async (
     (result === undefined || result === null
       ? []
       : result instanceof ResourceBase
-      ? [result]
-      : (result as Collection).models) as unknown as RA<
+        ? [result]
+        : (result as Collection).models) as unknown as RA<
       SpecifyResource
     >;
   // Running only on dependent resources. the order shouldn't matter.....
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/collection.ts b/specifyweb/frontend/js_src/lib/components/DataModel/collection.ts
index 06010a7fbe3..9aa75af2d83 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/collection.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/collection.ts
@@ -48,7 +48,7 @@ export type SerializedCollection = {
  */
 export const fetchCollection = async <
   TABLE_NAME extends keyof Tables,
-  SCHEMA extends Tables[TABLE_NAME]
+  SCHEMA extends Tables[TABLE_NAME],
 >(
   tableName: TABLE_NAME,
   // Basic filters. Type-safe
@@ -125,7 +125,7 @@ function mapValue(
  */
 export async function fetchRelated<
   SCHEMA extends AnySchema,
-  RELATIONSHIP extends string & keyof SCHEMA['toManyIndependent']
+  RELATIONSHIP extends string & keyof SCHEMA['toManyIndependent'],
 >(
   resource: SerializedResource,
   relationshipName: RELATIONSHIP,
@@ -159,17 +159,17 @@ export async function fetchRelated<
 }
 
 type FieldsToTypes<
-  FIELDS extends IR>
+  FIELDS extends IR>,
 > = {
   readonly [FIELD in keyof FIELDS]: FIELDS[FIELD][number] extends 'boolean'
     ? boolean
     : FIELDS[FIELD][number] | never extends 'null'
-    ? null
-    : FIELDS[FIELD][number] | never extends 'number'
-    ? number
-    : FIELDS[FIELD][number] | never extends 'string'
-    ? string
-    : never;
+      ? null
+      : FIELDS[FIELD][number] | never extends 'number'
+        ? number
+        : FIELDS[FIELD][number] | never extends 'string'
+          ? string
+          : never;
 };
 
 /**
@@ -181,7 +181,7 @@ export const fetchRows = async <
   FIELDS extends RR<
     Exclude | string,
     RA<'boolean' | 'null' | 'number' | 'string'>
-  >
+  >,
 >(
   tableName: TABLE_NAME,
   // Basic filters. Type-safe
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/helperTypes.ts b/specifyweb/frontend/js_src/lib/components/DataModel/helperTypes.ts
index cccbd567d90..2aafeeb7706 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/helperTypes.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/helperTypes.ts
@@ -111,22 +111,22 @@ export type SerializedResource = {
     | keyof SCHEMA['toOneIndependent']]: KEY extends keyof CommonFields
     ? CommonFields[KEY]
     : KEY extends keyof SCHEMA['fields']
-    ? SCHEMA['fields'][KEY]
-    : KEY extends keyof SCHEMA['toOneDependent']
-    ? Partial<
-        SerializedResource>
-      > | null extends SCHEMA['toOneDependent'][KEY]
-      ? null
-      : never
-    : KEY extends keyof SCHEMA['toOneIndependent']
-    ? null extends SCHEMA['toOneIndependent'][KEY]
-      ? string | null
-      : string
-    : KEY extends keyof SCHEMA['toManyDependent']
-    ? RA>
-    : KEY extends keyof SCHEMA['toManyIndependent']
-    ? string
-    : never;
+      ? SCHEMA['fields'][KEY]
+      : KEY extends keyof SCHEMA['toOneDependent']
+        ? Partial<
+            SerializedResource>
+          > | null extends SCHEMA['toOneDependent'][KEY]
+          ? null
+          : never
+        : KEY extends keyof SCHEMA['toOneIndependent']
+          ? null extends SCHEMA['toOneIndependent'][KEY]
+            ? string | null
+            : string
+          : KEY extends keyof SCHEMA['toManyDependent']
+            ? RA>
+            : KEY extends keyof SCHEMA['toManyIndependent']
+              ? string
+              : never;
 };
 
 /** Convert type's keys to lowercase */
@@ -136,10 +136,10 @@ export type KeysToLowerCase> = {
   >]: DICTIONARY[KEY] extends IR
     ? KeysToLowerCase
     : DICTIONARY[KEY] extends RA
-    ? RA<
-        DICTIONARY[KEY][number] extends IR
-          ? KeysToLowerCase
-          : DICTIONARY[KEY][number]
-      >
-    : DICTIONARY[KEY];
+      ? RA<
+          DICTIONARY[KEY][number] extends IR
+            ? KeysToLowerCase
+            : DICTIONARY[KEY][number]
+        >
+      : DICTIONARY[KEY];
 };
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/helpers.ts b/specifyweb/frontend/js_src/lib/components/DataModel/helpers.ts
index bc7b53e976b..83db501aa4b 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/helpers.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/helpers.ts
@@ -117,7 +117,7 @@ const _backendFilters = (field: string, ...fieldTransforms: RA) =>
           ? value
           : caseInsensitiveHash(weekDayMap, value),
     }),
-  } as const);
+  }) as const;
 
 /**
  * Use this to construct a query using a lookup for Django.
@@ -170,7 +170,7 @@ export const toResource = (
  */
 export const getField = <
   SCHEMA extends ValueOf,
-  FIELD extends TableFields
+  FIELD extends TableFields,
 >(
   table: SpecifyTable,
   name: FIELD
@@ -228,13 +228,13 @@ export async function fetchDistantRelated(
     fields === undefined || fields.length === 0
       ? resource
       : fields.length === 1
-      ? await resource.fetch()
-      : await resource.rgetPromise(
-          fields
-            .slice(0, -1)
-            .map(({ name }) => name)
-            .join(backboneFieldSeparator)
-        );
+        ? await resource.fetch()
+        : await resource.rgetPromise(
+            fields
+              .slice(0, -1)
+              .map(({ name }) => name)
+              .join(backboneFieldSeparator)
+          );
 
   const field = fields?.at(-1);
   const relatedResource = related ?? undefined;
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/legacyTypes.ts b/specifyweb/frontend/js_src/lib/components/DataModel/legacyTypes.ts
index 13bb62f3826..22b4bb1413b 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/legacyTypes.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/legacyTypes.ts
@@ -56,19 +56,19 @@ export type SpecifyResource = {
       SCHEMA['toManyDependent'] &
       SCHEMA['toManyIndependent'] &
       SCHEMA['toOneDependent'] &
-      SCHEMA['toOneIndependent'])[FIELD_NAME]
+      SCHEMA['toOneIndependent'])[FIELD_NAME],
   >(
     fieldName: FIELD_NAME
     // eslint-disable-next-line functional/prefer-readonly-type
   ): [VALUE] extends [never]
     ? never
     : VALUE extends AnySchema
-    ? VALUE extends null
-      ? string | null
-      : string
-    : VALUE extends RA
-    ? string
-    : VALUE;
+      ? VALUE extends null
+        ? string | null
+        : string
+      : VALUE extends RA
+        ? string
+        : VALUE;
   // Case-insensitive fetch of a -to-one resource
   rgetPromise<
     FIELD_NAME extends
@@ -76,7 +76,7 @@ export type SpecifyResource = {
       | keyof SCHEMA['toOneIndependent'],
     VALUE = (IR &
       SCHEMA['toOneDependent'] &
-      SCHEMA['toOneIndependent'])[FIELD_NAME]
+      SCHEMA['toOneIndependent'])[FIELD_NAME],
   >(
     fieldName: FIELD_NAME,
     prePopulate?: boolean
@@ -93,7 +93,7 @@ export type SpecifyResource = {
       | keyof SCHEMA['toOneIndependent'],
     VALUE = (IR &
       SCHEMA['toOneDependent'] &
-      SCHEMA['toOneIndependent'])[FIELD_NAME]
+      SCHEMA['toOneIndependent'])[FIELD_NAME],
   >(
     fieldName: FIELD_NAME,
     options?: {
@@ -112,7 +112,7 @@ export type SpecifyResource = {
     FIELD_NAME extends keyof (SCHEMA['toManyDependent'] &
       SCHEMA['toManyIndependent']),
     VALUE extends (SCHEMA['toManyDependent'] &
-      SCHEMA['toManyIndependent'])[FIELD_NAME]
+      SCHEMA['toManyIndependent'])[FIELD_NAME],
   >(
     fieldName: FIELD_NAME,
     filters?: CollectionFetchFilters
@@ -131,7 +131,7 @@ export type SpecifyResource = {
       SCHEMA['toManyDependent'] &
       SCHEMA['toManyIndependent'] &
       SCHEMA['toOneDependent'] &
-      SCHEMA['toOneIndependent'])[FIELD_NAME]
+      SCHEMA['toOneIndependent'])[FIELD_NAME],
   >(
     fieldName: FIELD_NAME,
     value: readonly [VALUE] extends readonly [never]
@@ -149,11 +149,11 @@ export type SpecifyResource = {
                   | RA>
                   | RA>
               : null extends VALUE
-              ?
-                  | SerializedResource>
-                  | SpecifyResource>
-                  | null
-              : SerializedResource | SpecifyResource),
+                ?
+                    | SerializedResource>
+                    | SpecifyResource>
+                    | null
+                : SerializedResource | SpecifyResource),
     options?: { readonly silent: boolean }
   ): SpecifyResource;
   // Not type safe
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/resource.ts b/specifyweb/frontend/js_src/lib/components/DataModel/resource.ts
index 581e2876960..e41f70e92b7 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/resource.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/resource.ts
@@ -42,7 +42,7 @@ export const resourceEvents = eventListener<{
 export const fetchResource = async <
   TABLE_NAME extends keyof Tables,
   SCHEMA extends Tables[TABLE_NAME],
-  STRICT extends boolean = true
+  STRICT extends boolean = true,
 >(
   tableName: TABLE_NAME,
   id: number,
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/resourceApi.ts b/specifyweb/frontend/js_src/lib/components/DataModel/resourceApi.ts
index e9dc9630ade..2fe9e86ae5f 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/resourceApi.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/resourceApi.ts
@@ -89,7 +89,7 @@ function eventHandlerForToMany(related, field) {
 // Always returns a resource
 const maybeMakeResource = <
   TABLE extends SpecifyTable,
-  TABLE_SCHEMA extends Tables[TABLE['name']]
+  TABLE_SCHEMA extends Tables[TABLE['name']],
 >(
   value:
     | Partial | SerializedResource>
@@ -364,9 +364,9 @@ export const ResourceBase = Backbone.Model.extend({
     const newValue = value ?? undefined;
     const oldValue =
       typeof key === 'string'
-        ? this.attributes[key.toLowerCase()] ??
+        ? (this.attributes[key.toLowerCase()] ??
           this.dependentResources[key.toLowerCase()] ??
-          undefined
+          undefined)
         : undefined;
     // Don't needlessly trigger unload protect if value didn't change
     if (
@@ -464,12 +464,12 @@ export const ResourceBase = Backbone.Model.extend({
       value = _.isString(value)
         ? this._handleUri(value, fieldName)
         : typeof value === 'number'
-        ? this._handleUri(
-            // Back-end sends SpPrincipal.scope as a number, rather than as a URL
-            getResourceApiUrl(field.table.name, value),
-            fieldName
-          )
-        : this._handleInlineDataOrResource(value, fieldName);
+          ? this._handleUri(
+              // Back-end sends SpPrincipal.scope as a number, rather than as a URL
+              getResourceApiUrl(field.table.name, value),
+              fieldName
+            )
+          : this._handleInlineDataOrResource(value, fieldName);
     }
     return [fieldName, value];
   },
@@ -636,7 +636,8 @@ export const ResourceBase = Backbone.Model.extend({
          * or collection
          */
         if (options.prePop) {
-          if (!value) return value; // Ok if the related resource doesn't exist
+          if (!value)
+            return value; // Ok if the related resource doesn't exist
           else if (typeof value.fetchIfNotPopulated === 'function')
             return value.fetchIfNotPopulated();
           /*
@@ -906,8 +907,8 @@ export const ResourceBase = Backbone.Model.extend({
           json[fieldName] = isRelationshipCollection(related)
             ? related.toApiJSON(options)
             : related.isNew() || related.needsSaved
-            ? related.toJSON(options)
-            : related.url();
+              ? related.toJSON(options)
+              : related.url();
         }
       }
     );
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/saveBlockers.tsx b/specifyweb/frontend/js_src/lib/components/DataModel/saveBlockers.tsx
index ed6ce30ac50..4d690b0a028 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/saveBlockers.tsx
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/saveBlockers.tsx
@@ -172,12 +172,12 @@ export function useAllSaveBlockers(
       resource === undefined
         ? undefined
         : resource.noBusinessRules
-        ? setBlockers([])
-        : blockerEvents.on(
-            'change',
-            () => setBlockers(getAllBlockers(resource, filterBlockers)),
-            true
-          ),
+          ? setBlockers([])
+          : blockerEvents.on(
+              'change',
+              () => setBlockers(getAllBlockers(resource, filterBlockers)),
+              true
+            ),
     [resource]
   );
   return blockers;
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/schema.ts b/specifyweb/frontend/js_src/lib/components/DataModel/schema.ts
index 0440bec0998..d0e376e1f5c 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/schema.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/schema.ts
@@ -16,7 +16,7 @@ import type { IR, RR, Writable } from '../../utils/types';
 import { load } from '../InitialContext';
 
 type Schema = {
-  readonly domainLevelIds: RR;
+  readonly domainLevelIds: RR<(typeof domainLevels)[number], number>;
   readonly embeddedCollectingEvent: boolean;
   readonly embeddedPaleoContext: boolean;
   readonly paleoContextChildTable: string;
@@ -28,7 +28,7 @@ type Schema = {
     'Collection',
     'Discipline',
     'Division',
-    'Institution'
+    'Institution',
   ];
   readonly referenceSymbol: string;
   readonly treeDefinitionSymbol: string;
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/schemaExtras.ts b/specifyweb/frontend/js_src/lib/components/DataModel/schemaExtras.ts
index 9fa87c36c25..00977172648 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/schemaExtras.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/schemaExtras.ts
@@ -30,7 +30,7 @@ export const schemaExtras: {
     table: SpecifyTable
   ) => readonly [
     fields: RA,
-    callback?: () => void
+    callback?: () => void,
   ];
 } = {
   Agent: (table) => [
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/scoping.ts b/specifyweb/frontend/js_src/lib/components/DataModel/scoping.ts
index 304640ff3ec..1d9fdfd18cc 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/scoping.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/scoping.ts
@@ -73,7 +73,7 @@ export function initializeResource(resource: SpecifyResource): void {
 }
 
 export function getDomainResource<
-  LEVEL extends keyof typeof schema.domainLevelIds
+  LEVEL extends keyof typeof schema.domainLevelIds,
 >(level: LEVEL): SpecifyResource]> | undefined {
   const id = schema.domainLevelIds?.[level];
   if (id === undefined) {
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/specifyField.ts b/specifyweb/frontend/js_src/lib/components/DataModel/specifyField.ts
index 2d9d1377ade..e7577da3302 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/specifyField.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/specifyField.ts
@@ -47,7 +47,7 @@ const relationshipTypes = [
   'zero-to-one',
 ] as const;
 
-export type RelationshipType = typeof relationshipTypes[number];
+export type RelationshipType = (typeof relationshipTypes)[number];
 
 export type FieldDefinition = {
   readonly column?: string;
@@ -137,8 +137,8 @@ export abstract class FieldBase {
       globalFieldOverride?.visibility === 'required'
         ? true
         : globalFieldOverride?.visibility === 'optional'
-        ? false
-        : fieldDefinition.required;
+          ? false
+          : fieldDefinition.required;
     this.type = fieldDefinition.type;
     this.length = fieldDefinition.length;
     this.databaseColumn = fieldDefinition.column;
@@ -240,8 +240,8 @@ export abstract class FieldBase {
     const name = value.startsWith('[literalField')
       ? 'literalField'
       : value.startsWith('[relationship')
-      ? 'relationship'
-      : undefined;
+        ? 'relationship'
+        : undefined;
     if (name === undefined) return undefined;
     const parts = value.replace(`[${name} `, '').replace(']', '').split('.');
     if (parts.length !== 2) return undefined;
@@ -345,9 +345,9 @@ export class Relationship extends FieldBase {
       this.name === 'collectingEvent'
       ? schema.embeddedCollectingEvent
       : this.table.name.toLowerCase() === schema.paleoContextChildTable &&
-        this.name === 'paleoContext'
-      ? schema.embeddedPaleoContext
-      : this.dependent;
+          this.name === 'paleoContext'
+        ? schema.embeddedPaleoContext
+        : this.dependent;
   }
 
   // Returns the field of the related table that is the reverse of this field.
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/specifyTable.ts b/specifyweb/frontend/js_src/lib/components/DataModel/specifyTable.ts
index e7abde2361e..2abed7540d5 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/specifyTable.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/specifyTable.ts
@@ -220,7 +220,7 @@ export class SpecifyTable {
       this.name === 'Attachment'
         ? // Render the attachment plugin rather than the form
           attachmentView
-        : tableDefinition.view ?? tableViews[this.name] ?? this.name;
+        : (tableDefinition.view ?? tableViews[this.name] ?? this.name);
     this.searchDialog = tableDefinition.searchDialog ?? undefined;
     this.tableId = tableDefinition.tableId;
     this.isSystem = tableDefinition.system;
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts b/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts
index 22a45e270c3..0aeb645b346 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts
@@ -100,7 +100,7 @@ export const fetchContext = f
       })
       .forEach(([tableDefinition, table]) => {
         const [frontEndFields, callback] = (
-          schemaExtras[table.name] as typeof schemaExtras['Agent'] | undefined
+          schemaExtras[table.name] as (typeof schemaExtras)['Agent'] | undefined
         )?.(table as SpecifyTable) ?? [[]];
         const [literalFields, relationships] = split(
           frontEndFields.map((field) => {
@@ -179,13 +179,13 @@ export function getTable(name: string): SpecifyTable | undefined {
   const lowerCase = name.toLowerCase();
   return name === ''
     ? undefined
-    : genericTables[name as keyof Tables] ??
+    : (genericTables[name as keyof Tables] ??
         Object.values(genericTables).find(
           (table) => table.name.toLowerCase() === lowerCase
         ) ??
         Object.values(genericTables).find(
           (table) => table.longName.toLowerCase() === lowerCase
-        );
+        ));
 }
 
 export const strictGetTable = (name: string): SpecifyTable =>
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/treeBusinessRules.ts b/specifyweb/frontend/js_src/lib/components/DataModel/treeBusinessRules.ts
index d7617146c3e..fb191f03d63 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/treeBusinessRules.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/treeBusinessRules.ts
@@ -91,7 +91,7 @@ export const treeBusinessRules = async (
 
 const getRelatedTreeTables = async <
   TREE extends AnyTree,
-  TREE_DEF_ITEM extends TreeDefItem
+  TREE_DEF_ITEM extends TreeDefItem,
 >(
   resource: SpecifyResource
 ): Promise<{
@@ -114,7 +114,7 @@ const getRelatedTreeTables = async <
 
 const predictFullName = async <
   TREE extends AnyTree,
-  TREE_DEF_ITEM extends TreeDefItem
+  TREE_DEF_ITEM extends TreeDefItem,
 >(
   resource: SpecifyResource,
   parent: SpecifyResource,
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/uniquenessRules.ts b/specifyweb/frontend/js_src/lib/components/DataModel/uniquenessRules.ts
index c305c903750..6d844ec6d69 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/uniquenessRules.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/uniquenessRules.ts
@@ -96,15 +96,15 @@ export function getUniquenessRules(
   return Object.keys(uniquenessRules).length === 0
     ? undefined
     : tableName === undefined
-    ? uniquenessRules
-    : uniquenessRules[tableName];
+      ? uniquenessRules
+      : uniquenessRules[tableName];
 }
 
 export function useTableUniquenessRules(
   tableName: keyof Tables
 ): readonly [
   ...tableRules: GetOrSet,
-  setCachedTableRules: (value: UniquenessRules[keyof Tables]) => void
+  setCachedTableRules: (value: UniquenessRules[keyof Tables]) => void,
 ] {
   const [rawModelRules = [], setTableUniquenessRules] = React.useState(
     uniquenessRules[tableName]
@@ -145,7 +145,7 @@ export function getUniqueInvalidReason(
 
 export async function validateUniqueness<
   TABLE_NAME extends keyof Tables,
-  SCHEMA extends Tables[TABLE_NAME]
+  SCHEMA extends Tables[TABLE_NAME],
 >(
   table: TABLE_NAME,
   fields: RA,
diff --git a/specifyweb/frontend/js_src/lib/components/Errors/ErrorBoundary.tsx b/specifyweb/frontend/js_src/lib/components/Errors/ErrorBoundary.tsx
index 2a4a5e1e385..6b0ca070e77 100644
--- a/specifyweb/frontend/js_src/lib/components/Errors/ErrorBoundary.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Errors/ErrorBoundary.tsx
@@ -89,7 +89,7 @@ export class ErrorBoundary extends React.Component<
           {this.state.errorInfo.componentStack}
         
       ) : (
-        this.props.children ?? null
+        (this.props.children ?? null)
       );
   }
 }
diff --git a/specifyweb/frontend/js_src/lib/components/Errors/FormatError.tsx b/specifyweb/frontend/js_src/lib/components/Errors/FormatError.tsx
index df0f3c85d08..03fb7df0fb9 100644
--- a/specifyweb/frontend/js_src/lib/components/Errors/FormatError.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Errors/FormatError.tsx
@@ -22,7 +22,7 @@ export function formatError(
   readonly [
     errorObject: JSX.Element,
     errorMessage: string,
-    copiableMessage: string
+    copiableMessage: string,
   ]
 > {
   const errorObject: WritableArray = [
diff --git a/specifyweb/frontend/js_src/lib/components/Errors/JsonError.tsx b/specifyweb/frontend/js_src/lib/components/Errors/JsonError.tsx
index a1997d5b97f..ea8bfd76d4f 100644
--- a/specifyweb/frontend/js_src/lib/components/Errors/JsonError.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Errors/JsonError.tsx
@@ -38,8 +38,8 @@ export function formatJsonBackendResponse(error: string): JSX.Element {
   return response.exception === 'BusinessRuleException'
     ? formatBusinessRuleException(response)
     : response.exception === 'TreeBusinessRuleException'
-    ? formatTreeBusinessRuleException(response)
-    : formatBasicResponse(response);
+      ? formatTreeBusinessRuleException(response)
+      : formatBasicResponse(response);
 }
 
 /**
diff --git a/specifyweb/frontend/js_src/lib/components/Errors/interceptLogs.ts b/specifyweb/frontend/js_src/lib/components/Errors/interceptLogs.ts
index a6121e5fa25..339e8819857 100644
--- a/specifyweb/frontend/js_src/lib/components/Errors/interceptLogs.ts
+++ b/specifyweb/frontend/js_src/lib/components/Errors/interceptLogs.ts
@@ -27,7 +27,7 @@ const logTypes = [
 export type LogMessage = {
   readonly message: RA;
   // Context is not a real type, but is used by deduplicateLogContext()
-  readonly type: typeof logTypes[number] | 'context';
+  readonly type: (typeof logTypes)[number] | 'context';
   readonly date: string;
   readonly context: IR;
 };
diff --git a/specifyweb/frontend/js_src/lib/components/Errors/logContext.ts b/specifyweb/frontend/js_src/lib/components/Errors/logContext.ts
index e7fb4948d54..167247357f8 100644
--- a/specifyweb/frontend/js_src/lib/components/Errors/logContext.ts
+++ b/specifyweb/frontend/js_src/lib/components/Errors/logContext.ts
@@ -49,8 +49,8 @@ function modifyContext(
   const path: RA = Array.isArray(rawPath)
     ? rawPath
     : rawPath === undefined
-    ? []
-    : [rawPath];
+      ? []
+      : [rawPath];
   const newPath = callback(path);
   setLogContext({
     ...getLogContext(),
diff --git a/specifyweb/frontend/js_src/lib/components/FormCells/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCells/index.tsx
index 6d5f96c9c97..866a31460d6 100644
--- a/specifyweb/frontend/js_src/lib/components/FormCells/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormCells/index.tsx
@@ -40,8 +40,8 @@ const cellRenderers: {
     readonly formatId: (id: string) => string;
     readonly resource: SpecifyResource;
     readonly formType: FormType;
-    readonly align: typeof cellAlign[number];
-    readonly verticalAlign: typeof cellVerticalAlign[number];
+    readonly align: (typeof cellAlign)[number];
+    readonly verticalAlign: (typeof cellVerticalAlign)[number];
   }) => JSX.Element | null;
 } = {
   Field({
@@ -91,7 +91,7 @@ const cellRenderers: {
         className="border-b border-gray-500"
         title={
           typeof forClass === 'string'
-            ? genericTables[forClass].localization.desc ?? undefined
+            ? (genericTables[forClass].localization.desc ?? undefined)
             : undefined
         }
       >
@@ -338,10 +338,12 @@ export function FormCell({
   readonly id: string | undefined;
   readonly formatId: (id: string) => string;
   readonly formType: FormType;
-  readonly align: typeof cellAlign[number];
-  readonly verticalAlign: typeof cellVerticalAlign[number];
+  readonly align: (typeof cellAlign)[number];
+  readonly verticalAlign: (typeof cellVerticalAlign)[number];
 }): JSX.Element {
-  const Render = cellRenderers[cellData.type] as typeof cellRenderers['Field'];
+  const Render = cellRenderers[
+    cellData.type
+  ] as (typeof cellRenderers)['Field'];
   return (
     ) => void
+    (viewSets: ViewSets, changedViewNames: RA) => void,
   ];
   readonly disciplines: RA>;
 };
diff --git a/specifyweb/frontend/js_src/lib/components/FormFields/Field.tsx b/specifyweb/frontend/js_src/lib/components/FormFields/Field.tsx
index de1a5668725..94a54096946 100644
--- a/specifyweb/frontend/js_src/lib/components/FormFields/Field.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormFields/Field.tsx
@@ -81,8 +81,8 @@ function RelationshipField({
         formatted === undefined
           ? commonText.loading()
           : formatted === false
-          ? ''
-          : formatted.toString()
+            ? ''
+            : formatted.toString()
       }
     />
   );
diff --git a/specifyweb/frontend/js_src/lib/components/FormParse/cells.ts b/specifyweb/frontend/js_src/lib/components/FormParse/cells.ts
index ef8b141fbf0..90e5465be1f 100644
--- a/specifyweb/frontend/js_src/lib/components/FormParse/cells.ts
+++ b/specifyweb/frontend/js_src/lib/components/FormParse/cells.ts
@@ -239,10 +239,10 @@ const processCellType: {
 
     const formType =
       rawFormType === undefined
-        ? defaultFormType ?? 'form'
+        ? (defaultFormType ?? 'form')
         : rawFormType === 'table'
-        ? 'formTable'
-        : 'form';
+          ? 'formTable'
+          : 'form';
 
     return {
       type: 'SubView',
@@ -299,11 +299,11 @@ const processCellType: {
 
 export type FormCellDefinition = ValueOf & {
   readonly id: string | undefined;
-  readonly align: typeof cellAlign[number];
+  readonly align: (typeof cellAlign)[number];
   readonly colSpan: number;
   readonly visible: boolean;
   readonly ariaLabel: LocalizedString | undefined;
-  readonly verticalAlign: typeof cellVerticalAlign[number];
+  readonly verticalAlign: (typeof cellVerticalAlign)[number];
 };
 
 const cellTypeTranslation: IR = {
@@ -351,13 +351,13 @@ export async function parseFormCell(
     align: f.includes(cellAlign, align)
       ? align
       : cellType === 'Label'
-      ? 'right'
-      : 'left',
+        ? 'right'
+        : 'left',
     verticalAlign: f.includes(cellVerticalAlign, verticalAlign)
       ? verticalAlign
       : cellType === 'SubView'
-      ? 'stretch'
-      : 'center',
+        ? 'stretch'
+        : 'center',
     /*
      * Specify 6 has `initialize="visible=false"` and
      * `initialize="vis=false"` attributes for some cell definitions.
diff --git a/specifyweb/frontend/js_src/lib/components/FormParse/commands.ts b/specifyweb/frontend/js_src/lib/components/FormParse/commands.ts
index 9fb87163719..61cc3511499 100644
--- a/specifyweb/frontend/js_src/lib/components/FormParse/commands.ts
+++ b/specifyweb/frontend/js_src/lib/components/FormParse/commands.ts
@@ -57,8 +57,8 @@ const processUiCommand: {
     !hasTablePermission('LoanReturnPreparation', 'update')
       ? { type: 'Blank' }
       : table.name === 'Loan'
-      ? { type: 'ReturnLoan' }
-      : { type: 'WrongTable', supportedTables: ['Loan'] },
+        ? { type: 'ReturnLoan' }
+        : { type: 'WrongTable', supportedTables: ['Loan'] },
   Unsupported: ({ name }) => {
     console.error(`Unsupported command: ${name ?? '(null)'}`);
     return { type: 'Unsupported', name };
diff --git a/specifyweb/frontend/js_src/lib/components/FormParse/fields.ts b/specifyweb/frontend/js_src/lib/components/FormParse/fields.ts
index cc723f79eda..958e4940379 100644
--- a/specifyweb/frontend/js_src/lib/components/FormParse/fields.ts
+++ b/specifyweb/frontend/js_src/lib/components/FormParse/fields.ts
@@ -195,8 +195,8 @@ const processFieldType: {
           name === 'name'
             ? 'PartialDateUI'
             : name === 'canChangePrecision'
-            ? 'false'
-            : getProperty(name),
+              ? 'false'
+              : getProperty(name),
       });
     else if (fieldType === 'checkbox') return processFieldType.Checkbox(props);
 
diff --git a/specifyweb/frontend/js_src/lib/components/FormParse/index.ts b/specifyweb/frontend/js_src/lib/components/FormParse/index.ts
index a4b2f0591ac..424b9d2e131 100644
--- a/specifyweb/frontend/js_src/lib/components/FormParse/index.ts
+++ b/specifyweb/frontend/js_src/lib/components/FormParse/index.ts
@@ -87,7 +87,7 @@ export type ViewDefinition = {
 };
 
 export const formTypes = ['form', 'formTable'] as const;
-export type FormType = typeof formTypes[number];
+export type FormType = (typeof formTypes)[number];
 export type FormMode = 'edit' | 'search' | 'view';
 
 let views: R = {};
@@ -300,9 +300,9 @@ export function resolveViewDefinition(
   const resolvedFormType =
     formType === 'formTable'
       ? 'formTable'
-      : formTypes.find(
+      : (formTypes.find(
           (type) => type.toLowerCase() === newFormType?.toLowerCase()
-        ) ?? 'form';
+        ) ?? 'form');
   if (resolvedFormType === undefined)
     console.warn(
       `Unknown form type ${
@@ -425,9 +425,10 @@ async function parseFormTableDefinition(
           : undefined) ??
         labelsForCells[cell.id ?? '']?.text ??
         (cell.type === 'Field' || cell.type === 'SubView'
-          ? table?.getField(cell.fieldNames?.join(backboneFieldSeparator) ?? '')
-              ?.label ??
-            localized(cell.fieldNames?.join(backboneFieldSeparator))
+          ? (table?.getField(
+              cell.fieldNames?.join(backboneFieldSeparator) ?? ''
+            )?.label ??
+            localized(cell.fieldNames?.join(backboneFieldSeparator)))
           : undefined),
       // Remove labels from checkboxes (as labels would be in the table header)
       ...(cell.type === 'Field' && cell.fieldDefinition.type === 'Checkbox'
diff --git a/specifyweb/frontend/js_src/lib/components/FormParse/postProcessFormDef.ts b/specifyweb/frontend/js_src/lib/components/FormParse/postProcessFormDef.ts
index 16ea6fc081a..d7dccec46da 100644
--- a/specifyweb/frontend/js_src/lib/components/FormParse/postProcessFormDef.ts
+++ b/specifyweb/frontend/js_src/lib/components/FormParse/postProcessFormDef.ts
@@ -347,11 +347,11 @@ const addMissingLabel = (
     // Don't add aria-label to checkboxes as they would already have a label
     cell.type === 'Field' && cell.fieldDefinition.type === 'Checkbox'
       ? undefined
-      : cell.ariaLabel ??
+      : (cell.ariaLabel ??
         (cell.type === 'Field' || cell.type === 'SubView'
           ? table?.getField(cell.fieldNames?.join(backboneFieldSeparator) ?? '')
               ?.label
-          : undefined),
+          : undefined)),
 });
 
 export const exportsForTests = {
diff --git a/specifyweb/frontend/js_src/lib/components/FormPlugins/DateInput.tsx b/specifyweb/frontend/js_src/lib/components/FormPlugins/DateInput.tsx
index dbd435f50c2..7bc39cd85c7 100644
--- a/specifyweb/frontend/js_src/lib/components/FormPlugins/DateInput.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormPlugins/DateInput.tsx
@@ -61,12 +61,12 @@ export function DateInput({
       moment === undefined
         ? ''
         : moment.isValid()
-        ? precision === 'full'
-          ? moment.format(inputFullFormat)
-          : precision === 'month-year'
-          ? moment.format(inputMonthFormat)
-          : moment.year().toString()
-        : inputValueRef.current;
+          ? precision === 'full'
+            ? moment.format(inputFullFormat)
+            : precision === 'month-year'
+              ? moment.format(inputMonthFormat)
+              : moment.year().toString()
+          : inputValueRef.current;
     if (inputValueRef.current !== formattedValue) {
       setInputValue(formattedValue);
       inputValueRef.current = formattedValue;
@@ -79,10 +79,10 @@ export function DateInput({
     isValid
       ? ''
       : precision === 'full'
-      ? formsText.requiredFormat({ format: fullDateFormat() })
-      : precision === 'month-year'
-      ? formsText.requiredFormat({ format: monthFormat() })
-      : formsText.invalidDate()
+        ? formsText.requiredFormat({ format: fullDateFormat() })
+        : precision === 'month-year'
+          ? formsText.requiredFormat({ format: monthFormat() })
+          : formsText.invalidDate()
   );
 
   return (
diff --git a/specifyweb/frontend/js_src/lib/components/FormPlugins/DatePrecisionPicker.tsx b/specifyweb/frontend/js_src/lib/components/FormPlugins/DatePrecisionPicker.tsx
index 2d21d77647f..a507820480e 100644
--- a/specifyweb/frontend/js_src/lib/components/FormPlugins/DatePrecisionPicker.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormPlugins/DatePrecisionPicker.tsx
@@ -19,7 +19,7 @@ export function DatePrecisionPicker({
 }: ReturnType & {
   readonly moment: readonly [
     ReturnType | undefined,
-    (value: ReturnType) => void
+    (value: ReturnType) => void,
   ];
 }): JSX.Element {
   const isReadOnly = React.useContext(ReadOnlyContext);
diff --git a/specifyweb/frontend/js_src/lib/components/FormPlugins/LatLongUi.tsx b/specifyweb/frontend/js_src/lib/components/FormPlugins/LatLongUi.tsx
index 487fcc016c9..882adfde6fe 100644
--- a/specifyweb/frontend/js_src/lib/components/FormPlugins/LatLongUi.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormPlugins/LatLongUi.tsx
@@ -13,7 +13,7 @@ import { tables } from '../DataModel/tables';
 import type { Locality } from '../DataModel/types';
 
 export const coordinateType = ['Point', 'Line', 'Rectangle'] as const;
-export type CoordinateType = typeof coordinateType[number];
+export type CoordinateType = (typeof coordinateType)[number];
 
 function Coordinate({
   resource,
@@ -81,7 +81,7 @@ function Coordinate({
     const trimmedValue = trimLatLong(value?.toString() ?? '');
     const hasValue = trimmedValue.length > 0;
     const parsed = hasValue
-      ? (fieldType === 'Lat' ? Lat : Long).parse(trimmedValue) ?? undefined
+      ? ((fieldType === 'Lat' ? Lat : Long).parse(trimmedValue) ?? undefined)
       : undefined;
 
     const isValid = !hasValue || parsed !== undefined;
@@ -96,7 +96,7 @@ function Coordinate({
     handleFormatted(
       isValid
         ? hasValue
-          ? parsed?.format(step) ?? ''
+          ? (parsed?.format(step) ?? '')
           : commonText.notApplicable()
         : undefined
     );
@@ -277,8 +277,8 @@ export function LatLongUi({
               coordinateType === 'Point'
                 ? localityText.coordinates()
                 : coordinateType === 'Line'
-                ? commonText.start()
-                : localityText.northWestCorner()
+                  ? commonText.start()
+                  : localityText.northWestCorner()
             }
             resource={resource}
             step={step}
diff --git a/specifyweb/frontend/js_src/lib/components/FormPlugins/Leaflet.tsx b/specifyweb/frontend/js_src/lib/components/FormPlugins/Leaflet.tsx
index a0ea8e3460b..fd4a0445999 100644
--- a/specifyweb/frontend/js_src/lib/components/FormPlugins/Leaflet.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormPlugins/Leaflet.tsx
@@ -50,9 +50,8 @@ function LeafletDialog({
       localityPoints={[localityData]}
       onClose={handleClose}
       onMarkerClick={async (_, { target: marker }): Promise => {
-        fullLocalityData.current ??= await fetchLocalityDataFromResource(
-          locality
-        );
+        fullLocalityData.current ??=
+          await fetchLocalityDataFromResource(locality);
         if (fullLocalityData.current === false) return;
         (marker as Leaflet.Marker)
           .getPopup()
diff --git a/specifyweb/frontend/js_src/lib/components/FormPlugins/useMoment.tsx b/specifyweb/frontend/js_src/lib/components/FormPlugins/useMoment.tsx
index 67abb79d6bc..e47972eb8b4 100644
--- a/specifyweb/frontend/js_src/lib/components/FormPlugins/useMoment.tsx
+++ b/specifyweb/frontend/js_src/lib/components/FormPlugins/useMoment.tsx
@@ -15,7 +15,7 @@ export function useMoment(
   defaultValue: Date | undefined
 ): readonly [
   ReturnType | undefined,
-  (value: ReturnType | undefined) => void
+  (value: ReturnType | undefined) => void,
 ] {
   const syncMoment = React.useCallback(
     (moment: ReturnType | undefined) => {
@@ -23,7 +23,7 @@ export function useMoment(
       const newMoment =
         value === undefined
           ? undefined
-          : dayjs(value, databaseDateFormat, true) ?? undefined;
+          : (dayjs(value, databaseDateFormat, true) ?? undefined);
 
       // Only change the object instance if it is different
       return moment === undefined ||
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Components.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Components.tsx
index 14b3179d88e..483068829a6 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Components.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Components.tsx
@@ -89,7 +89,7 @@ export function GenericFormatterPickList<
   ITEM extends {
     readonly title: LocalizedString | undefined;
     readonly table: SpecifyTable | undefined;
-  }
+  },
 >({
   table,
   value = localized(''),
@@ -172,8 +172,8 @@ export function ResourceMapping({
       ...(rawPath.length === 0
         ? [emptyMapping]
         : relationship?.isRelationship === false
-        ? []
-        : [formattedEntry]),
+          ? []
+          : [formattedEntry]),
     ]);
   }, [mapping, table.name]);
   const [mappingPath, setMappingPath] = React.useState(sourcePath);
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Element.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Element.tsx
index 7a2d01ff2a1..4b5fbbc4044 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Element.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Element.tsx
@@ -30,7 +30,7 @@ import type { FormatterTypesOutlet } from './Types';
  */
 export function XmlEditorShell<
   ITEM extends { readonly name: string },
-  OUTLET_CONTEXT extends { readonly items: GetSet> }
+  OUTLET_CONTEXT extends { readonly items: GetSet> },
 >({
   header,
   children,
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/List.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/List.tsx
index 4192ec8f377..5c4423aff0f 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/List.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/List.tsx
@@ -76,7 +76,7 @@ export function XmlEntryList<
   ITEM extends {
     readonly table: SpecifyTable | undefined;
     readonly name: string;
-  }
+  },
 >({
   items: [items, setItems],
   tableName,
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Types.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Types.tsx
index 7e83531d3bd..3bc6b2fd0bc 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Types.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Types.tsx
@@ -26,8 +26,8 @@ export function FormatterTypes(): JSX.Element {
     onChange: handleChange,
   } = React.useContext(FormattersContext)!;
 
-  const [type, setType] = useRoutePart('type');
-  const indexType = types.indexOf(type as typeof types[number]);
+  const [type, setType] = useRoutePart<(typeof types)[number]>('type');
+  const indexType = types.indexOf(type as (typeof types)[number]);
 
   const resolvedType = type === 'formatter' ? 'formatters' : 'aggregators';
 
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts b/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
index 77e6b857859..48549e48e65 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
@@ -183,13 +183,13 @@ async function formatField(
                 cycleDetector
               ))
       : formatFieldValue
-      ? await fieldFormat(
-          field,
-          resource.get(field.name) as string | undefined,
-          undefined,
-          fieldFormatter
-        )
-      : (resource.get(field.name) as string | null) ?? undefined;
+        ? await fieldFormat(
+            field,
+            resource.get(field.name) as string | undefined,
+            undefined,
+            fieldFormatter
+          )
+        : ((resource.get(field.name) as string | null) ?? undefined);
   } else
     formatted = tryBest
       ? naiveFormatter(parentResource.specifyTable.name, parentResource.id)
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/index.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/index.tsx
index e0e1f37ddbd..9722fc132a2 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/index.tsx
@@ -109,12 +109,14 @@ function WrappedXmlEditor>({
   );
 }
 
-export type XmlEditorContext> =
-  | Omit & {
-      readonly xmlNode: XmlNode;
-      readonly syncer: Syncer>;
-      readonly parsed: GetOrSet>;
-    };
+export type XmlEditorContext> = Omit<
+  AppResourceTabProps,
+  'data'
+> & {
+  readonly xmlNode: XmlNode;
+  readonly syncer: Syncer>;
+  readonly parsed: GetOrSet>;
+};
 
 export function createXmlContext>(
   spec: SPEC
diff --git a/specifyweb/frontend/js_src/lib/components/Forms/BaseResourceView.tsx b/specifyweb/frontend/js_src/lib/components/Forms/BaseResourceView.tsx
index 3734b7ccc21..ead3aa7f5cd 100644
--- a/specifyweb/frontend/js_src/lib/components/Forms/BaseResourceView.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Forms/BaseResourceView.tsx
@@ -121,18 +121,18 @@ export function useResourceView({
     resource === undefined
       ? localized('')
       : resource.isNew()
-      ? formsText.newResourceTitle({ tableName: resource.specifyTable.label })
-      : resource.specifyTable.label;
+        ? formsText.newResourceTitle({ tableName: resource.specifyTable.label })
+        : resource.specifyTable.label;
   const title =
     formatted.length === 0
       ? formattedTableName
       : resource?.specifyTable.name &&
-        tableNamesToHide.has(resource.specifyTable.name)
-      ? formatted
-      : commonText.colonLine({
-          label: formattedTableName,
-          value: formatted,
-        });
+          tableNamesToHide.has(resource.specifyTable.name)
+        ? formatted
+        : commonText.colonLine({
+            label: formattedTableName,
+            value: formatted,
+          });
 
   const formRef = React.useRef(form);
   formRef.current = form;
@@ -207,7 +207,7 @@ export const FormContext = React.createContext<
       | ((
           newState: FormMetaType | ((oldMeta: FormMetaType) => FormMetaType)
         ) => void)
-      | undefined
+      | undefined,
   ]
 >([
   {
diff --git a/specifyweb/frontend/js_src/lib/components/Forms/DeleteBlocked.tsx b/specifyweb/frontend/js_src/lib/components/Forms/DeleteBlocked.tsx
index 5266c229bf2..ba96b907ff7 100644
--- a/specifyweb/frontend/js_src/lib/components/Forms/DeleteBlocked.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Forms/DeleteBlocked.tsx
@@ -167,12 +167,12 @@ function BlockerPreview({
             directRelationship.relatedTable.idField.name,
           ])
         : parentRelationship.otherSideName === undefined
-        ? undefined
-        : QueryFieldSpec.fromPath(table.name, [
-            parentRelationship.otherSideName,
-            directRelationship.name,
-            directRelationship.relatedTable.idField.name,
-          ]);
+          ? undefined
+          : QueryFieldSpec.fromPath(table.name, [
+              parentRelationship.otherSideName,
+              directRelationship.name,
+              directRelationship.relatedTable.idField.name,
+            ]);
 
     return (
       rawQueryField
diff --git a/specifyweb/frontend/js_src/lib/components/Forms/DeleteButton.tsx b/specifyweb/frontend/js_src/lib/components/Forms/DeleteButton.tsx
index f6706b4e45f..7ec918ea7b0 100644
--- a/specifyweb/frontend/js_src/lib/components/Forms/DeleteButton.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Forms/DeleteButton.tsx
@@ -56,7 +56,7 @@ export function DeleteButton({
    * button's resource can change often.
    */
   readonly deferred?: boolean;
-  readonly component?: typeof Button['Secondary'];
+  readonly component?: (typeof Button)['Secondary'];
   readonly onDeleted?: () => void;
   readonly isIcon?: boolean;
 }): JSX.Element {
diff --git a/specifyweb/frontend/js_src/lib/components/Forms/ShowResource.tsx b/specifyweb/frontend/js_src/lib/components/Forms/ShowResource.tsx
index 4d49e21c7db..e4b1e514261 100644
--- a/specifyweb/frontend/js_src/lib/components/Forms/ShowResource.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Forms/ShowResource.tsx
@@ -66,8 +66,8 @@ export function ShowResource({
     typeof recordSetId === 'number'
       ? 'recordSets'
       : interactionTables.has(resource.specifyTable.name)
-      ? 'interactions'
-      : 'dataEntry'
+        ? 'interactions'
+        : 'dataEntry'
   );
 
   const navigate = useNavigate();
@@ -109,7 +109,7 @@ export function ViewResourceById({
   const resource = React.useMemo(
     () =>
       typeof table === 'object'
-        ? record ?? new table.Resource({ id: numericId })
+        ? (record ?? new table.Resource({ id: numericId }))
         : undefined,
     [table, record, numericId]
   );
diff --git a/specifyweb/frontend/js_src/lib/components/Forms/dataObjFormatters.ts b/specifyweb/frontend/js_src/lib/components/Forms/dataObjFormatters.ts
index 97f9164daa8..cce72be87a1 100644
--- a/specifyweb/frontend/js_src/lib/components/Forms/dataObjFormatters.ts
+++ b/specifyweb/frontend/js_src/lib/components/Forms/dataObjFormatters.ts
@@ -208,11 +208,11 @@ export async function format(
   // Doesn't support switch fields that are in child objects
   const fields =
     typeof formatter.switchFieldName === 'string'
-      ? formatter.fields.find(
+      ? (formatter.fields.find(
           ({ value }) =>
             (value?.toString() ?? '') ===
             (resource.get(formatter.switchFieldName ?? '') ?? '').toString()
-        )?.fields ?? formatter.fields[0].fields
+        )?.fields ?? formatter.fields[0].fields)
       : formatter.fields[0].fields;
 
   const automaticFormatter = tryBest
@@ -230,7 +230,7 @@ export async function format(
     .every((value) => value === undefined || value === null || value === '');
 
   return isEmptyResource
-    ? automaticFormatter ?? undefined
+    ? (automaticFormatter ?? undefined)
     : Promise.all(
         fields.map(async (field) => formatField(field, resource, tryBest))
       ).then(
@@ -278,7 +278,7 @@ async function formatField(
         >
       ).then(async (value) =>
         formatter.length > 0 && typeof value === 'object'
-          ? (await format(value, formatter)) ?? ''
+          ? ((await format(value, formatter)) ?? '')
           : fieldFormat(
               field,
               value as string | undefined,
@@ -286,8 +286,8 @@ async function formatField(
             )
       )
     : tryBest
-    ? naiveFormatter(resource.specifyTable.name, resource.id)
-    : userText.noPermission();
+      ? naiveFormatter(resource.specifyTable.name, resource.id)
+      : userText.noPermission();
 
   return { formatted, separator: formatted ? separator : '' };
 }
diff --git a/specifyweb/frontend/js_src/lib/components/Forms/generateFormDefinition.ts b/specifyweb/frontend/js_src/lib/components/Forms/generateFormDefinition.ts
index 6bfb93f25e2..26f9963353b 100644
--- a/specifyweb/frontend/js_src/lib/components/Forms/generateFormDefinition.ts
+++ b/specifyweb/frontend/js_src/lib/components/Forms/generateFormDefinition.ts
@@ -253,27 +253,27 @@ function getFieldDefinition(
             printOnSave: false,
           }
         : typeof parser.pickListName === 'string'
-        ? {
-            type: 'ComboBox',
-            defaultValue: undefined,
-            pickList: parser.pickListName,
-          }
-        : field.type === 'text'
-        ? {
-            type: 'TextArea',
-            defaultValue: undefined,
-            rows: undefined,
-          }
-        : {
-            type: 'Text',
-            defaultValue: undefined,
-            min: parser.min,
-            max: parser.max,
-            step: parser.step,
-            minLength: parser.minLength,
-            maxLength: parser.maxLength,
-            whiteSpaceSensitive: parser.whiteSpaceSensitive,
-          }),
+          ? {
+              type: 'ComboBox',
+              defaultValue: undefined,
+              pickList: parser.pickListName,
+            }
+          : field.type === 'text'
+            ? {
+                type: 'TextArea',
+                defaultValue: undefined,
+                rows: undefined,
+              }
+            : {
+                type: 'Text',
+                defaultValue: undefined,
+                min: parser.min,
+                max: parser.max,
+                step: parser.step,
+                minLength: parser.minLength,
+                maxLength: parser.maxLength,
+                whiteSpaceSensitive: parser.whiteSpaceSensitive,
+              }),
     },
   };
 }
diff --git a/specifyweb/frontend/js_src/lib/components/Header/ChooseCollection.tsx b/specifyweb/frontend/js_src/lib/components/Header/ChooseCollection.tsx
index 6aa29481cc9..aa7411dd586 100644
--- a/specifyweb/frontend/js_src/lib/components/Header/ChooseCollection.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Header/ChooseCollection.tsx
@@ -44,7 +44,7 @@ export function CollectionPicker({
 }: {
   readonly collectionId: readonly [
     number | undefined,
-    (collectionId: number) => void
+    (collectionId: number) => void,
   ];
   readonly isReadOnly?: boolean;
 }): JSX.Element {
diff --git a/specifyweb/frontend/js_src/lib/components/Header/ExpressSearchHooks.tsx b/specifyweb/frontend/js_src/lib/components/Header/ExpressSearchHooks.tsx
index 035e4d29bf0..d083ec276f8 100644
--- a/specifyweb/frontend/js_src/lib/components/Header/ExpressSearchHooks.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Header/ExpressSearchHooks.tsx
@@ -49,12 +49,13 @@ export function usePrimarySearch(
   return primaryResults;
 }
 
-const relatedSearchesPromise = contextUnlockedPromise.then(async (entrypoint) =>
-  entrypoint === 'main'
-    ? ajax>('/context/available_related_searches.json', {
-        headers: { Accept: 'application/json' },
-      }).then(({ data }) => data)
-    : foreverFetch>()
+const relatedSearchesPromise = contextUnlockedPromise.then(
+  async (entrypoint) =>
+    entrypoint === 'main'
+      ? ajax>('/context/available_related_searches.json', {
+          headers: { Accept: 'application/json' },
+        }).then(({ data }) => data)
+      : foreverFetch>()
 );
 export const expressSearchFetchSize = 40;
 
diff --git a/specifyweb/frontend/js_src/lib/components/Header/index.tsx b/specifyweb/frontend/js_src/lib/components/Header/index.tsx
index a0660a71e8d..98923ab758c 100644
--- a/specifyweb/frontend/js_src/lib/components/Header/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Header/index.tsx
@@ -106,10 +106,10 @@ export function Header({
           position === 'left'
             ? 'dark:border-r'
             : position === 'top'
-            ? 'dark:border-b'
-            : position === 'right'
-            ? 'dark:border-l'
-            : 'dark:border-t'
+              ? 'dark:border-b'
+              : position === 'right'
+                ? 'dark:border-l'
+                : 'dark:border-t'
         }
         ${
           isMenuLight
@@ -215,8 +215,8 @@ export function MenuButton({
       isActive
         ? 'bg-brand-300 !text-white'
         : isSideBarDark
-        ? 'text-white'
-        : 'text-gray-700'
+          ? 'text-white'
+          : 'text-gray-700'
     }
     ${className.ariaHandled}
     ${extraProps?.className ?? ''}
diff --git a/specifyweb/frontend/js_src/lib/components/HomePage/TaxonTiles.tsx b/specifyweb/frontend/js_src/lib/components/HomePage/TaxonTiles.tsx
index de9b219acae..c124889b5f8 100644
--- a/specifyweb/frontend/js_src/lib/components/HomePage/TaxonTiles.tsx
+++ b/specifyweb/frontend/js_src/lib/components/HomePage/TaxonTiles.tsx
@@ -121,7 +121,7 @@ function useTreeData(): ReturnType | undefined {
               rankId: number,
               parentId: number,
               name: string,
-              count: number
+              count: number,
             ]
           >
         >('/barvis/taxon_bar/', {
diff --git a/specifyweb/frontend/js_src/lib/components/HomePage/taxonTileHelpers.ts b/specifyweb/frontend/js_src/lib/components/HomePage/taxonTileHelpers.ts
index dfecc567ace..edf1adcc0a3 100644
--- a/specifyweb/frontend/js_src/lib/components/HomePage/taxonTileHelpers.ts
+++ b/specifyweb/frontend/js_src/lib/components/HomePage/taxonTileHelpers.ts
@@ -177,7 +177,7 @@ const recurseTreeTiles = (
     ? [
         ...(node.parent === null
           ? []
-          : recurseTreeTiles(node.parent, genusRankId) ?? []),
+          : (recurseTreeTiles(node.parent, genusRankId) ?? [])),
         Array.isArray(node.children) ? node.data.name : undefined,
       ]
     : undefined;
diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/icons.ts b/specifyweb/frontend/js_src/lib/components/InitialContext/icons.ts
index 200ba611e29..899ab365f0e 100644
--- a/specifyweb/frontend/js_src/lib/components/InitialContext/icons.ts
+++ b/specifyweb/frontend/js_src/lib/components/InitialContext/icons.ts
@@ -69,5 +69,5 @@ function findIconInXml(
   const alias = iconNode?.getAttribute('alias');
   return typeof alias === 'string'
     ? findIconInXml(alias, xml, [...cycleDetect, icon])
-    : iconNode ?? undefined;
+    : (iconNode ?? undefined);
 }
diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/legacyUiLocalization.ts b/specifyweb/frontend/js_src/lib/components/InitialContext/legacyUiLocalization.ts
index 5b4c1707d7f..689d0153ac5 100644
--- a/specifyweb/frontend/js_src/lib/components/InitialContext/legacyUiLocalization.ts
+++ b/specifyweb/frontend/js_src/lib/components/InitialContext/legacyUiLocalization.ts
@@ -17,7 +17,7 @@ import { load } from './index';
 const bundleLanguages = ['en', 'ru', 'uk', 'pt'];
 const locale =
   bundleLanguages.find((language) => LANGUAGE.startsWith(language)) ?? 'en';
-const bundles = {} as Record;
+const bundles = {} as Record<(typeof bundleNames)[number], string>;
 
 const bundleNames = [
   'resources',
diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts b/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts
index c70f2292ded..83bf2d6c614 100644
--- a/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts
+++ b/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts
@@ -50,15 +50,15 @@ type TypeOf =
   DEFINITION['defaultValue'] extends string
     ? string
     : DEFINITION['defaultValue'] extends number
-    ? number
-    : boolean;
+      ? number
+      : boolean;
 
 type DefinitionOf =
   KEY extends keyof Definitions
     ? Definitions[KEY]
     : KEY extends keyof CollectionDefinitions
-    ? CollectionDefinitions[KEY]
-    : never;
+      ? CollectionDefinitions[KEY]
+      : never;
 
 export const getPref = (
   key: KEY
@@ -101,7 +101,7 @@ function parsePref(
       ? parsed.isValid
         ? parsed.parsed
         : defaultValue
-      : value ?? defaultValue
+      : (value ?? defaultValue)
   ) as boolean | number | string;
 }
 
@@ -295,7 +295,7 @@ export const remotePrefsDefinitions = f.store(
        *   isLegacy: true,
        * },
        */
-    } as const)
+    }) as const
 );
 
 /**
diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/treeRanks.ts b/specifyweb/frontend/js_src/lib/components/InitialContext/treeRanks.ts
index c006f7d1f81..b4183772ad8 100644
--- a/specifyweb/frontend/js_src/lib/components/InitialContext/treeRanks.ts
+++ b/specifyweb/frontend/js_src/lib/components/InitialContext/treeRanks.ts
@@ -100,7 +100,7 @@ export const treeRanksPromise = Promise.all([
 
 function getTreeScope(
   treeName: AnyTree['tableName']
-): keyof typeof schema['domainLevelIds'] | undefined {
+): keyof (typeof schema)['domainLevelIds'] | undefined {
   const treeRelationships = new Set(
     genericTables[`${treeName}TreeDef`].relationships.map(({ relatedTable }) =>
       relatedTable.name.toLowerCase()
@@ -149,16 +149,16 @@ export function getTreeDefinitionItems(
   return specificTreeDefinitions === undefined
     ? undefined
     : typeof treeDefinitionId === 'number'
-    ? specificTreeDefinitions
-        .find(({ definition }) => definition.id === treeDefinitionId)
-        ?.ranks.slice(includeRoot ? 0 : 1)
-    : specificTreeDefinitions.flatMap(({ ranks }) =>
-        ranks.slice(includeRoot ? 0 : 1)
-      );
+      ? specificTreeDefinitions
+          .find(({ definition }) => definition.id === treeDefinitionId)
+          ?.ranks.slice(includeRoot ? 0 : 1)
+      : specificTreeDefinitions.flatMap(({ ranks }) =>
+          ranks.slice(includeRoot ? 0 : 1)
+        );
 }
 
 export const strictGetTreeDefinitionItems = <
-  TREE_NAME extends AnyTree['tableName']
+  TREE_NAME extends AnyTree['tableName'],
 >(
   tableName: TREE_NAME,
   includeRoot: boolean,
diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx
index 8e73162dfad..e98fa14d3e3 100644
--- a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx
@@ -334,8 +334,8 @@ export function InteractionDialog({
               typeof itemCollection === 'object'
                 ? interactionsText.addItems()
                 : itemTable.name === 'Loan'
-                ? interactionsText.recordReturn({ table: itemTable.label })
-                : interactionsText.createRecord({ table: actionTable.name })
+                  ? interactionsText.recordReturn({ table: itemTable.label })
+                  : interactionsText.createRecord({ table: actionTable.name })
             }
             onClose={handleClose}
           >
diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionsDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionsDialog.tsx
index 36712b27590..53b7389acac 100644
--- a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionsDialog.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionsDialog.tsx
@@ -72,10 +72,10 @@ function Interactions({
                   table.name === 'LoanReturnPreparation'
                     ? `/specify/overlay/interactions/return-loan/`
                     : interactionsWithPrepTables.includes(
-                        (table as SpecifyTable).name
-                      )
-                    ? `/specify/overlay/interactions/create/${table.name}/`
-                    : getResourceViewUrl(table.name)
+                          (table as SpecifyTable).name
+                        )
+                      ? `/specify/overlay/interactions/create/${table.name}/`
+                      : getResourceViewUrl(table.name)
                 }
               >
                 
diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx
index d684113ee8e..0cbfc9866d5 100644
--- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx
@@ -129,8 +129,8 @@ export function PrepDialogRow({
                                   resource: new (loans.length === 1
                                     ? tables.Loan
                                     : gifts.length === 1
-                                    ? tables.Gift
-                                    : tables.ExchangeOut
+                                      ? tables.Gift
+                                      : tables.ExchangeOut
                                   ).Resource({
                                     id: [...loans, ...gifts, ...exchangeOuts][0]
                                       .id,
diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/helpers.ts b/specifyweb/frontend/js_src/lib/components/Interactions/helpers.ts
index 21ea5352abc..3fa6bb3ac4d 100644
--- a/specifyweb/frontend/js_src/lib/components/Interactions/helpers.ts
+++ b/specifyweb/frontend/js_src/lib/components/Interactions/helpers.ts
@@ -50,7 +50,7 @@ export type PreparationRow = readonly [
   amountLoaned: string | null,
   amountedGifted: string | null,
   amountExchanged: string | null,
-  amountAvailable: string
+  amountAvailable: string,
 ];
 
 export const getPrepsAvailableForLoanRs = async (
diff --git a/specifyweb/frontend/js_src/lib/components/Leaflet/addOns.ts b/specifyweb/frontend/js_src/lib/components/Leaflet/addOns.ts
index b1593b563fd..4e6ecf84802 100644
--- a/specifyweb/frontend/js_src/lib/components/Leaflet/addOns.ts
+++ b/specifyweb/frontend/js_src/lib/components/Leaflet/addOns.ts
@@ -77,7 +77,7 @@ const markerLayerName = [
   'polygonBoundary',
   'errorRadius',
 ] as const;
-export type MarkerLayerName = typeof markerLayerName[number];
+export type MarkerLayerName = (typeof markerLayerName)[number];
 const defaultMarkerGroupsState: RR = {
   marker: true,
   polygon: true,
@@ -143,7 +143,7 @@ export function addMarkersToMap(
       (groupName) =>
         [groupName, L.featureGroup.subGroup(cluster)] as readonly [
           MarkerLayerName,
-          L.FeatureGroup
+          L.FeatureGroup,
         ]
     )
   );
diff --git a/specifyweb/frontend/js_src/lib/components/Leaflet/localityRecordDataExtractor.ts b/specifyweb/frontend/js_src/lib/components/Leaflet/localityRecordDataExtractor.ts
index 71f28064367..32133106b45 100644
--- a/specifyweb/frontend/js_src/lib/components/Leaflet/localityRecordDataExtractor.ts
+++ b/specifyweb/frontend/js_src/lib/components/Leaflet/localityRecordDataExtractor.ts
@@ -62,7 +62,7 @@ type FilterFunction = (
   mappingPath: readonly [
     pastParts: MappingPath,
     currentPart: MappingPath,
-    nextParts: MappingPath
+    nextParts: MappingPath,
   ],
   resource: Collection | SpecifyResource
 ) => boolean;
@@ -182,7 +182,7 @@ async function recursiveResourceResolve(
 // eslint-disable-next-line functional/prefer-readonly-type
 export const parsedLocalityPinFields: [
   RA | undefined,
-  RA | undefined
+  RA | undefined,
 ] = [undefined, undefined];
 export const parseLocalityPinFields = (
   quickFetch: boolean
diff --git a/specifyweb/frontend/js_src/lib/components/Merging/CompareSubView.tsx b/specifyweb/frontend/js_src/lib/components/Merging/CompareSubView.tsx
index 8d8d46458cd..b79ada12f16 100644
--- a/specifyweb/frontend/js_src/lib/components/Merging/CompareSubView.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Merging/CompareSubView.tsx
@@ -327,7 +327,7 @@ function useChildren(
         records?.reduce<
           readonly [
             RR>,
-            RA
+            RA,
           ]
         >(
           ([mappings, mergedRecords], record) => {
diff --git a/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts b/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts
index f9278bdae32..427a4958d3a 100644
--- a/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts
+++ b/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts
@@ -180,8 +180,8 @@ export const resourceToGeneric = (
         Array.isArray(value)
           ? value.map((value) => resourceToGeneric(value, strong))
           : typeof value === 'object' && value !== null
-          ? resourceToGeneric(value, strong)
-          : value,
+            ? resourceToGeneric(value, strong)
+            : value,
       ])
   ) as SerializedResource;
 };
@@ -273,9 +273,9 @@ const genericPostProcessors: RA = [
       Object.entries(merged).map(([fieldName, value]) => [
         fieldName,
         getMax.has(fieldName)
-          ? resources
+          ? (resources
               .map((resource) => resource[fieldName])
-              .sort(sortFunction(f.id, true))[0] ?? value
+              .sort(sortFunction(f.id, true))[0] ?? value)
           : value,
       ])
     ),
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/AutoComplete.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/AutoComplete.tsx
index 2b5433f8dec..3bbd1a6bea0 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/AutoComplete.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/AutoComplete.tsx
@@ -39,8 +39,8 @@ const getScrollParent = (node: Element | undefined): Element =>
   node === undefined
     ? document.body
     : node.scrollHeight > node.clientHeight
-    ? node
-    : getScrollParent(node.parentElement ?? undefined);
+      ? node
+      : getScrollParent(node.parentElement ?? undefined);
 
 const optionClassName = (isActive: boolean, isSelected: boolean) => `
   p-0.5 active:bg-brand-100 dark:active:bg-brand-500
@@ -130,35 +130,35 @@ export function AutoComplete({
       pendingValue.length === 0
         ? newResults
         : shouldFilterItems
-        ? newResults.filter(({ label, searchValue }) => {
-            let searchString =
-              typeof label === 'string' ? label : searchValue ?? '';
-            let searchQuery = pendingValue;
-
-            if (
-              searchAlgorithm === 'contains' ||
-              searchAlgorithm === 'startsWith'
-            ) {
-              searchString = searchString.toLowerCase();
-              searchQuery = pendingValue.toLowerCase();
-            }
-
-            if (
-              searchAlgorithm === 'contains' ||
-              searchAlgorithm === 'containsCaseSensitive'
-            ) {
-              if (searchString.includes(searchQuery)) return true;
-            } else if (searchString.startsWith(searchQuery)) return true;
-
-            return (
-              typeof searchValue === 'string' &&
-              compareStrings(
-                searchValue.slice(0, pendingValue.length),
-                pendingValue
-              ) === 0
-            );
-          })
-        : newResults,
+          ? newResults.filter(({ label, searchValue }) => {
+              let searchString =
+                typeof label === 'string' ? label : (searchValue ?? '');
+              let searchQuery = pendingValue;
+
+              if (
+                searchAlgorithm === 'contains' ||
+                searchAlgorithm === 'startsWith'
+              ) {
+                searchString = searchString.toLowerCase();
+                searchQuery = pendingValue.toLowerCase();
+              }
+
+              if (
+                searchAlgorithm === 'contains' ||
+                searchAlgorithm === 'containsCaseSensitive'
+              ) {
+                if (searchString.includes(searchQuery)) return true;
+              } else if (searchString.startsWith(searchQuery)) return true;
+
+              return (
+                typeof searchValue === 'string' &&
+                compareStrings(
+                  searchValue.slice(0, pendingValue.length),
+                  pendingValue
+                ) === 0
+              );
+            })
+          : newResults,
     [shouldFilterItems, searchAlgorithm]
   );
 
@@ -200,8 +200,7 @@ export function AutoComplete({
         .then((items) => updateItems(items, value))
         .catch(softFail)
         .finally(handleLoaded);
-    },
-    delay),
+    }, delay),
     []
   );
 
@@ -237,7 +236,7 @@ export function AutoComplete({
    * thus the filtered list of items has only one item.
    */
   const ignoreFilter = currentValue === pendingValue;
-  const itemSource = ignoreFilter ? results ?? [] : filteredItems;
+  const itemSource = ignoreFilter ? (results ?? []) : filteredItems;
 
   const pendingItem = results?.find(
     ({ label, searchValue }) => (searchValue ?? label) === pendingValue
@@ -252,7 +251,7 @@ export function AutoComplete({
   function handleChanged(item: AutoCompleteItem): void {
     handleChange(item);
     const value =
-      typeof item.label === 'string' ? item.label : item.searchValue ?? '';
+      typeof item.label === 'string' ? item.label : (item.searchValue ?? '');
     setPendingValue(value);
     if (typeof pendingValueRef === 'object') pendingValueRef.current = value;
   }
@@ -403,8 +402,8 @@ export function AutoComplete({
           typeof item === 'string'
             ? item
             : typeof item?.label === 'string'
-            ? item.label
-            : item?.searchValue ?? ''
+              ? item.label
+              : (item?.searchValue ?? '')
         }
         ref={forwardChildRef}
         onBlur={withHandleBlur(inputProps?.onBlur).onBlur}
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/Dialog.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/Dialog.tsx
index ccf642a3939..1b51cef1895 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/Dialog.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/Dialog.tsx
@@ -437,10 +437,10 @@ export function Dialog({
           reduceTransparency || highContrast || specialMode === 'noGradient'
             ? dialogClassNames.solidBackground
             : transparentDialog && modal
-            ? supportsBackdropBlur
-              ? dialogClassNames.transparentBackground
-              : dialogClassNames.legacyTransparentBackground
-            : dialogClassNames.gradientBackground
+              ? supportsBackdropBlur
+                ? dialogClassNames.transparentBackground
+                : dialogClassNames.legacyTransparentBackground
+              : dialogClassNames.gradientBackground
         }
       `}
       closeTimeoutMS={transitionDuration === 0 ? undefined : transitionDuration}
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/GenericSortedDataViewer.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/GenericSortedDataViewer.tsx
index b8b60e9e0ad..05a242af1b2 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/GenericSortedDataViewer.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/GenericSortedDataViewer.tsx
@@ -9,7 +9,7 @@ import type {
 } from '../SchemaViewer/helpers';
 
 export function GenericSortedDataViewer<
-  DATA extends SchemaViewerRow>
+  DATA extends SchemaViewerRow>,
 >({
   headers,
   data,
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/Paginator.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/Paginator.tsx
index 79e15f6c786..800b7e30a2e 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/Paginator.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/Paginator.tsx
@@ -17,7 +17,7 @@ export type Paginators = 'queryBuilder' | 'recordSets';
 
 export function usePaginator(
   cacheName: Paginators,
-  defaultRowsPerPage: typeof pageSizes[number] = 10
+  defaultRowsPerPage: (typeof pageSizes)[number] = 10
 ): {
   readonly paginator: (totalCount: number | undefined) => JSX.Element;
   readonly currentPage: GetSet;
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/ResourceLink.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/ResourceLink.tsx
index 402fb4309fc..cd0336ff8b2 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/ResourceLink.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/ResourceLink.tsx
@@ -19,7 +19,7 @@ import type { ResourceView } from '../Forms/ResourceView';
 export const IsNotReadOnly = React.createContext(false);
 IsNotReadOnly.displayName = 'IsNotReadOnly';
 
-export function ResourceLink({
+export function ResourceLink({
   resource,
   component: Component,
   props: rawProps,
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/Sorting.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/Sorting.tsx
index 65c6d66657b..8cad781fabf 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/Sorting.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/Sorting.tsx
@@ -50,7 +50,7 @@ export function useSortConfig(
   applySortConfig: (
     array: RA,
     mapper: (item: T) => boolean | number | string | null | undefined
-  ) => RA
+  ) => RA,
 ] {
   const defaultValue = React.useMemo(
     () => ({ sortField: defaultField, ascending }),
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/SvgIcon.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/SvgIcon.tsx
index 87251c112cf..c2a8d834d94 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/SvgIcon.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/SvgIcon.tsx
@@ -110,8 +110,8 @@ function getShortName(rawName: keyof Tables): string {
     rawName.endsWith('Attachment') && rawName !== 'Attachment'
       ? rawName.slice(0, -'Attachment'.length)
       : rawName.startsWith('Sp')
-      ? rawName.slice(2)
-      : rawName;
+        ? rawName.slice(2)
+        : rawName;
   const capitalLetters = name.replaceAll(/[^A-Z]/gu, '');
   return capitalLetters.length > 1
     ? capitalLetters.slice(0, 3)
diff --git a/specifyweb/frontend/js_src/lib/components/Molecules/TableIcon.tsx b/specifyweb/frontend/js_src/lib/components/Molecules/TableIcon.tsx
index f6bda0cde81..fb0ca381864 100644
--- a/specifyweb/frontend/js_src/lib/components/Molecules/TableIcon.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Molecules/TableIcon.tsx
@@ -63,8 +63,8 @@ export function TableIcon({
     label === false
       ? undefined
       : typeof label === 'string'
-      ? label
-      : table?.label ?? camelToHuman(name);
+        ? label
+        : (table?.label ?? camelToHuman(name));
   if (tableName === undefined) {
     const tableIconSource = getIcon(name);
     // Display a legacy Specify 6 icon
diff --git a/specifyweb/frontend/js_src/lib/components/Permissions/FormatError.tsx b/specifyweb/frontend/js_src/lib/components/Permissions/FormatError.tsx
index 5fb2cafe57c..7792151a258 100644
--- a/specifyweb/frontend/js_src/lib/components/Permissions/FormatError.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Permissions/FormatError.tsx
@@ -76,8 +76,8 @@ export function FormatPermissionError({
                     index === 0
                       ? 'rounded-l'
                       : index + 1 === length
-                      ? 'rounded-r'
-                      : ''
+                        ? 'rounded-r'
+                        : ''
                   }
                 `}
                 key={index}
@@ -98,7 +98,7 @@ export function FormatPermissionError({
                   collectionId={
                     institutionPermissions.has(resource)
                       ? undefined
-                      : collectionid ?? undefined
+                      : (collectionid ?? undefined)
                   }
                 />,
                 ,
diff --git a/specifyweb/frontend/js_src/lib/components/Permissions/PermissionDenied.tsx b/specifyweb/frontend/js_src/lib/components/Permissions/PermissionDenied.tsx
index b442b45a9e5..57d1c54a87d 100644
--- a/specifyweb/frontend/js_src/lib/components/Permissions/PermissionDenied.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Permissions/PermissionDenied.tsx
@@ -41,7 +41,7 @@ export function ToolPermissionDenied({
   action,
 }: {
   readonly tool: keyof ReturnType;
-  readonly action: typeof tableActions[number];
+  readonly action: (typeof tableActions)[number];
 }): JSX.Element {
   return (
     ;
-  readonly action: typeof tableActions[number];
+  readonly action: (typeof tableActions)[number];
   readonly children: React.ReactNode;
 }): JSX.Element {
   return hasToolPermission(tool, action) ? (
@@ -81,7 +81,7 @@ export function ProtectedTool({
 }
 
 export function PermissionDenied<
-  RESOURCE extends keyof ReturnType[number]
+  RESOURCE extends keyof ReturnType[number],
 >({
   resource,
   action,
@@ -111,7 +111,7 @@ export function PermissionDenied<
 }
 
 export function ProtectedAction<
-  RESOURCE extends keyof ReturnType[number]
+  RESOURCE extends keyof ReturnType[number],
 >({
   resource,
   action,
@@ -134,7 +134,7 @@ export function TablePermissionDenied({
   action,
 }: {
   readonly tableName: keyof Tables;
-  readonly action: typeof tableActions[number];
+  readonly action: (typeof tableActions)[number];
 }): JSX.Element {
   return (
     [number]
+  RESOURCE extends keyof ReturnType[number],
 >(
   resource: RESOURCE,
   action: keyof ReturnType[number][RESOURCE],
@@ -50,12 +50,12 @@ export const hasPermission = <
   resource === '%' && action === '%'
     ? userInformation.isadmin
     : getOperationPermissions()[collectionId][resource][action]
-    ? true
-    : f.log(`No permission to ${action.toString()} ${resource}`) ?? false;
+      ? true
+      : (f.log(`No permission to ${action.toString()} ${resource}`) ?? false);
 
 export const hasToolPermission = (
   tool: keyof ReturnType,
-  action: typeof tableActions[number],
+  action: (typeof tableActions)[number],
   collectionId = schema.domainLevelIds.collection
 ): boolean =>
   (toolDefinitions()[tool].tables as RA).every((tableName) =>
@@ -64,7 +64,7 @@ export const hasToolPermission = (
 
 export const hasTreeAccess = (
   treeName: AnyTree['tableName'],
-  action: typeof tableActions[number],
+  action: (typeof tableActions)[number],
   collectionId = schema.domainLevelIds.collection
 ): boolean =>
   hasTablePermission(treeName, action, collectionId) &&
@@ -72,7 +72,7 @@ export const hasTreeAccess = (
   hasTablePermission(`${treeName}TreeDefItem`, action, collectionId);
 
 export const hasDerivedPermission = <
-  RESOURCE extends keyof ReturnType[number]
+  RESOURCE extends keyof ReturnType[number],
 >(
   resource: RESOURCE,
   action: keyof ReturnType[number][RESOURCE],
@@ -80,12 +80,12 @@ export const hasDerivedPermission = <
 ): boolean =>
   getDerivedPermissions()[collectionId][resource][action]
     ? true
-    : f.log(`No permission to ${action.toString()} ${resource}`) ?? false;
+    : (f.log(`No permission to ${action.toString()} ${resource}`) ?? false);
 
 /** Check if user has a given permission for each table in a mapping path */
 export const hasPathPermission = (
   mappingPath: RA,
-  action: typeof tableActions[number],
+  action: (typeof tableActions)[number],
   collectionId = schema.domainLevelIds.collection
 ): boolean =>
   mappingPath
diff --git a/specifyweb/frontend/js_src/lib/components/Permissions/index.ts b/specifyweb/frontend/js_src/lib/components/Permissions/index.ts
index 4b17cc6eda9..d1e7e50bcd4 100644
--- a/specifyweb/frontend/js_src/lib/components/Permissions/index.ts
+++ b/specifyweb/frontend/js_src/lib/components/Permissions/index.ts
@@ -27,12 +27,12 @@ let operationPermissions: RR<
   number,
   RR> & {
     readonly [RESOURCE in keyof typeof frontEndPermissions]: RR<
-      typeof frontEndPermissions[RESOURCE][number],
+      (typeof frontEndPermissions)[RESOURCE][number],
       boolean
     >;
   } & {
     readonly [RESOURCE in keyof typeof operationPolicies]: RR<
-      typeof operationPolicies[RESOURCE][number],
+      (typeof operationPolicies)[RESOURCE][number],
       boolean
     >;
   }
@@ -42,7 +42,7 @@ let tablePermissions: RR<
   number,
   {
     readonly [TABLE_NAME in keyof Tables as `${typeof tablePermissionsPrefix}${Lowercase}`]: RR<
-      typeof tableActions[number],
+      (typeof tableActions)[number],
       boolean
     >;
   }
@@ -52,7 +52,7 @@ let derivedPermissions: RR<
   number,
   {
     readonly [RESOURCE in keyof typeof derivedPolicies]: RR<
-      typeof derivedPolicies[RESOURCE][number],
+      (typeof derivedPolicies)[RESOURCE][number],
       boolean
     >;
   }
@@ -188,7 +188,7 @@ export const queryUserPermissions = async (
 
 const calculateDerivedPermissions = (
   items: RA
-): typeof derivedPermissions[number] =>
+): (typeof derivedPermissions)[number] =>
   Object.fromEntries(
     indexQueryItems(
       items
@@ -214,7 +214,7 @@ const calculateDerivedPermissions = (
           })
         )
     )
-  ) as typeof derivedPermissions[number];
+  ) as (typeof derivedPermissions)[number];
 
 const indexQueryItems = (
   query: RA
@@ -274,9 +274,9 @@ export const fetchUserPermissions = async (
                     ).map(Object.fromEntries);
                     return {
                       operations:
-                        operations as unknown as typeof operationPermissions[number],
+                        operations as unknown as (typeof operationPermissions)[number],
                       tables:
-                        tables as unknown as typeof tablePermissions[number],
+                        tables as unknown as (typeof tablePermissions)[number],
                       derived: calculateDerivedPermissions(query),
                     };
                   }
diff --git a/specifyweb/frontend/js_src/lib/components/PickLists/FieldsPickList.tsx b/specifyweb/frontend/js_src/lib/components/PickLists/FieldsPickList.tsx
index b3fca618dcb..d6090850aa6 100644
--- a/specifyweb/frontend/js_src/lib/components/PickLists/FieldsPickList.tsx
+++ b/specifyweb/frontend/js_src/lib/components/PickLists/FieldsPickList.tsx
@@ -14,12 +14,12 @@ export function FieldsPickList(props: DefaultComboBoxProps): JSX.Element {
   const getItems = React.useCallback(
     () =>
       props.resource?.get('type') === PickListTypes.FIELDS
-        ? getTable(props.resource.get('tableName') ?? '')?.fields.map(
+        ? (getTable(props.resource.get('tableName') ?? '')?.fields.map(
             (field) => ({
               value: field.name,
               title: field.label,
             })
-          ) ?? []
+          ) ?? [])
         : [],
     [props.resource]
   );
diff --git a/specifyweb/frontend/js_src/lib/components/PickLists/TreeLevelPickList.tsx b/specifyweb/frontend/js_src/lib/components/PickLists/TreeLevelPickList.tsx
index b5b44999d62..7da5712d9db 100644
--- a/specifyweb/frontend/js_src/lib/components/PickLists/TreeLevelPickList.tsx
+++ b/specifyweb/frontend/js_src/lib/components/PickLists/TreeLevelPickList.tsx
@@ -115,14 +115,14 @@ export function TreeLevelComboBox(props: DefaultComboBoxProps): JSX.Element {
                   idFromUrl(treeDefinitionItem.get('treeDef'))!
                 )
               : typeof resource.get('definitionItem') === 'string' &&
-                !resource.isNew()
-              ? ([
-                  await fetchTreeRoot(
-                    resource.specifyTable.name,
-                    idFromUrl(resource.get('definition'))!
-                  ),
-                ] as RA>>)
-              : undefined
+                  !resource.isNew()
+                ? ([
+                    await fetchTreeRoot(
+                      resource.specifyTable.name,
+                      idFromUrl(resource.get('definition'))!
+                    ),
+                  ] as RA>>)
+                : undefined
           )
           .then((items) => {
             if (destructorCalled) return undefined;
diff --git a/specifyweb/frontend/js_src/lib/components/PickLists/fetch.ts b/specifyweb/frontend/js_src/lib/components/PickLists/fetch.ts
index daabeb9ae74..a5ce74f680a 100644
--- a/specifyweb/frontend/js_src/lib/components/PickLists/fetch.ts
+++ b/specifyweb/frontend/js_src/lib/components/PickLists/fetch.ts
@@ -84,7 +84,7 @@ async function fetchPickListItems(
 
   const limit = Math.max(
     0,
-    pickList.get('readOnly') ? pickList.get('sizeLimit') ?? 0 : 0
+    pickList.get('readOnly') ? (pickList.get('sizeLimit') ?? 0) : 0
   );
 
   if (type === PickListTypes.TABLE)
@@ -180,8 +180,8 @@ export function getPickListItems(pickList: SpecifyResource): RA<{
     pickList.get('sortType') === PickListSortType.TITLE_SORT
       ? Array.from(items).sort(sortFunction(({ title }) => title))
       : pickList.get('sortType') === PickListSortType.ORDINAL_SORT
-      ? Array.from(items).sort(sortFunction(({ ordinal }) => ordinal))
-      : items
+        ? Array.from(items).sort(sortFunction(({ ordinal }) => ordinal))
+        : items
   ).map(({ value, title }) => ({
     value: value ?? title,
     title: title ?? value,
diff --git a/specifyweb/frontend/js_src/lib/components/PickLists/index.tsx b/specifyweb/frontend/js_src/lib/components/PickLists/index.tsx
index d7d1e2d3152..7bc3dbb07ea 100644
--- a/specifyweb/frontend/js_src/lib/components/PickLists/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/PickLists/index.tsx
@@ -93,8 +93,8 @@ export function PickListComboBox({
   const value = React.useMemo(
     () =>
       typeof rawValue === 'object'
-        ? (rawValue as unknown as SpecifyResource)?.url() ?? null
-        : (rawValue as number | string | undefined)?.toString() ?? null,
+        ? ((rawValue as unknown as SpecifyResource)?.url() ?? null)
+        : ((rawValue as number | string | undefined)?.toString() ?? null),
     [rawValue]
   );
 
@@ -104,8 +104,8 @@ export function PickListComboBox({
         value === '' && parser.required !== true
           ? null
           : parser?.type === 'number'
-          ? f.parseInt(value) ?? null
-          : value
+            ? (f.parseInt(value) ?? null)
+            : value
       ),
     [rawUpdateValue, parser]
   );
@@ -173,8 +173,8 @@ export function PickListComboBox({
             newValue === ''
               ? updateValue('')
               : items.some(({ value }) => value === newValue)
-              ? updateValue(newValue)
-              : undefined
+                ? updateValue(newValue)
+                : undefined
           }
         >
           {isExistingValue ? (
diff --git a/specifyweb/frontend/js_src/lib/components/Preferences/BasePreferences.tsx b/specifyweb/frontend/js_src/lib/components/Preferences/BasePreferences.tsx
index 258cc711421..bc308aaabd7 100644
--- a/specifyweb/frontend/js_src/lib/components/Preferences/BasePreferences.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Preferences/BasePreferences.tsx
@@ -155,7 +155,7 @@ export class BasePreferences {
       ? string & keyof DEFINITIONS[CATEGORY]['subCategories']
       : never,
     ITEM extends string &
-      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items']
+      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items'],
   >(
     category: CATEGORY,
     subcategory: SUBCATEGORY,
@@ -181,7 +181,7 @@ export class BasePreferences {
       ? string & keyof DEFINITIONS[CATEGORY]['subCategories']
       : never,
     ITEM extends string &
-      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items']
+      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items'],
   >(
     category: CATEGORY,
     subcategory: SUBCATEGORY,
@@ -203,7 +203,7 @@ export class BasePreferences {
       ? string & keyof DEFINITIONS[CATEGORY]['subCategories']
       : never,
     ITEM extends string &
-      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items']
+      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items'],
   >(
     category: CATEGORY,
     subcategory: SUBCATEGORY,
@@ -357,7 +357,7 @@ export class BasePreferences {
       ? string & keyof DEFINITIONS[CATEGORY]['subCategories']
       : never,
     ITEM extends string &
-      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items']
+      keyof DEFINITIONS[CATEGORY]['subCategories'][SUBCATEGORY]['items'],
   >(
     category: CATEGORY,
     subcategory: SUBCATEGORY,
diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/AuditLogFormatter.tsx b/specifyweb/frontend/js_src/lib/components/QueryBuilder/AuditLogFormatter.tsx
index 930e50bbad8..0146d79444a 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/AuditLogFormatter.tsx
+++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/AuditLogFormatter.tsx
@@ -81,19 +81,19 @@ export function getAuditRecordFormatter(
           if (fields[index]?.name === 'fieldName') {
             const tableId = row[tableIdIndex];
             return typeof tableId === 'number'
-              ? getTableById(tableId).getField(stringValue)?.label ??
-                  stringValue
-              : tableId ?? '';
+              ? (getTableById(tableId).getField(stringValue)?.label ??
+                  stringValue)
+              : (tableId ?? '');
           } else if (fields[index]?.name === 'recordId') {
             const tableId = row[tableIdIndex];
             return typeof tableId === 'number'
               ? resourceToLink(getTableById(tableId), Number(value))
-              : tableId ?? '';
+              : (tableId ?? '');
           } else if (fields[index]?.name === 'parentRecordId') {
             const tableId = row[parentTableIdIndex];
             return typeof tableId === 'number'
               ? resourceToLink(getTableById(tableId), Number(value))
-              : tableId ?? '';
+              : (tableId ?? '');
           } else
             return fieldFormat(
               fields[index],
diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/Context.tsx b/specifyweb/frontend/js_src/lib/components/QueryBuilder/Context.tsx
index 79fef18ccc0..664ff877ef3 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/Context.tsx
+++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/Context.tsx
@@ -21,8 +21,8 @@ export function useQueryViewPref(queryId: number): GetSet {
   const isBasic = viewCollectionPref.basicView.includes(queryId)
     ? true
     : viewCollectionPref.detailedView.includes(queryId)
-    ? false
-    : isDefaultBasicViewPref;
+      ? false
+      : isDefaultBasicViewPref;
 
   return [
     isBasic,
diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/Export.tsx b/specifyweb/frontend/js_src/lib/components/QueryBuilder/Export.tsx
index 7be4dc5c3bf..d93d71b8941 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/Export.tsx
+++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/Export.tsx
@@ -156,24 +156,25 @@ export function QueryExportButtons({
           {queryText.missingCoordinatesForKmlDescription()}
         
       ) : undefined}
-      {containsResults && hasPermission('/querybuilder/query', 'export_csv') && (
-         {
-            selectedRows.size === 0
-              ? doQueryExport(
-                  '/stored_query/exportcsv/',
-                  separator,
-                  utf8Bom,
-                  undefined
-                )
-              : exportCsvSelected().catch(softFail);
-          }}
-        >
-          {queryText.createCsv()}
-        
-      )}
+      {containsResults &&
+        hasPermission('/querybuilder/query', 'export_csv') && (
+           {
+              selectedRows.size === 0
+                ? doQueryExport(
+                    '/stored_query/exportcsv/',
+                    separator,
+                    utf8Bom,
+                    undefined
+                  )
+                : exportCsvSelected().catch(softFail);
+            }}
+          >
+            {queryText.createCsv()}
+          
+        )}
       {canUseKml && (
         
       
   );
 }
diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/fieldSpec.ts b/specifyweb/frontend/js_src/lib/components/QueryBuilder/fieldSpec.ts
index cb34c3f8dca..1a0e16fcc3f 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/fieldSpec.ts
+++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/fieldSpec.ts
@@ -108,22 +108,22 @@ export class QueryFieldSpec {
       field === undefined
         ? undefined
         : overrideIsRelationship
-        ? field.name === 'fullName' || field.isRelationship
-          ? undefined
-          : field === field.table.idField
-          ? /*
-             * Back-end expects "taxonId" and other id fields for tree ranks
-             * to be called "ID" (case-sensitive)
-             */
-            'ID'
-          : field.name === 'author'
-          ? 'Author'
-          : field.name
-        : `${field.name}${
-            typeof this.datePart === 'string' && this.datePart !== 'fullDate'
-              ? `Numeric${capitalize(this.datePart)}`
-              : ''
-          }`,
+          ? field.name === 'fullName' || field.isRelationship
+            ? undefined
+            : field === field.table.idField
+              ? /*
+                 * Back-end expects "taxonId" and other id fields for tree ranks
+                 * to be called "ID" (case-sensitive)
+                 */
+                'ID'
+              : field.name === 'author'
+                ? 'Author'
+                : field.name
+          : `${field.name}${
+              typeof this.datePart === 'string' && this.datePart !== 'fullDate'
+                ? `Numeric${capitalize(this.datePart)}`
+                : ''
+            }`,
     ]).join(' ');
 
     const tableList = this.makeTableList();
@@ -162,12 +162,12 @@ export class QueryFieldSpec {
           ? relationshipIsToMany(field)
             ? formatToManyIndex(1)
             : isTreeTable(field.relatedTable.name)
-            ? formatTreeRank(
-                index + 1 === length
-                  ? this.treeRank ?? anyTreeRank
-                  : anyTreeRank
-              )
-            : undefined
+              ? formatTreeRank(
+                  index + 1 === length
+                    ? (this.treeRank ?? anyTreeRank)
+                    : anyTreeRank
+                )
+              : undefined
           : undefined,
       ])
     );
@@ -307,16 +307,16 @@ export class QueryFieldSpec {
         typeof parsedField === 'object'
           ? parts.slice(0, -1).join(' ') || anyTreeRank
           : typeof field === 'object'
-          ? anyTreeRank
-          : fieldName || anyTreeRank;
+            ? anyTreeRank
+            : fieldName || anyTreeRank;
       fieldSpec.joinPath = filterArray([
         ...fieldSpec.joinPath,
         field === undefined
-          ? parsedField ??
+          ? (parsedField ??
             // If no field provided, use fullName
             (fieldSpec.treeRank === anyTreeRank
               ? undefined
-              : fieldSpec.table.strictGetLiteralField('fullName'))
+              : fieldSpec.table.strictGetLiteralField('fullName')))
           : undefined,
       ]);
     }
@@ -327,7 +327,7 @@ export class QueryFieldSpec {
         ? resolveParser(newField, { datePart: fieldSpec.datePart })
         : {};
     fieldSpec.datePart =
-      newField?.isTemporal() === true ? datePart ?? 'fullDate' : undefined;
+      newField?.isTemporal() === true ? (datePart ?? 'fullDate') : undefined;
 
     return fieldSpec;
   }
diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/fromTree.ts b/specifyweb/frontend/js_src/lib/components/QueryBuilder/fromTree.ts
index ab1a0d0fb68..c46c6da6a9b 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/fromTree.ts
+++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/fromTree.ts
@@ -217,9 +217,8 @@ export async function queryFromTree(
     tables.CollectionObject
   );
 
-  const rank: SpecifyResource = await node.rgetPromise(
-    'definitionItem'
-  );
+  const rank: SpecifyResource =
+    await node.rgetPromise('definitionItem');
   query.set(
     'fields',
     await defaultFields[tree.name](
diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/helpers.ts b/specifyweb/frontend/js_src/lib/components/QueryBuilder/helpers.ts
index a563da3ca7c..e842721fbf2 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/helpers.ts
+++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/helpers.ts
@@ -85,7 +85,7 @@ export function parseQueryFields(
                 .map((parsed) =>
                   parsed?.isValid
                     ? (parsed.parsed as string)
-                    : field.startValue ?? ''
+                    : (field.startValue ?? '')
                 )
                 .join(',')
             : field.startValue;
@@ -164,8 +164,8 @@ export const augmentQueryFields = (
   isDistinct
     ? fields
     : baseTableName === 'SpAuditLog'
-    ? addQueryFields(fields, auditLogMappingPaths, true)
-    : addLocalityFields(baseTableName, fields);
+      ? addQueryFields(fields, auditLogMappingPaths, true)
+      : addLocalityFields(baseTableName, fields);
 
 /**
  * It is expected by QueryResultsWrapper that this function does not change
@@ -220,7 +220,7 @@ const addQueryFields = (
               isStrict: false,
             },
           ],
-        } as const)
+        }) as const
     ),
 ];
 
@@ -336,7 +336,7 @@ export const unParseQueryFields = (
                */
               isDisplay: commonData.isDisplay && index === 0,
               // REFACTOR: add missing nullable fields here
-            } as unknown as SerializedResource)
+            }) as unknown as SerializedResource
         );
     }
   );
diff --git a/specifyweb/frontend/js_src/lib/components/QueryComboBox/helpers.ts b/specifyweb/frontend/js_src/lib/components/QueryComboBox/helpers.ts
index 3fb5bb0a27a..5b5d8f78d29 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryComboBox/helpers.ts
+++ b/specifyweb/frontend/js_src/lib/components/QueryComboBox/helpers.ts
@@ -190,8 +190,8 @@ export const getRelatedCollectionId = (
   (fieldName === 'rightSide'
     ? left
     : fieldName === 'leftSide'
-    ? right
-    : undefined
+      ? right
+      : undefined
   )?.find(
     ({ id }) =>
       id ===
diff --git a/specifyweb/frontend/js_src/lib/components/QueryComboBox/index.tsx b/specifyweb/frontend/js_src/lib/components/QueryComboBox/index.tsx
index 9b8afe496bb..91c764d589d 100644
--- a/specifyweb/frontend/js_src/lib/components/QueryComboBox/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/QueryComboBox/index.tsx
@@ -242,18 +242,19 @@ export function QueryComboBox({
     state.type === 'ViewResourceState' || state.type === 'AccessDeniedState'
       ? setState({ type: 'MainState' })
       : typeof relatedCollectionId === 'number' &&
-        !userInformation.availableCollections.some(
-          ({ id }) => id === relatedCollectionId
-        )
-      ? loading(
-          fetchResource('Collection', relatedCollectionId).then((collection) =>
-            setState({
-              type: 'AccessDeniedState',
-              collectionName: collection?.collectionName ?? '',
-            })
+          !userInformation.availableCollections.some(
+            ({ id }) => id === relatedCollectionId
           )
-        )
-      : setState({ type: 'ViewResourceState', isReadOnly });
+        ? loading(
+            fetchResource('Collection', relatedCollectionId).then(
+              (collection) =>
+                setState({
+                  type: 'AccessDeniedState',
+                  collectionName: collection?.collectionName ?? '',
+                })
+            )
+          )
+        : setState({ type: 'ViewResourceState', isReadOnly });
 
   const subViewRelationship = React.useContext(SubViewContext)?.relationship;
   const pendingValueRef = React.useRef('');
@@ -522,23 +523,23 @@ export function QueryComboBox({
                                       value: startValue,
                                     }
                                   : fieldName === 'nodeNumber'
-                                  ? {
-                                      field: 'nodeNumber',
-                                      operation: 'between',
-                                      isNot: true,
-                                      value: startValue,
-                                    }
-                                  : fieldName === 'collectionRelTypeId'
-                                  ? {
-                                      field: 'id',
-                                      operation: 'in',
-                                      isNot: false,
-                                      value: startValue,
-                                    }
-                                  : f.error(`extended filter not created`, {
-                                      fieldName,
-                                      startValue,
-                                    })
+                                    ? {
+                                        field: 'nodeNumber',
+                                        operation: 'between',
+                                        isNot: true,
+                                        value: startValue,
+                                      }
+                                    : fieldName === 'collectionRelTypeId'
+                                      ? {
+                                          field: 'id',
+                                          operation: 'in',
+                                          isNot: false,
+                                          value: startValue,
+                                        }
+                                      : f.error(`extended filter not created`, {
+                                          fieldName,
+                                          startValue,
+                                        })
                               )
                           ),
                         })
diff --git a/specifyweb/frontend/js_src/lib/components/Reports/Report.tsx b/specifyweb/frontend/js_src/lib/components/Reports/Report.tsx
index 886808e4a24..9cb770e52ee 100644
--- a/specifyweb/frontend/js_src/lib/components/Reports/Report.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Reports/Report.tsx
@@ -145,7 +145,7 @@ async function fixupImages(definition: Element): Promise> {
         Array.from(definition.querySelectorAll('imageExpression'), (image) => {
           const match = image.classList.contains('java.net.URL')
             ? undefined
-            : image.textContent?.match(reImage)?.slice(1)?.[0] ?? undefined;
+            : (image.textContent?.match(reImage)?.slice(1)?.[0] ?? undefined);
           return typeof match === 'string' ? [match, image] : undefined;
         })
       )
diff --git a/specifyweb/frontend/js_src/lib/components/Router/Router.tsx b/specifyweb/frontend/js_src/lib/components/Router/Router.tsx
index fa82a878018..144295e32f6 100644
--- a/specifyweb/frontend/js_src/lib/components/Router/Router.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Router/Router.tsx
@@ -40,8 +40,8 @@ export function unsafeTriggerNotFound(): boolean {
     unsafeLocation === undefined
       ? '/specify/'
       : pathIsOverlay(locationToUrl(unsafeLocation))
-      ? '/specify/overlay/not-found/'
-      : unsafeLocation,
+        ? '/specify/overlay/not-found/'
+        : unsafeLocation,
     {
       replace: true,
       state:
diff --git a/specifyweb/frontend/js_src/lib/components/Router/RouterUtils.tsx b/specifyweb/frontend/js_src/lib/components/Router/RouterUtils.tsx
index 448c31e88d1..79c9a96c848 100644
--- a/specifyweb/frontend/js_src/lib/components/Router/RouterUtils.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Router/RouterUtils.tsx
@@ -152,8 +152,8 @@ function SingleResource({
     index === -1
       ? undefined
       : index === 0
-      ? location.pathname
-      : location.pathname.slice(0, index);
+        ? location.pathname
+        : location.pathname.slice(0, index);
   if (process.env.NODE_ENV !== 'production') {
     if (path === undefined)
       throw new Error(
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaConfig/Field.tsx b/specifyweb/frontend/js_src/lib/components/SchemaConfig/Field.tsx
index 096ffbddda4..a0f4febe33d 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaConfig/Field.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaConfig/Field.tsx
@@ -90,7 +90,7 @@ export function SchemaConfigField({
       
         
       
@@ -198,7 +198,7 @@ function FormatterLine({
             handleFormatted(
               name,
               typeof values === 'object'
-                ? Object.values(values)[0][0][0]! ?? null
+                ? (Object.values(values)[0][0][0]! ?? null)
                 : null
             )
           }
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaConfig/Hooks.tsx b/specifyweb/frontend/js_src/lib/components/SchemaConfig/Hooks.tsx
index 3c6d3338645..4d53d05e39e 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaConfig/Hooks.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaConfig/Hooks.tsx
@@ -26,7 +26,7 @@ export function useSchemaContainer(
 ): readonly [
   SerializedResource,
   (container: SerializedResource) => void,
-  boolean
+  boolean,
 ] {
   const initialValue = React.useRef<
     SerializedResource | undefined
@@ -59,7 +59,7 @@ export function useContainerString(
   readonly [
     NewSpLocaleItemString | SpLocaleItemString | undefined,
     (containerName: NewSpLocaleItemString | SpLocaleItemString) => void,
-    boolean
+    boolean,
   ]
 > {
   const initialValue = React.useRef<
@@ -107,7 +107,7 @@ export function useContainerItems(
       index: number,
       item: SerializedResource & WithFetchedStrings
     ) => void,
-    RA
+    RA,
   ]
 > {
   const [changed, setChanged] = React.useState>([]);
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaViewer/Fields.tsx b/specifyweb/frontend/js_src/lib/components/SchemaViewer/Fields.tsx
index 2322d180501..fa995a174b9 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaViewer/Fields.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaViewer/Fields.tsx
@@ -63,7 +63,7 @@ const fieldColumns = f.store(
       type: getField(tables.SpLocaleContainerItem, 'type').label,
       length: schemaText.fieldLength(),
       databaseColumn: schemaText.databaseColumn(),
-    } as const)
+    }) as const
 );
 
 const getFields = (table: SpecifyTable) =>
@@ -91,6 +91,6 @@ const getFields = (table: SpecifyTable) =>
             ,
           ],
           databaseColumn: field.databaseColumn,
-        } as const)
+        }) as const
     )
   );
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaViewer/Relationships.tsx b/specifyweb/frontend/js_src/lib/components/SchemaViewer/Relationships.tsx
index 595f6106e4d..9829502969b 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaViewer/Relationships.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaViewer/Relationships.tsx
@@ -53,8 +53,8 @@ export function SchemaViewerRelationships({
                 dependentFilter === undefined
                   ? true
                   : dependentFilter
-                  ? undefined
-                  : true
+                    ? undefined
+                    : true
               )
             }
           >
@@ -69,8 +69,8 @@ export function SchemaViewerRelationships({
                 dependentFilter === undefined
                   ? false
                   : dependentFilter
-                  ? false
-                  : undefined
+                    ? false
+                    : undefined
               )
             }
           >
@@ -102,7 +102,7 @@ const relationshipColumns = f.store(
       relatedTable: schemaText.relatedTable(),
       otherSideName: schemaText.otherSideName(),
       isDependent: schemaText.dependent(),
-    } as const)
+    }) as const
 );
 
 const getRelationships = (table: SpecifyTable) =>
@@ -133,6 +133,6 @@ const getRelationships = (table: SpecifyTable) =>
           ],
           otherSideName: field.otherSideName,
           isDependent: booleanFormatter(field.isDependent()),
-        } as const)
+        }) as const
     )
   );
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaViewer/Table.tsx b/specifyweb/frontend/js_src/lib/components/SchemaViewer/Table.tsx
index ea0b28e3093..a89e0a385c2 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaViewer/Table.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaViewer/Table.tsx
@@ -61,7 +61,7 @@ export const schemaViewerTableColumns = f.store(
       tableId: schemaText.tableId(),
       fieldCount: schemaText.fieldCount(),
       relationshipCount: schemaText.relationshipCount(),
-    } as const)
+    }) as const
 );
 
 export const getSchemaViewerTables = () =>
@@ -103,6 +103,6 @@ export const getSchemaViewerTables = () =>
               {formatNumber(table.relationships.length)}
             ,
           ],
-        } as const)
+        }) as const
     )
   );
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaViewer/TableList.tsx b/specifyweb/frontend/js_src/lib/components/SchemaViewer/TableList.tsx
index f7ed6a8a27a..ad65c793093 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaViewer/TableList.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaViewer/TableList.tsx
@@ -14,7 +14,7 @@ export function SchemaViewerTableList<
     | 'schemaViewerRelationships'
     | 'schemaViewerTables',
   FIELD_NAME extends SortConfigs[SORT_CONFIG],
-  DATA extends SchemaViewerRow>
+  DATA extends SchemaViewerRow>,
 >({
   sortName,
   headers,
diff --git a/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx b/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx
index 36134d3ed30..f6170ade75d 100644
--- a/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx
@@ -146,19 +146,19 @@ function testFilter(
       ? (resource.get(field) ?? 0) >= values[0] &&
         (resource.get(field) ?? 0) <= values[1]
       : operation === 'in'
-      ? // Cast numbers to strings
-        // eslint-disable-next-line eqeqeq
-        values.some((value) => value == resource.get(field))
-      : operation === 'less'
-      ? values.every((value) => (resource.get(field) ?? 0) < value)
-      : error('Invalid Query Combo Box search filter', {
-          filter: {
-            operation,
-            field,
-            values,
-          },
-          resource,
-        });
+        ? // Cast numbers to strings
+          // eslint-disable-next-line eqeqeq
+          values.some((value) => value == resource.get(field))
+        : operation === 'less'
+          ? values.every((value) => (resource.get(field) ?? 0) < value)
+          : error('Invalid Query Combo Box search filter', {
+              filter: {
+                operation,
+                field,
+                values,
+              },
+              resource,
+            });
   return isNot ? !result : result;
 }
 
diff --git a/specifyweb/frontend/js_src/lib/components/Security/AdminStatusPlugin.tsx b/specifyweb/frontend/js_src/lib/components/Security/AdminStatusPlugin.tsx
index b367aad3e19..2283821736d 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/AdminStatusPlugin.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/AdminStatusPlugin.tsx
@@ -49,10 +49,10 @@ export function AdminStatusPlugin({
         resource.isNew()
           ? userText.saveUserFirst()
           : isAdmin && isCurrentUser
-          ? userText.canNotRemoveYourself()
-          : user.userType === 'Manager'
-          ? undefined
-          : userText.mustBeManager()
+            ? userText.canNotRemoveYourself()
+            : user.userType === 'Manager'
+              ? undefined
+              : userText.mustBeManager()
       }
       onClick={(): void =>
         loading(
diff --git a/specifyweb/frontend/js_src/lib/components/Security/CollectionHooks.tsx b/specifyweb/frontend/js_src/lib/components/Security/CollectionHooks.tsx
index 489df73811e..de2415422e3 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/CollectionHooks.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/CollectionHooks.tsx
@@ -100,7 +100,7 @@ export const mergeCollectionUsers = (
                 userId,
                 userName,
                 roles: [],
-              } as const)
+              }) as const
           ),
       ].sort(sortFunction(({ userName }) => userName))
     : undefined;
diff --git a/specifyweb/frontend/js_src/lib/components/Security/LibraryRole.tsx b/specifyweb/frontend/js_src/lib/components/Security/LibraryRole.tsx
index c5e0365bf69..5eb730a064b 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/LibraryRole.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/LibraryRole.tsx
@@ -83,7 +83,7 @@ function useRole(
     const id = f.parseInt(roleId);
     if (typeof id === 'number') {
       return typeof libraryRoles === 'object'
-        ? libraryRoles[id] ?? false
+        ? (libraryRoles[id] ?? false)
         : undefined;
     } else
       return {
diff --git a/specifyweb/frontend/js_src/lib/components/Security/Policies.tsx b/specifyweb/frontend/js_src/lib/components/Security/Policies.tsx
index 1993674b86e..a07b5efe2fc 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/Policies.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/Policies.tsx
@@ -209,7 +209,7 @@ function mutatePolicy(policy: Policy): Policy {
     possibleActions.length === 1
       ? possibleActions
       : hasTableActions(possibleActions)
-      ? f.unique(['read', ...selectedActions])
-      : selectedActions
+        ? f.unique(['read', ...selectedActions])
+        : selectedActions
   );
 }
diff --git a/specifyweb/frontend/js_src/lib/components/Security/PreviewComponents.tsx b/specifyweb/frontend/js_src/lib/components/Security/PreviewComponents.tsx
index aa779789056..2909e50dcb0 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/PreviewComponents.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/PreviewComponents.tsx
@@ -23,7 +23,7 @@ export function PreviewRow({
   readonly getOpenRoleUrl: (roleId: number) => string;
 }): JSX.Element {
   const [view, setView] = React.useState<
-    typeof tableActions[number] | undefined
+    (typeof tableActions)[number] | undefined
   >(undefined);
   const id = useId('preview-row');
   return (
@@ -98,8 +98,8 @@ export function PermissionExplanation({
                   index === 0
                     ? 'rounded-l'
                     : index + 1 === length
-                    ? 'rounded-r'
-                    : ''
+                      ? 'rounded-r'
+                      : ''
                 }
               `}
               key={index}
@@ -154,8 +154,8 @@ export function PermissionExplanation({
                   index === 0
                     ? 'rounded-l'
                     : index + 1 === length
-                    ? 'rounded-r'
-                    : ''
+                      ? 'rounded-r'
+                      : ''
                 }
               `}
               key={index}
diff --git a/specifyweb/frontend/js_src/lib/components/Security/PreviewTables.tsx b/specifyweb/frontend/js_src/lib/components/Security/PreviewTables.tsx
index a1a36e6d9d8..8966974d8c9 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/PreviewTables.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/PreviewTables.tsx
@@ -74,8 +74,8 @@ export function PreviewTables({
                 index === 0
                   ? 'rounded-l'
                   : index + 1 === length
-                  ? 'rounded-r'
-                  : ''
+                    ? 'rounded-r'
+                    : ''
               }
             `}
             key={header}
diff --git a/specifyweb/frontend/js_src/lib/components/Security/RoleTemplate.tsx b/specifyweb/frontend/js_src/lib/components/Security/RoleTemplate.tsx
index ce428951244..dc47000fadf 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/RoleTemplate.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/RoleTemplate.tsx
@@ -57,7 +57,7 @@ export function CreateRole({
   const currentRoleNames = (
     scope === 'institution'
       ? Object.values(libraryRoles ?? [])
-      : Object.values(roles ?? []).find(([{ id }]) => id === scope)?.[1] ?? []
+      : (Object.values(roles ?? []).find(([{ id }]) => id === scope)?.[1] ?? [])
   ).map(({ name }) => name);
   const loading = React.useContext(LoadingContext);
   const navigate = useNavigate();
diff --git a/specifyweb/frontend/js_src/lib/components/Security/User.tsx b/specifyweb/frontend/js_src/lib/components/Security/User.tsx
index 1d11ed7e22a..ab6f9f52030 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/User.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/User.tsx
@@ -507,40 +507,40 @@ function UserView({
                             response: JSON.parse(data),
                           })
                         : Array.isArray(institutionPolicies) &&
-                          changedInstitutionPolicies
-                        ? ajax(
-                            `/permissions/user_policies/institution/${userResource.id}/`,
-                            {
-                              method: 'PUT',
-                              body: decompressPolicies(institutionPolicies),
-                              headers: { Accept: 'text/plain' },
-                              expectedErrors: [Http.BAD_REQUEST],
-                            }
-                          ).then(({ data, status }) => {
-                            /*
-                             * Removing admin status fails if current user
-                             * is the last admin
-                             */
-                            if (status === Http.BAD_REQUEST) {
-                              const parsed: {
-                                readonly NoAdminUsersException: IR;
-                              } = JSON.parse(data);
-                              if (
-                                typeof parsed === 'object' &&
-                                'NoAdminUsersException' in parsed
-                              )
-                                setState({
-                                  type: 'NoAdminsError',
-                                });
-                              else
-                                setState({
-                                  type: 'SettingAgents',
-                                  response: JSON.parse(data),
-                                });
-                            } else return true;
-                            return undefined;
-                          })
-                        : true
+                            changedInstitutionPolicies
+                          ? ajax(
+                              `/permissions/user_policies/institution/${userResource.id}/`,
+                              {
+                                method: 'PUT',
+                                body: decompressPolicies(institutionPolicies),
+                                headers: { Accept: 'text/plain' },
+                                expectedErrors: [Http.BAD_REQUEST],
+                              }
+                            ).then(({ data, status }) => {
+                              /*
+                               * Removing admin status fails if current user
+                               * is the last admin
+                               */
+                              if (status === Http.BAD_REQUEST) {
+                                const parsed: {
+                                  readonly NoAdminUsersException: IR;
+                                } = JSON.parse(data);
+                                if (
+                                  typeof parsed === 'object' &&
+                                  'NoAdminUsersException' in parsed
+                                )
+                                  setState({
+                                    type: 'NoAdminsError',
+                                  });
+                                else
+                                  setState({
+                                    type: 'SettingAgents',
+                                    response: JSON.parse(data),
+                                  });
+                              } else return true;
+                              return undefined;
+                            })
+                          : true
                     )
                     .then(async (canContinue) =>
                       canContinue === true
diff --git a/specifyweb/frontend/js_src/lib/components/Security/UserCollections.tsx b/specifyweb/frontend/js_src/lib/components/Security/UserCollections.tsx
index e7c58880b5c..cda027fe177 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/UserCollections.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/UserCollections.tsx
@@ -125,8 +125,8 @@ export function UserCollections({
           user === undefined
             ? commonText.loading()
             : user.isNew()
-            ? userText.saveUserFirst()
-            : undefined
+              ? userText.saveUserFirst()
+              : undefined
         }
         onClick={handleOpen}
       >
diff --git a/specifyweb/frontend/js_src/lib/components/Security/UserComponents.tsx b/specifyweb/frontend/js_src/lib/components/Security/UserComponents.tsx
index 8c460324e86..d44e9a6a67c 100644
--- a/specifyweb/frontend/js_src/lib/components/Security/UserComponents.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Security/UserComponents.tsx
@@ -110,7 +110,7 @@ export function UserRoles({
       
       
    {typeof collectionRoles === 'object' && typeof userRoles === 'object' - ? collectionRoles[collectionId]?.map((role) => ( + ? (collectionRoles[collectionId]?.map((role) => (
  • (
  • {roleName}
  • - )) + ))) : commonText.loading()}
diff --git a/specifyweb/frontend/js_src/lib/components/Security/UserHooks.tsx b/specifyweb/frontend/js_src/lib/components/Security/UserHooks.tsx index 7470e09c08a..c6706fd7727 100644 --- a/specifyweb/frontend/js_src/lib/components/Security/UserHooks.tsx +++ b/specifyweb/frontend/js_src/lib/components/Security/UserHooks.tsx @@ -54,7 +54,7 @@ export function useUserRoles( userRoles: IR | undefined> | undefined, setUserRoles: (value: IR | undefined>) => void, initialRoles: React.MutableRefObject | undefined>>, - hasChanges: boolean + hasChanges: boolean, ] { const initialUserRoles = React.useRef | undefined>>({}); const [userRoles, setUserRoles] = useAsyncState | undefined>>( diff --git a/specifyweb/frontend/js_src/lib/components/Security/UserPolicyHooks.tsx b/specifyweb/frontend/js_src/lib/components/Security/UserPolicyHooks.tsx index e19ec459ff2..2e7d14b14c7 100644 --- a/specifyweb/frontend/js_src/lib/components/Security/UserPolicyHooks.tsx +++ b/specifyweb/frontend/js_src/lib/components/Security/UserPolicyHooks.tsx @@ -24,7 +24,7 @@ export function useUserPolicies( userPolicies: IR | undefined> | undefined, setUserPolicies: (value: IR | undefined> | undefined) => void, initialPolicies: React.MutableRefObject | undefined>>, - hasChanges: boolean + hasChanges: boolean, ] { const initialUserPolicies = React.useRef | undefined>>({}); const [userPolicies, setUserPolicies] = useAsyncState( @@ -98,7 +98,7 @@ export function useUserInstitutionalPolicies( institutionPolicies: RA | undefined, setInstitutionPolicies: (value: RA) => void, initialInstitutionPolicies: React.MutableRefObject>, - hasChanges: boolean + hasChanges: boolean, ] { const initialInstitutionPolicies = React.useRef>([]); const [institutionPolicies, setInstitutionPolicies] = useAsyncState( @@ -107,20 +107,20 @@ export function useUserInstitutionalPolicies( userResource.isNew() ? [] : hasDerivedPermission( - '/permissions/institutional_policies/user', - 'read' - ) - ? ajax>>( - `/permissions/user_policies/institution/${userResource.id}/`, - { - headers: { Accept: 'application/json' }, - } - ).then(({ data }) => { - const policies = processPolicies(data); - initialInstitutionPolicies.current = policies; - return policies; - }) - : undefined, + '/permissions/institutional_policies/user', + 'read' + ) + ? ajax>>( + `/permissions/user_policies/institution/${userResource.id}/`, + { + headers: { Accept: 'application/json' }, + } + ).then(({ data }) => { + const policies = processPolicies(data); + initialInstitutionPolicies.current = policies; + return policies; + }) + : undefined, [userResource] ), false diff --git a/specifyweb/frontend/js_src/lib/components/Security/policyConverter.ts b/specifyweb/frontend/js_src/lib/components/Security/policyConverter.ts index c9d0dac927e..f215e4ecb1e 100644 --- a/specifyweb/frontend/js_src/lib/components/Security/policyConverter.ts +++ b/specifyweb/frontend/js_src/lib/components/Security/policyConverter.ts @@ -69,15 +69,15 @@ export function decompressPolicies(rawPolicies: RA): IR> { actions: policy.actions, })) : policy.resource === anyResource && - getAllActions(anyResource).every((action) => - policy.actions.includes(action) - ) - ? { - // Combine separate actions on "any" resource into one - resource: anyResource, - actions: [anyAction], - } - : policy + getAllActions(anyResource).every((action) => + policy.actions.includes(action) + ) + ? { + // Combine separate actions on "any" resource into one + resource: anyResource, + actions: [anyAction], + } + : policy ); return Object.fromEntries( // If has collection access, add other basic policies diff --git a/specifyweb/frontend/js_src/lib/components/Security/registry.ts b/specifyweb/frontend/js_src/lib/components/Security/registry.ts index 47a7791324b..5c9f7ca2417 100644 --- a/specifyweb/frontend/js_src/lib/components/Security/registry.ts +++ b/specifyweb/frontend/js_src/lib/components/Security/registry.ts @@ -166,19 +166,19 @@ export function policiesToTsv(): string { key === '%' ? [] : Object.keys(entry.children).length > 0 - ? iterate( - entry.children, - [...path, entry.label], - isInstitutional || entry.isInstitutional - ) - : entry.actions.map((action) => [ - [...path, entry.label].join(' > '), - actionToLabel(action), - isInstitutional || entry.isInstitutional - ? 'Institution' - : 'Collection', - entry.groupName, - ]) + ? iterate( + entry.children, + [...path, entry.label], + isInstitutional || entry.isInstitutional + ) + : entry.actions.map((action) => [ + [...path, entry.label].join(' > '), + actionToLabel(action), + isInstitutional || entry.isInstitutional + ? 'Institution' + : 'Collection', + entry.groupName, + ]) ); return [ diff --git a/specifyweb/frontend/js_src/lib/components/SpecifyNetwork/Overlay.tsx b/specifyweb/frontend/js_src/lib/components/SpecifyNetwork/Overlay.tsx index 597b7418926..07cccd37321 100644 --- a/specifyweb/frontend/js_src/lib/components/SpecifyNetwork/Overlay.tsx +++ b/specifyweb/frontend/js_src/lib/components/SpecifyNetwork/Overlay.tsx @@ -70,8 +70,8 @@ export function useBrokerData( const speciesName = React.useMemo( () => (typeof species === 'object' - ? extractBrokerField(species, 'gbif', 'dwc:scientificName') ?? - extractBrokerField(species, 'gbif', 's2n:scientific_name') + ? (extractBrokerField(species, 'gbif', 'dwc:scientificName') ?? + extractBrokerField(species, 'gbif', 's2n:scientific_name')) : undefined) ?? occurrenceSpeciesName, [species, occurrenceSpeciesName] ); diff --git a/specifyweb/frontend/js_src/lib/components/Statistics/Categories.tsx b/specifyweb/frontend/js_src/lib/components/Statistics/Categories.tsx index 41c3bf413ca..f194e904121 100644 --- a/specifyweb/frontend/js_src/lib/components/Statistics/Categories.tsx +++ b/specifyweb/frontend/js_src/lib/components/Statistics/Categories.tsx @@ -221,26 +221,26 @@ export function Categories({ checkEmptyItems || handleEdit === undefined ? undefined : item.type === 'DefaultStat' - ? (querySpec, itemName): void => - handleClick( - { - type: 'CustomStat', - label: itemName, - querySpec: { - tableName: querySpec.tableName, - fields: querySpec.fields, - isDistinct: querySpec.isDistinct, + ? (querySpec, itemName): void => + handleClick( + { + type: 'CustomStat', + label: itemName, + querySpec: { + tableName: querySpec.tableName, + fields: querySpec.fields, + isDistinct: querySpec.isDistinct, + }, }, - }, - categoryIndex, - itemIndex - ) - : (querySpec): void => - handleEdit?.( - categoryIndex, - itemIndex, - querySpec - ) + categoryIndex, + itemIndex + ) + : (querySpec): void => + handleEdit?.( + categoryIndex, + itemIndex, + querySpec + ) } onLoad={onLoad} onRemove={ diff --git a/specifyweb/frontend/js_src/lib/components/Statistics/StatItems.tsx b/specifyweb/frontend/js_src/lib/components/Statistics/StatItems.tsx index 93991a6e958..8d20af31452 100644 --- a/specifyweb/frontend/js_src/lib/components/Statistics/StatItems.tsx +++ b/specifyweb/frontend/js_src/lib/components/Statistics/StatItems.tsx @@ -268,8 +268,8 @@ function QueryItem({ statState === 'noPermission' ? userText.noPermission() : statState === 'error' - ? statsText.error() - : value + ? statsText.error() + : value } onClick={handleClick} onClone={handleClone} diff --git a/specifyweb/frontend/js_src/lib/components/Statistics/StatsSpec.tsx b/specifyweb/frontend/js_src/lib/components/Statistics/StatsSpec.tsx index 2aa70f230ac..9c3035e585c 100644 --- a/specifyweb/frontend/js_src/lib/components/Statistics/StatsSpec.tsx +++ b/specifyweb/frontend/js_src/lib/components/Statistics/StatsSpec.tsx @@ -103,8 +103,8 @@ export const statsSpec: StatsSpec = { prep === undefined ? undefined : showPreparationsTotal - ? `${formatNumber(prep.lots)} / ${formatNumber(prep.total)}` - : formatNumber(prep.lots), + ? `${formatNumber(prep.lots)} / ${formatNumber(prep.total)}` + : formatNumber(prep.lots), querySpec: (dynamicResult) => ({ tableName: 'Preparation', diff --git a/specifyweb/frontend/js_src/lib/components/Statistics/__tests__/layout.tests.ts b/specifyweb/frontend/js_src/lib/components/Statistics/__tests__/layout.tests.ts index c774178846a..c3dd06baf37 100644 --- a/specifyweb/frontend/js_src/lib/components/Statistics/__tests__/layout.tests.ts +++ b/specifyweb/frontend/js_src/lib/components/Statistics/__tests__/layout.tests.ts @@ -55,8 +55,8 @@ export const statsSpecTest: StatsSpec = { prep === undefined ? undefined : showPreparationsTotal - ? `${formatNumber(prep.lots)} / ${formatNumber(prep.total)}` - : formatNumber(prep.lots), + ? `${formatNumber(prep.lots)} / ${formatNumber(prep.total)}` + : formatNumber(prep.lots), }, }, }, diff --git a/specifyweb/frontend/js_src/lib/components/Statistics/hooks.tsx b/specifyweb/frontend/js_src/lib/components/Statistics/hooks.tsx index b4fefe75a41..186aa63821b 100644 --- a/specifyweb/frontend/js_src/lib/components/Statistics/hooks.tsx +++ b/specifyweb/frontend/js_src/lib/components/Statistics/hooks.tsx @@ -400,7 +400,7 @@ export function statsToTsv( * */ export function useStatValueLoad< - PROMISE_TYPE extends number | string | undefined + PROMISE_TYPE extends number | string | undefined, >( value: number | string | undefined, promiseGenerator: () => Promise, diff --git a/specifyweb/frontend/js_src/lib/components/Statistics/index.tsx b/specifyweb/frontend/js_src/lib/components/Statistics/index.tsx index 5ee44970a03..1c420008e7d 100644 --- a/specifyweb/frontend/js_src/lib/components/Statistics/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/Statistics/index.tsx @@ -310,8 +310,8 @@ function ProtectedStatsPage(): JSX.Element | null { ? undefined : sharedLayout[activePage.pageIndex] : personalLayout?.[activePage.pageIndex].categories === undefined - ? undefined - : personalLayout[activePage.pageIndex]; + ? undefined + : personalLayout[activePage.pageIndex]; const handleChange = React.useCallback( ( diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/syncers.test.ts b/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/syncers.test.ts index 2c1d1c7a44c..e44df789395 100644 --- a/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/syncers.test.ts +++ b/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/syncers.test.ts @@ -18,23 +18,23 @@ requireContext(); const tests: { readonly [SYNCER in keyof typeof syncers]: RA< - (typeof syncers[SYNCER] extends ( + ((typeof syncers)[SYNCER] extends ( ...args: RA ) => Syncer ? { readonly arguments: - | Parameters - | (() => Parameters); + | Parameters<(typeof syncers)[SYNCER]> + | (() => Parameters<(typeof syncers)[SYNCER]>); } : RR) & { - readonly in: SyncerIn>; + readonly in: SyncerIn>; readonly out: - | SyncerOut> - | (() => SyncerOut>); + | SyncerOut> + | (() => SyncerOut>); readonly newOut?: - | SyncerOut> - | (() => SyncerOut>); - readonly final?: SyncerIn>; + | SyncerOut> + | (() => SyncerOut>); + readonly final?: SyncerIn>; readonly logContext?: LogPathPart; readonly error?: RA; readonly warn?: RA; diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/formatXmlNode.ts b/specifyweb/frontend/js_src/lib/components/Syncer/formatXmlNode.ts index 636757afb63..5c421f82904 100644 --- a/specifyweb/frontend/js_src/lib/components/Syncer/formatXmlNode.ts +++ b/specifyweb/frontend/js_src/lib/components/Syncer/formatXmlNode.ts @@ -24,8 +24,8 @@ const formatXmlChildren = ( child.type === 'Text' ? { ...child, string: child.string.trim() } : child.type === 'XmlNode' - ? formatXmlNode(child, `${indentation}${indent}`) - : child + ? formatXmlNode(child, `${indentation}${indent}`) + : child ) .flatMap((child) => [ { diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/fromSimpleXmlNode.ts b/specifyweb/frontend/js_src/lib/components/Syncer/fromSimpleXmlNode.ts index ef38beb513e..7631af041d8 100644 --- a/specifyweb/frontend/js_src/lib/components/Syncer/fromSimpleXmlNode.ts +++ b/specifyweb/frontend/js_src/lib/components/Syncer/fromSimpleXmlNode.ts @@ -125,10 +125,10 @@ function mergeNodes( return newChildren === undefined ? child : // Child was removed - newChild === undefined - ? undefined - : // Child was modified - fromSimpleXmlNode(newChild); + newChild === undefined + ? undefined + : // Child was modified + fromSimpleXmlNode(newChild); }) ); return Object.values(writableChildren) diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/index.ts b/specifyweb/frontend/js_src/lib/components/Syncer/index.ts index df6347c4f1f..b50aada715c 100644 --- a/specifyweb/frontend/js_src/lib/components/Syncer/index.ts +++ b/specifyweb/frontend/js_src/lib/components/Syncer/index.ts @@ -32,7 +32,7 @@ export type SyncerIn> = export type SyncerOut> = SYNCER extends Syncer ? OUTPUT : never; -export type ExtractSyncer = +export type ExtractSyncer = T extends (...args: RA) => Syncer ? ReturnType : T; /** diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/syncers.ts b/specifyweb/frontend/js_src/lib/components/Syncer/syncers.ts index aaa772ecc16..bec735238bf 100644 --- a/specifyweb/frontend/js_src/lib/components/Syncer/syncers.ts +++ b/specifyweb/frontend/js_src/lib/components/Syncer/syncers.ts @@ -381,7 +381,7 @@ export const syncers = { SUB_SPEC extends BaseSpec, NEW_OBJECT extends Omit & { readonly [key in KEY]: SpecToJson; - } + }, >( key: KEY, spec: (dependent: OBJECT) => SUB_SPEC @@ -408,7 +408,7 @@ export const syncers = { .deserializer(object?.[key]), logContext: getLogContext(), }, - } as unknown as OBJECT) + }) as unknown as OBJECT ), /** @@ -442,7 +442,7 @@ export const syncers = { RAW, PARSED, OBJECT extends { readonly [key in KEY]: RAW }, - NEW_OBJECT extends Omit & { readonly [key in KEY]: PARSED } + NEW_OBJECT extends Omit & { readonly [key in KEY]: PARSED }, >( key: KEY, serializer: (object: OBJECT) => PARSED, @@ -453,12 +453,12 @@ export const syncers = { ({ ...object, [key]: serializer(object), - } as unknown as NEW_OBJECT), + }) as unknown as NEW_OBJECT, (object) => ({ ...object, [key]: deserializer(object ?? {}), - } as unknown as OBJECT) + }) as unknown as OBJECT ), /** @@ -610,7 +610,7 @@ export const syncers = { readonly type: TYPE_MAPPER[KEY]; readonly rawType: string & keyof TYPE_MAPPER; }; - }[keyof TYPE_MAPPER] + }[keyof TYPE_MAPPER], >( /** * They key in the original object at which the @@ -688,9 +688,9 @@ export const syncers = { const resolvedRawType = typeFromRawType === definition.type ? rawType - : Object.entries(typeMapper).find( + : (Object.entries(typeMapper).find( ([_raw, mapped]) => mapped === definition.type - )?.[0] ?? rawType; + )?.[0] ?? rawType); const spec = mapper[definition.type] ?? mapper.Unknown; const { deserializer } = syncers.object( spec(cell as unknown as IN, extraPayload, rawType) diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/xmlToJson.ts b/specifyweb/frontend/js_src/lib/components/Syncer/xmlToJson.ts index 8227aeb89e3..bf6fcc130e0 100644 --- a/specifyweb/frontend/js_src/lib/components/Syncer/xmlToJson.ts +++ b/specifyweb/frontend/js_src/lib/components/Syncer/xmlToJson.ts @@ -37,13 +37,13 @@ export const xmlToJson = (element: Element): XmlNode => ({ comment: node.data, } : node instanceof Text - ? { - type: 'Text', - string: node.data, - } - : node instanceof Element - ? xmlToJson(node) - : error('Unknown element type', node) + ? { + type: 'Text', + string: node.data, + } + : node instanceof Element + ? xmlToJson(node) + : error('Unknown element type', node) ), }); @@ -62,8 +62,8 @@ export function jsonToXml(node: XmlNode): Element { child.type === 'Text' ? xmlDocument.createTextNode(child.string) : child.type === 'Comment' - ? xmlDocument.createComment(child.comment) - : jsonToXml(child) + ? xmlDocument.createComment(child.comment) + : jsonToXml(child) ) ); return element; diff --git a/specifyweb/frontend/js_src/lib/components/Toolbar/Language.tsx b/specifyweb/frontend/js_src/lib/components/Toolbar/Language.tsx index c593cb16a01..cfde42616e2 100644 --- a/specifyweb/frontend/js_src/lib/components/Toolbar/Language.tsx +++ b/specifyweb/frontend/js_src/lib/components/Toolbar/Language.tsx @@ -137,8 +137,8 @@ export function LanguageSelection({ value === 'supportLocalization' ? setShowSupportDialog(true) : !isForInterface || f.has(completeLanguages, value) - ? handleChange(value as LANGUAGES) - : setWarningLanguage(value as LANGUAGES) + ? handleChange(value as LANGUAGES) + : setWarningLanguage(value as LANGUAGES) } > {Object.entries(languages).map(([code, nameLocal]) => ( diff --git a/specifyweb/frontend/js_src/lib/components/Toolbar/WbsDialog.tsx b/specifyweb/frontend/js_src/lib/components/Toolbar/WbsDialog.tsx index e6de4ab12d9..38f04d7ff6d 100644 --- a/specifyweb/frontend/js_src/lib/components/Toolbar/WbsDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Toolbar/WbsDialog.tsx @@ -44,7 +44,7 @@ const createWorkbenchDataSet = async () => ); export const createEmptyDataSet = async < - DATASET extends AttachmentDataSet | Dataset + DATASET extends AttachmentDataSet | Dataset, >( datasetUrl: string, name: LocalizedString, @@ -164,8 +164,8 @@ export function DataSetsDialog({ sortConfig.sortField === 'name' ? name : sortConfig.sortField === 'dateCreated' - ? timestampcreated - : uploadresult?.timestamp ?? '' + ? timestampcreated + : (uploadresult?.timestamp ?? '') ) : undefined; diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/Actions.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/Actions.tsx index 4ba6c76087a..c6d8c34f465 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/Actions.tsx +++ b/specifyweb/frontend/js_src/lib/components/TreeView/Actions.tsx @@ -34,7 +34,7 @@ const treeActions = [ 'synonymize', ] as const; -type Action = typeof treeActions[number]; +type Action = (typeof treeActions)[number]; export function TreeViewActions({ tableName, @@ -339,15 +339,17 @@ function ActiveAction({ type === 'move' ? treeText.nodeMoveHintMessage({ nodeName: actionRow.fullName }) : type === 'merge' - ? treeText.mergeNodeHintMessage({ nodeName: actionRow.fullName }) - : type === 'bulkMove' - ? treeText.bulkMoveNodeHintMessage({ nodeName: actionRow.fullName }) - : type === 'synonymize' - ? treeText.synonymizeNodeHintMessage({ nodeName: actionRow.fullName }) - : treeText.desynonymizeNodeMessage({ - nodeName: actionRow.fullName, - synonymName: focusedRow.fullName, - }); + ? treeText.mergeNodeHintMessage({ nodeName: actionRow.fullName }) + : type === 'bulkMove' + ? treeText.bulkMoveNodeHintMessage({ nodeName: actionRow.fullName }) + : type === 'synonymize' + ? treeText.synonymizeNodeHintMessage({ + nodeName: actionRow.fullName, + }) + : treeText.desynonymizeNodeMessage({ + nodeName: actionRow.fullName, + synonymName: focusedRow.fullName, + }); let disabled: string | false = false; if (type === 'move') { if (isSameRecord) disabled = title; @@ -382,17 +384,19 @@ function ActiveAction({ {typeof disabled === 'string' ? disabled : type === 'move' - ? treeText.moveNodeHere({ nodeName: actionRow.fullName }) - : type === 'bulkMove' - ? treeText.moveNodePreparationsHere({ nodeName: actionRow.fullName }) - : type === 'merge' - ? treeText.mergeNodeHere({ nodeName: actionRow.fullName }) - : type === 'synonymize' - ? treeText.makeSynonym({ - nodeName: actionRow.fullName, - synonymName: focusedRow.fullName, - }) - : treeText.desynonymizeNode()} + ? treeText.moveNodeHere({ nodeName: actionRow.fullName }) + : type === 'bulkMove' + ? treeText.moveNodePreparationsHere({ + nodeName: actionRow.fullName, + }) + : type === 'merge' + ? treeText.mergeNodeHere({ nodeName: actionRow.fullName }) + : type === 'synonymize' + ? treeText.makeSynonym({ + nodeName: actionRow.fullName, + synonymName: focusedRow.fullName, + }) + : treeText.desynonymizeNode()}
{commonText.cancel()} @@ -424,12 +428,12 @@ function ActiveAction({ {type === 'move' ? treeText.moveNode() : type === 'bulkMove' - ? treeText.moveItems() - : type === 'merge' - ? treeText.mergeNode() - : type === 'synonymize' - ? treeText.synonymizeNode() - : treeText.desynonymizeNode()} + ? treeText.moveItems() + : type === 'merge' + ? treeText.mergeNode() + : type === 'synonymize' + ? treeText.synonymizeNode() + : treeText.desynonymizeNode()} } @@ -437,12 +441,12 @@ function ActiveAction({ type === 'move' ? treeText.moveNode() : type === 'bulkMove' - ? treeText.moveItems() - : type === 'merge' - ? treeText.mergeNode() - : type === 'synonymize' - ? treeText.synonymizeNode() - : treeText.desynonymizeNode() + ? treeText.moveItems() + : type === 'merge' + ? treeText.mergeNode() + : type === 'synonymize' + ? treeText.synonymizeNode() + : treeText.desynonymizeNode() } onClose={handleCancelAction} > @@ -453,27 +457,27 @@ function ActiveAction({ parentName: focusedRow.fullName, }) : type === 'bulkMove' - ? treeText.nodeBulkMoveMessage({ - treeName, - nodeName: actionRow.fullName, - parentName: focusedRow.fullName, - }) - : type === 'merge' - ? treeText.mergeNodeMessage({ - treeName, - nodeName: actionRow.fullName, - parentName: focusedRow.fullName, - }) - : type === 'synonymize' - ? treeText.synonymizeMessage({ - treeName, - nodeName: actionRow.fullName, - synonymName: focusedRow.fullName, - }) - : treeText.desynonymizeNodeMessage({ - nodeName: actionRow.fullName, - synonymName: focusedRow.fullName, - })} + ? treeText.nodeBulkMoveMessage({ + treeName, + nodeName: actionRow.fullName, + parentName: focusedRow.fullName, + }) + : type === 'merge' + ? treeText.mergeNodeMessage({ + treeName, + nodeName: actionRow.fullName, + parentName: focusedRow.fullName, + }) + : type === 'synonymize' + ? treeText.synonymizeMessage({ + treeName, + nodeName: actionRow.fullName, + synonymName: focusedRow.fullName, + }) + : treeText.desynonymizeNodeMessage({ + nodeName: actionRow.fullName, + synonymName: focusedRow.fullName, + })} ) : undefined} diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/CreateTree.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/CreateTree.tsx index c76782c0161..c24855839dc 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/CreateTree.tsx +++ b/specifyweb/frontend/js_src/lib/components/TreeView/CreateTree.tsx @@ -24,7 +24,7 @@ import { defaultTreeDefs } from './defaults'; export function CreateTree< SCHEMA extends AnyTree, - TREE_NAME extends AnyTree['tableName'] + TREE_NAME extends AnyTree['tableName'], >({ tableName, treeDefinitions, diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/Row.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/Row.tsx index 902deb8d8fa..55757eed813 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/Row.tsx +++ b/specifyweb/frontend/js_src/lib/components/TreeView/Row.tsx @@ -172,8 +172,8 @@ export function TreeRow({ isAction ? 'outline outline-1 outline-red-500' : isFocused - ? 'outline outline-1 outline-blue-500' - : '' + ? 'outline outline-1 outline-blue-500' + : '' } ${hideEmptyNodes && isLoadingStats ? 'opacity-50' : ''} `} @@ -205,19 +205,19 @@ export function TreeRow({ ? isLoading ? commonText.loading() : row.children === 0 - ? treeText.leafNode() - : displayChildren - ? treeText.opened() - : treeText.closed() + ? treeText.leafNode() + : displayChildren + ? treeText.opened() + : treeText.closed() : undefined} {isLoading ? icons.clock : row.children === 0 - ? icons.blank - : displayChildren - ? icons.chevronDown - : icons.chevronRight} + ? icons.blank + : displayChildren + ? icons.chevronDown + : icons.chevronRight} ({ name: row.acceptedName ?? row.acceptedId.toString(), }) : typeof row.synonyms === 'string' - ? treeText.synonyms({ - names: row.synonyms, - }) - : undefined + ? treeText.synonyms({ + names: row.synonyms, + }) + : undefined } > {doIncludeAuthorPref && diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx index e18464929e2..c494894abb4 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx +++ b/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx @@ -39,7 +39,7 @@ const treeToPref = { export function Tree< SCHEMA extends AnyTree, - TREE_NAME extends SCHEMA['tableName'] + TREE_NAME extends SCHEMA['tableName'], >({ treeDefinitionItems, tableName, @@ -207,7 +207,7 @@ export function Tree< } > { - (collapsedRanks?.includes(rank.rankId) ?? false + ((collapsedRanks?.includes(rank.rankId) ?? false) ? rankName[0] : rankName) as LocalizedString } diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/helpers.ts b/specifyweb/frontend/js_src/lib/components/TreeView/helpers.ts index 069fd4dc0cc..9f986e6a16a 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/helpers.ts +++ b/specifyweb/frontend/js_src/lib/components/TreeView/helpers.ts @@ -26,7 +26,7 @@ export const fetchRows = async (fetchUrl: string) => string | null, string | null, number, - string | null + string | null, ] > >(fetchUrl, { @@ -151,8 +151,7 @@ export const scrollIntoView = throttle(function scrollIntoView( } catch { element.scrollIntoView(mode === 'start'); } -}, -throttleRate); +}, throttleRate); export type KeyAction = | 'child' diff --git a/specifyweb/frontend/js_src/lib/components/WbActions/WbUpload.tsx b/specifyweb/frontend/js_src/lib/components/WbActions/WbUpload.tsx index 4823c588881..400d3ee468a 100644 --- a/specifyweb/frontend/js_src/lib/components/WbActions/WbUpload.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbActions/WbUpload.tsx @@ -46,8 +46,8 @@ export function WbUpload({ hasUnsavedChanges ? wbText.unavailableWhileEditing() : cellCounts.invalidCells > 0 - ? wbText.uploadUnavailableWhileHasErrors() - : undefined + ? wbText.uploadUnavailableWhileHasErrors() + : undefined } onClick={handleUpload} > diff --git a/specifyweb/frontend/js_src/lib/components/WbActions/WbValidate.tsx b/specifyweb/frontend/js_src/lib/components/WbActions/WbValidate.tsx index 5398e16c159..f8e80c880a4 100644 --- a/specifyweb/frontend/js_src/lib/components/WbActions/WbValidate.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbActions/WbValidate.tsx @@ -65,8 +65,8 @@ export function WbValidate({ hasUnsavedChanges ? wbText.unavailableWhileEditing() : isMapped - ? undefined - : wbText.wbValidateUnavailable() + ? undefined + : wbText.wbValidateUnavailable() } onClick={handleValidate} > diff --git a/specifyweb/frontend/js_src/lib/components/WbActions/index.tsx b/specifyweb/frontend/js_src/lib/components/WbActions/index.tsx index 6349a50e37e..f8856a4b1b9 100644 --- a/specifyweb/frontend/js_src/lib/components/WbActions/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbActions/index.tsx @@ -105,8 +105,8 @@ export function WbActions({ dataCheckInProgress ? wbText.unavailableWhileValidating() : isUploaded - ? undefined - : wbText.wbUploadedUnavailable() + ? undefined + : wbText.wbUploadedUnavailable() } onClick={handleToggleResults} > @@ -212,16 +212,16 @@ export function WbActions({ mode === 'validate' ? wbText.validationCanceled() : mode === 'unupload' - ? wbText.rollbackCanceled() - : wbText.uploadCanceled() + ? wbText.rollbackCanceled() + : wbText.uploadCanceled() } onClose={closeAbortedMessage} > {mode === 'validate' ? wbText.validationCanceledDescription() : mode === 'unupload' - ? wbText.rollbackCanceledDescription() - : wbText.uploadCanceledDescription()} + ? wbText.rollbackCanceledDescription() + : wbText.uploadCanceledDescription()} )} diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/Components.tsx b/specifyweb/frontend/js_src/lib/components/WbPlanView/Components.tsx index fc1143aaf9f..190ce13bf18 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/Components.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/Components.tsx @@ -42,7 +42,8 @@ export function ListOfBaseTables({ filter={filter} getAction={({ name }) => () => - handleClick(name)} + handleClick(name) + } /> ); } diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/CustomSelectElement.tsx b/specifyweb/frontend/js_src/lib/components/WbPlanView/CustomSelectElement.tsx index 259659b48ba..de59957a8ac 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/CustomSelectElement.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/CustomSelectElement.tsx @@ -580,12 +580,12 @@ export function CustomSelectElement({ defaultOption?.isRequired === true ? 'custom-select-input-required bg-[color:var(--custom-select-b2)]' : defaultOption?.isHidden === true - ? `custom-select-input-hidden bg-[color:var(--custom-select-b2)] + ? `custom-select-input-hidden bg-[color:var(--custom-select-b2)] dark:!border-solid` - : customSelectType === 'OPTIONS_LIST' && - defaultOption?.isRelationship === true - ? 'bg-yellow-250 dark:bg-yellow-900' - : customSelectElementBackground + : customSelectType === 'OPTIONS_LIST' && + defaultOption?.isRelationship === true + ? 'bg-yellow-250 dark:bg-yellow-900' + : customSelectElementBackground } ${isOpen ? 'z-[3] rounded-b-none' : ''} ${handleClick === undefined ? '' : 'border border-gray-500'} diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/LineComponents.tsx b/specifyweb/frontend/js_src/lib/components/WbPlanView/LineComponents.tsx index d4c7648c1e0..248a8f36e37 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/LineComponents.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/LineComponents.tsx @@ -229,16 +229,21 @@ export function MappingElement({ }: MappingElementProps): JSX.Element { const fieldGroups = Object.entries(fieldsData).reduce< R> - >((fieldGroups, [fieldName, fieldData]) => { - const groupName = getFieldGroupName( - fieldData.isHidden ?? false, - fieldData.isRequired ?? false - ); - fieldGroups[groupName] ??= {}; - fieldGroups[groupName][fieldName] = fieldData; + >( + (fieldGroups, [fieldName, fieldData]) => { + const groupName = getFieldGroupName( + fieldData.isHidden ?? false, + fieldData.isRequired ?? false + ); + fieldGroups[groupName] ??= {}; + fieldGroups[groupName][fieldName] = fieldData; - return fieldGroups; - }, Object.fromEntries(Object.keys(fieldGroupLabels).map((groupName) => [groupName, {}]))); + return fieldGroups; + }, + Object.fromEntries( + Object.keys(fieldGroupLabels).map((groupName) => [groupName, {}]) + ) + ); const customSelectOptionGroups = Object.fromEntries( Object.entries(fieldGroups) diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/autoMapper.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/autoMapper.ts index d4a3c7d25b0..1192e618a8f 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/autoMapper.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/autoMapper.ts @@ -569,7 +569,7 @@ export class AutoMapper { } private readonly findFormattedHeaderFieldSynonyms = < - TABLE_NAME extends keyof Tables + TABLE_NAME extends keyof Tables, >( tableName: TABLE_NAME, fieldName: string @@ -888,14 +888,14 @@ export class AutoMapper { if (isTreeTable(tableName)) { fixedNewPathParts = newPathParts.map((mappingPathPart) => valueIsTreeRank(mappingPathPart) - ? f.maybe( + ? (f.maybe( getTreeDefinitionItems(tableName, false, 'all')?.find( ({ name }) => name.toLowerCase() === getNameFromTreeRankName(mappingPathPart).toLowerCase() )?.name, formatTreeRank - ) ?? mappingPathPart + ) ?? mappingPathPart) : mappingPathPart ); } diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/mappingPreview.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/mappingPreview.ts index ad03b945177..ce7e4c0307a 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/mappingPreview.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/mappingPreview.ts @@ -161,16 +161,16 @@ export function generateMappingPathPreview( fieldNameFormatted === undefined ? tableOrRankName || fieldName : fieldIsGeneric - ? tableOrRankName - : undefined; + ? tableOrRankName + : undefined; const tableNameFormatted = tablesToHide.has(databaseTableOrRankName) && databaseFieldName !== formattedEntry ? [parentTableOrTreeName || tableNameNonEmpty] : genericTables.has(databaseTableOrRankName) - ? [parentTableOrTreeName, tableNameNonEmpty] - : [tableNameNonEmpty]; + ? [parentTableOrTreeName, tableNameNonEmpty] + : [tableNameNonEmpty]; return filterArray([ ...(valueIsTreeRank(databaseTableOrRankName) diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/navigator.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/navigator.ts index 6cb3c6a28a7..70559b6bf1c 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/navigator.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/navigator.ts @@ -143,7 +143,7 @@ function navigator({ callbacks.handleTreeRanks({ ...callbackPayload, definitionName: spec.useSpecificTreeInterface - ? definitions[0].definition.name ?? anyTreeRank + ? (definitions[0].definition.name ?? anyTreeRank) : anyTreeRank, }); } else if (valueIsTreeDefinition(parentPartName)) @@ -163,8 +163,8 @@ function navigator({ const nextTable = isSpecial ? table : typeof nextField === 'object' && nextField.isRelationship - ? nextField.relatedTable - : undefined; + ? nextField.relatedTable + : undefined; if (typeof nextTable === 'object' && nextField?.isRelationship !== false) navigator({ diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts index 3619bb9e853..86c639f5167 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts @@ -28,7 +28,7 @@ export type NavigatorSpec = { // Whether to include all tree fields for non "any rank" readonly includeAllTreeFields: boolean; readonly allowNestedToMany: boolean; - readonly ensurePermission: () => typeof tableActions[number] | undefined; + readonly ensurePermission: () => (typeof tableActions)[number] | undefined; // Whether can execute query/do workbench upload readonly hasActionPermission: () => boolean; readonly includeRelationshipsFromTree: boolean; diff --git a/specifyweb/frontend/js_src/lib/components/WbToolkit/CoordinateConverter.tsx b/specifyweb/frontend/js_src/lib/components/WbToolkit/CoordinateConverter.tsx index 049665853a2..4ae163bc836 100644 --- a/specifyweb/frontend/js_src/lib/components/WbToolkit/CoordinateConverter.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbToolkit/CoordinateConverter.tsx @@ -52,8 +52,8 @@ export function WbConvertCoordinates({ ? isUploaded ? wbText.unavailableWhenUploaded() : isResultsOpen - ? wbText.unavailableWhileViewingResults() - : undefined + ? wbText.unavailableWhileViewingResults() + : undefined : wbText.unavailableWithoutLocality() } onClick={openConvertCoords} @@ -167,10 +167,10 @@ function CoordinateConverter({ showDirection ? finalValue : 'SW'.includes(finalValue.at(-1)!) - ? `-${finalValue.slice(0, -1)}` - : 'NE'.includes(finalValue.at(-1)!) - ? finalValue.slice(0, -1) - : finalValue; + ? `-${finalValue.slice(0, -1)}` + : 'NE'.includes(finalValue.at(-1)!) + ? finalValue.slice(0, -1) + : finalValue; const originalState = columnsToWorkWith.flatMap((visualCol) => Array.from({ length: hot.countRows() }, (_, visualRow) => { diff --git a/specifyweb/frontend/js_src/lib/components/WbToolkit/GeoLocate.tsx b/specifyweb/frontend/js_src/lib/components/WbToolkit/GeoLocate.tsx index ef9984c49dd..dd4a7a09823 100644 --- a/specifyweb/frontend/js_src/lib/components/WbToolkit/GeoLocate.tsx +++ b/specifyweb/frontend/js_src/lib/components/WbToolkit/GeoLocate.tsx @@ -51,8 +51,8 @@ export function WbGeoLocate({ ? isUploaded ? wbText.unavailableWhenUploaded() : isResultsOpen - ? wbText.unavailableWhileViewingResults() - : undefined + ? wbText.unavailableWhileViewingResults() + : undefined : wbText.unavailableWithoutLocality() } onClick={openGeoLocate} diff --git a/specifyweb/frontend/js_src/lib/components/WbUtils/Utils.ts b/specifyweb/frontend/js_src/lib/components/WbUtils/Utils.ts index 9c8b45ba327..543e96a0826 100644 --- a/specifyweb/frontend/js_src/lib/components/WbUtils/Utils.ts +++ b/specifyweb/frontend/js_src/lib/components/WbUtils/Utils.ts @@ -62,7 +62,7 @@ export class WbUtils { readonly visualRow: number; readonly visualCol: number; }, - number + number, ] | readonly [undefined, number] { const cellMetaObject = this.workbench.cells.getCellMetaObject(); @@ -100,8 +100,8 @@ export class WbUtils { ? (visualCol: number) => visualCol >= currentTransposedCol : (visualCol: number) => visualCol > currentTransposedCol : matchCurrentCell - ? (visualCol: number) => visualCol <= currentTransposedCol - : (visualCol: number) => visualCol < currentTransposedCol; + ? (visualCol: number) => visualCol <= currentTransposedCol + : (visualCol: number) => visualCol < currentTransposedCol; let matchedCell: | { @@ -116,37 +116,39 @@ export class WbUtils { ? f.id : (array: RA): RA => Array.from(array).reverse(); - orderIt(Object.entries(cellMetaObject)).find(([visualRowString, metaRow]) => - typeof metaRow === 'object' - ? orderIt(Object.entries(metaRow)).find( - ([visualColString, metaArray]) => { - /* - * This is 10 times faster then Number.parseInt because of a slow - * Babel polyfill - */ - const visualRow = f.fastParseInt(visualRowString); - const visualCol = f.fastParseInt(visualColString); - - const cellTypeMatches = this.workbench.cells?.cellIsType( - metaArray, - type - ); - cellIsTypeCount += cellTypeMatches ? 1 : 0; - - const isWithinBounds = - compareRows(visualRow) && - (visualRow !== currentTransposedRow || compareCols(visualCol)); - - const matches = cellTypeMatches && isWithinBounds; - if (matches) - matchedCell = { - visualRow: resolveIndex(visualRow, visualCol, true), - visualCol: resolveIndex(visualRow, visualCol, false), - }; - return matches; - } - ) - : undefined + orderIt(Object.entries(cellMetaObject)).find( + ([visualRowString, metaRow]) => + typeof metaRow === 'object' + ? orderIt(Object.entries(metaRow)).find( + ([visualColString, metaArray]) => { + /* + * This is 10 times faster then Number.parseInt because of a slow + * Babel polyfill + */ + const visualRow = f.fastParseInt(visualRowString); + const visualCol = f.fastParseInt(visualColString); + + const cellTypeMatches = this.workbench.cells?.cellIsType( + metaArray, + type + ); + cellIsTypeCount += cellTypeMatches ? 1 : 0; + + const isWithinBounds = + compareRows(visualRow) && + (visualRow !== currentTransposedRow || + compareCols(visualCol)); + + const matches = cellTypeMatches && isWithinBounds; + if (matches) + matchedCell = { + visualRow: resolveIndex(visualRow, visualCol, true), + visualCol: resolveIndex(visualRow, visualCol, false), + }; + return matches; + } + ) + : undefined ); let cellRelativePosition; diff --git a/specifyweb/frontend/js_src/lib/components/WebLinks/Definition.tsx b/specifyweb/frontend/js_src/lib/components/WebLinks/Definition.tsx index 1393166f200..82bcffb5c56 100644 --- a/specifyweb/frontend/js_src/lib/components/WebLinks/Definition.tsx +++ b/specifyweb/frontend/js_src/lib/components/WebLinks/Definition.tsx @@ -59,18 +59,18 @@ export function WebLinkDefinition({ field: [], } : type === 'ThisField' - ? { - type: 'ThisField', - } - : type === 'FormattedResource' - ? { - type: 'FormattedResource', - formatter: localized(''), - } - : { - type: 'UrlPart', - value: localized(''), - } + ? { + type: 'ThisField', + } + : type === 'FormattedResource' + ? { + type: 'FormattedResource', + formatter: localized(''), + } + : { + type: 'UrlPart', + value: localized(''), + } ) ) } diff --git a/specifyweb/frontend/js_src/lib/components/WebLinks/index.tsx b/specifyweb/frontend/js_src/lib/components/WebLinks/index.tsx index 534fba58412..89ecaaa0237 100644 --- a/specifyweb/frontend/js_src/lib/components/WebLinks/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/WebLinks/index.tsx @@ -78,12 +78,12 @@ export function WebLinkField({ part.type === 'Field' ? fetchPathAsString(resource, part.field) : part.type === 'ThisField' - ? typeof field === 'object' - ? fetchPathAsString(resource, [field]) - : undefined - : part.type === 'FormattedResource' - ? format(resource, part.formatter, false) - : part.value + ? typeof field === 'object' + ? fetchPathAsString(resource, [field]) + : undefined + : part.type === 'FormattedResource' + ? format(resource, part.formatter, false) + : part.value ) ).then((values) => values.map((value) => value ?? '')); @@ -101,8 +101,8 @@ export function WebLinkField({ typeof definition === 'object' ? definition.description : typeof webLink === 'object' - ? webLink.name - : webLink + ? webLink.name + : webLink } className="max-h-[theme(spacing.5)] max-w-[theme(spacing.10)]" src={getIcon(icon) ?? unknownIcon} diff --git a/specifyweb/frontend/js_src/lib/components/WebLinks/spec.ts b/specifyweb/frontend/js_src/lib/components/WebLinks/spec.ts index bddba8305ff..84b4d5397c3 100644 --- a/specifyweb/frontend/js_src/lib/components/WebLinks/spec.ts +++ b/specifyweb/frontend/js_src/lib/components/WebLinks/spec.ts @@ -176,16 +176,16 @@ function reconstructWeblink( title: parameter.field.map(({ label }) => label).join(' > '), } : parameter.type === 'ThisField' - ? { - name: 'this', - title: 'This', - } - : parameter.type === 'FormattedResource' - ? { - name: `${formatter}${parameter.formatter}`, - title: parameter.formatter, - } - : parameter.value + ? { + name: 'this', + title: 'This', + } + : parameter.type === 'FormattedResource' + ? { + name: `${formatter}${parameter.formatter}`, + title: parameter.formatter, + } + : parameter.value ); return { url: augmented diff --git a/specifyweb/frontend/js_src/lib/components/WorkBench/CellMeta.ts b/specifyweb/frontend/js_src/lib/components/WorkBench/CellMeta.ts index b83586c3f72..b9796d5d2a0 100644 --- a/specifyweb/frontend/js_src/lib/components/WorkBench/CellMeta.ts +++ b/specifyweb/frontend/js_src/lib/components/WorkBench/CellMeta.ts @@ -35,7 +35,7 @@ export type WbMetaArray = [ isModified: boolean, isSearchResult: boolean, issues: RA, - originalValue: string | undefined + originalValue: string | undefined, ]; const defaultMetaValues = Object.freeze([ diff --git a/specifyweb/frontend/js_src/lib/components/WorkBench/Results.tsx b/specifyweb/frontend/js_src/lib/components/WorkBench/Results.tsx index 1c493dcdd50..8ffb2956a74 100644 --- a/specifyweb/frontend/js_src/lib/components/WorkBench/Results.tsx +++ b/specifyweb/frontend/js_src/lib/components/WorkBench/Results.tsx @@ -89,7 +89,7 @@ export function TableRecordCounts({ readonly sortFunction?: ( value: readonly [ Lowercase, - ValueOf, number>>> + ValueOf, number>>>, ] ) => ValueOf, number>>>; }): JSX.Element { diff --git a/specifyweb/frontend/js_src/lib/components/WorkBench/WbValidation.tsx b/specifyweb/frontend/js_src/lib/components/WorkBench/WbValidation.tsx index b220a90885e..41e1f0b7170 100644 --- a/specifyweb/frontend/js_src/lib/components/WorkBench/WbValidation.tsx +++ b/specifyweb/frontend/js_src/lib/components/WorkBench/WbValidation.tsx @@ -34,7 +34,7 @@ type UploadResults = { readonly [ tableName: Lowercase, id: number, - alternativeLabel: string | '' + alternativeLabel: string | '', ] > > diff --git a/specifyweb/frontend/js_src/lib/declarations.d.ts b/specifyweb/frontend/js_src/lib/declarations.d.ts index 3d2849254fa..9918987a89c 100644 --- a/specifyweb/frontend/js_src/lib/declarations.d.ts +++ b/specifyweb/frontend/js_src/lib/declarations.d.ts @@ -58,7 +58,7 @@ declare global { object: DICTIONARY ): [ keyof DICTIONARY extends number ? string : string & keyof DICTIONARY, - ValueOf + ValueOf, ][]; // Array diff --git a/specifyweb/frontend/js_src/lib/hooks/store.tsx b/specifyweb/frontend/js_src/lib/hooks/store.tsx index 1503d641299..f6c8af2de36 100644 --- a/specifyweb/frontend/js_src/lib/hooks/store.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/store.tsx @@ -42,7 +42,7 @@ type Store< BUCKETS extends Record< number | string, Record - > + >, > = { readonly [BUCKET_NAME in keyof BUCKETS]: { readonly listeners: readonly (() => void)[]; @@ -63,7 +63,7 @@ const store: Store = {}; */ export function useStore< BUCKET_NAME extends keyof Buckets, - ID extends keyof Buckets[BUCKET_NAME] + ID extends keyof Buckets[BUCKET_NAME], >( callback: (id: ID) => Promise, deleteCallback: ( diff --git a/specifyweb/frontend/js_src/lib/hooks/useBooleanState.tsx b/specifyweb/frontend/js_src/lib/hooks/useBooleanState.tsx index 0dc9ef0a3bb..02258d64a8a 100644 --- a/specifyweb/frontend/js_src/lib/hooks/useBooleanState.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/useBooleanState.tsx @@ -42,7 +42,7 @@ export function useBooleanState( state: boolean, enable: () => void, disable: () => void, - toggle: () => void + toggle: () => void, ] > { const [state, setState] = useTriggerState(value); diff --git a/specifyweb/frontend/js_src/lib/hooks/useCachedState.tsx b/specifyweb/frontend/js_src/lib/hooks/useCachedState.tsx index 7de0137a666..797bec2547c 100644 --- a/specifyweb/frontend/js_src/lib/hooks/useCachedState.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/useCachedState.tsx @@ -18,7 +18,7 @@ import type { GetOrSet } from '../utils/types'; */ export function useCachedState< CATEGORY extends keyof CacheDefinitions, - KEY extends string & keyof CacheDefinitions[CATEGORY] + KEY extends string & keyof CacheDefinitions[CATEGORY], >( category: CATEGORY, key: KEY diff --git a/specifyweb/frontend/js_src/lib/hooks/useCollection.tsx b/specifyweb/frontend/js_src/lib/hooks/useCollection.tsx index 4466a47e8f9..2ac9bff2452 100644 --- a/specifyweb/frontend/js_src/lib/hooks/useCollection.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/useCollection.tsx @@ -27,7 +27,7 @@ export function useCollection({ ...GetOrSet | false | undefined>, ( filters?: CollectionFetchFilters - ) => Promise | undefined> + ) => Promise | undefined>, ] { const [collection, setCollection] = useAsyncState< Collection | false | undefined diff --git a/specifyweb/frontend/js_src/lib/hooks/useResourceValue.tsx b/specifyweb/frontend/js_src/lib/hooks/useResourceValue.tsx index e7ecea5689c..7d7e3e64661 100644 --- a/specifyweb/frontend/js_src/lib/hooks/useResourceValue.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/useResourceValue.tsx @@ -45,7 +45,7 @@ import { useValidation } from './useValidation'; */ export function useResourceValue< T extends boolean | number | string | null, - INPUT extends Input = HTMLInputElement + INPUT extends Input = HTMLInputElement, >( resource: SpecifyResource | undefined, // If field is undefined, this hook behaves pretty much like useValidation() @@ -125,12 +125,13 @@ export function useResourceValue< field?.isRelationship === true && newValue === '' ? null : ['checkbox', 'date'].includes(parser.type ?? '') || reportErrors - ? parsedValue - : newValue; + ? parsedValue + : newValue; setValue( (parser.type === 'number' && reportErrors - ? f.parseFloat(parser?.printFormatter?.(parsedValue, parser) ?? '') ?? - parsedValue + ? (f.parseFloat( + parser?.printFormatter?.(parsedValue, parser) ?? '' + ) ?? parsedValue) : formattedValue) as T ); if (field === undefined) return; @@ -223,9 +224,9 @@ export function useResourceValue< resource.set( field.name, (parser.type === 'date' - ? getDateInputValue( + ? (getDateInputValue( parseAnyDate(parser.value?.toString() ?? '') ?? new Date() - ) ?? new Date() + ) ?? new Date()) : parser.value) as never, { silent: true } ); diff --git a/specifyweb/frontend/js_src/lib/hooks/useSerializedCollection.tsx b/specifyweb/frontend/js_src/lib/hooks/useSerializedCollection.tsx index 1cc18d7c584..594f5b698f6 100644 --- a/specifyweb/frontend/js_src/lib/hooks/useSerializedCollection.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/useSerializedCollection.tsx @@ -15,7 +15,7 @@ export function useSerializedCollection( ): readonly [ SerializedCollection | undefined, GetOrSet | undefined>[1], - () => Promise + () => Promise, ] { const fetchRef = React.useRef< Promise | undefined> | undefined diff --git a/specifyweb/frontend/js_src/lib/localization/schema-localization/traversal.ts b/specifyweb/frontend/js_src/lib/localization/schema-localization/traversal.ts index 03fbf068020..87b1c96ab58 100644 --- a/specifyweb/frontend/js_src/lib/localization/schema-localization/traversal.ts +++ b/specifyweb/frontend/js_src/lib/localization/schema-localization/traversal.ts @@ -18,8 +18,8 @@ export const traverseSchema = ( typeNode?.tagName === 'names' ? 'name' : typeNode?.tagName === 'descs' - ? 'description' - : undefined; + ? 'description' + : undefined; if (type === undefined) return typeNode; // Get field name and table name @@ -87,7 +87,8 @@ const traverseParent = ( toParsedNode( traverseDom([node], (path, node) => { // Check we are in a text node - const text = typeof node.text === 'string' ? node.text?.trim() ?? '' : ''; + const text = + typeof node.text === 'string' ? (node.text?.trim() ?? '') : ''; if (text === '' || path.at(-1)?.tagName !== 'text') return node; // Reconstruct weblate language code diff --git a/specifyweb/frontend/js_src/lib/localization/schema-localization/xml.ts b/specifyweb/frontend/js_src/lib/localization/schema-localization/xml.ts index 1bed5408307..1d9a1f169bb 100644 --- a/specifyweb/frontend/js_src/lib/localization/schema-localization/xml.ts +++ b/specifyweb/frontend/js_src/lib/localization/schema-localization/xml.ts @@ -74,7 +74,7 @@ export const toUnparsedNode = (node: ParsedNode): ParsedDom[number] => ...(typeof node.tagName === 'string' ? { [node.tagName]: node.children } : {}), - } as ParsedDom[number]); + }) as ParsedDom[number]; /** * It's important to use the same setting for parser and builder diff --git a/specifyweb/frontend/js_src/lib/localization/utils/config.ts b/specifyweb/frontend/js_src/lib/localization/utils/config.ts index a5f44d03a62..2d0cc44eb38 100644 --- a/specifyweb/frontend/js_src/lib/localization/utils/config.ts +++ b/specifyweb/frontend/js_src/lib/localization/utils/config.ts @@ -53,7 +53,7 @@ export const devLanguages = { double: 'Double', }; -export type Language = typeof languages[number]; +export type Language = (typeof languages)[number]; export const DEFAULT_LANGUAGE = 'en-us'; diff --git a/specifyweb/frontend/js_src/lib/localization/utils/index.tsx b/specifyweb/frontend/js_src/lib/localization/utils/index.tsx index cb416491021..235ac9c9259 100644 --- a/specifyweb/frontend/js_src/lib/localization/utils/index.tsx +++ b/specifyweb/frontend/js_src/lib/localization/utils/index.tsx @@ -17,7 +17,7 @@ import type { Language } from './config'; import { DEFAULT_LANGUAGE, devLanguage, LANGUAGE } from './config'; export const localizationMetaKeys = ['comment'] as const; -type MetaKeys = typeof localizationMetaKeys[number]; +type MetaKeys = (typeof localizationMetaKeys)[number]; export type LocalizationEntry = Partial> & RR; export type LocalizationDictionary = IR; diff --git a/specifyweb/frontend/js_src/lib/localization/utils/sync.ts b/specifyweb/frontend/js_src/lib/localization/utils/sync.ts index a2164fa0aba..47e0615f784 100644 --- a/specifyweb/frontend/js_src/lib/localization/utils/sync.ts +++ b/specifyweb/frontend/js_src/lib/localization/utils/sync.ts @@ -146,7 +146,7 @@ const mergeSpecs = ( weblate?.comments?.[key as 'flag'] || '', ]) - ) as typeof local['comments'], + ) as (typeof local)['comments'], }, ]; }) diff --git a/specifyweb/frontend/js_src/lib/localization/utils/validateWeblate.ts b/specifyweb/frontend/js_src/lib/localization/utils/validateWeblate.ts index 7ddc425a9f1..17322c1f9da 100644 --- a/specifyweb/frontend/js_src/lib/localization/utils/validateWeblate.ts +++ b/specifyweb/frontend/js_src/lib/localization/utils/validateWeblate.ts @@ -81,8 +81,8 @@ export const getComponentKind = ( ignoredComponents.has(slug) ? undefined : slug.startsWith(schemaLocalizationName) - ? 'schema' - : 'userInterface'; + ? 'schema' + : 'userInterface'; function getToken(): string { const key = process.env.WEBLATE_API_TOKEN; diff --git a/specifyweb/frontend/js_src/lib/tests/reactUtils.tsx b/specifyweb/frontend/js_src/lib/tests/reactUtils.tsx index 2fd880f27ad..264db51f6aa 100644 --- a/specifyweb/frontend/js_src/lib/tests/reactUtils.tsx +++ b/specifyweb/frontend/js_src/lib/tests/reactUtils.tsx @@ -18,7 +18,7 @@ import type { IR } from '../utils/types'; export const mount = < Q extends Queries = typeof queries, CONTAINER extends DocumentFragment | Element = HTMLElement, - BASE_ELEMENT extends DocumentFragment | Element = CONTAINER + BASE_ELEMENT extends DocumentFragment | Element = CONTAINER, >( ui: React.ReactElement, options: RenderOptions = {} diff --git a/specifyweb/frontend/js_src/lib/tests/testBusinessRules.js b/specifyweb/frontend/js_src/lib/tests/testBusinessRules.js index 275205d2fa7..eaea988ef78 100644 --- a/specifyweb/frontend/js_src/lib/tests/testBusinessRules.js +++ b/specifyweb/frontend/js_src/lib/tests/testBusinessRules.js @@ -567,4 +567,4 @@ ); }; }); -}.call(this)); +}).call(this); diff --git a/specifyweb/frontend/js_src/lib/tests/testForms.js b/specifyweb/frontend/js_src/lib/tests/testForms.js index 6f493ba702c..546c3ca385a 100644 --- a/specifyweb/frontend/js_src/lib/tests/testForms.js +++ b/specifyweb/frontend/js_src/lib/tests/testForms.js @@ -326,28 +326,28 @@ define([ module('specifyform field text/dsptextfield/formattedtext/label'); _([true, false]).each(function (doingFormTable) { - _(['text', 'dsptextfield', 'formattedtext', 'label']).each(function ( - uitype - ) { - var node = - ''; - test(node + ' doingFormTable: ' + doingFormTable, function () { - var result = instProcessCell(doingFormTable, node); - equal(result.children().length, 1, 'only one element'); - var control = result.find('.specify-field'); - ok(control.is('input[type="text"]'), 'control is text input'); - if (uitype === 'formattedtext') - ok( - control.hasClass('specify-formattedtext'), - 'has formattedtext class' + _(['text', 'dsptextfield', 'formattedtext', 'label']).each( + function (uitype) { + var node = + ''; + test(node + ' doingFormTable: ' + doingFormTable, function () { + var result = instProcessCell(doingFormTable, node); + equal(result.children().length, 1, 'only one element'); + var control = result.find('.specify-field'); + ok(control.is('input[type="text"]'), 'control is text input'); + if (uitype === 'formattedtext') + ok( + control.hasClass('specify-formattedtext'), + 'has formattedtext class' + ); + equal( + control.prop('readonly'), + doingFormTable || uitype === 'dsptextfield' || uitype === 'label', + 'readonly if doing form table or dsptextfield or label' ); - equal( - control.prop('readonly'), - doingFormTable || uitype === 'dsptextfield' || uitype === 'label', - 'readonly if doing form table or dsptextfield or label' - ); - }); - }); + }); + } + ); }); module('specifyform field plugin'); diff --git a/specifyweb/frontend/js_src/lib/utils/ajax/helpers.ts b/specifyweb/frontend/js_src/lib/utils/ajax/helpers.ts index bf0cdd56a14..246421a1d95 100644 --- a/specifyweb/frontend/js_src/lib/utils/ajax/helpers.ts +++ b/specifyweb/frontend/js_src/lib/utils/ajax/helpers.ts @@ -44,10 +44,10 @@ export function formData( Array.isArray(value) ? JSON.stringify(value) : typeof value === 'number' - ? value.toString() - : typeof value === 'boolean' - ? value.toString() - : value + ? value.toString() + : typeof value === 'boolean' + ? value.toString() + : value ) ); return formData; diff --git a/specifyweb/frontend/js_src/lib/utils/cache/definitions.ts b/specifyweb/frontend/js_src/lib/utils/cache/definitions.ts index 59a6c0062a3..19a0377c69a 100644 --- a/specifyweb/frontend/js_src/lib/utils/cache/definitions.ts +++ b/specifyweb/frontend/js_src/lib/utils/cache/definitions.ts @@ -77,22 +77,22 @@ export type CacheDefinitions = { } & { readonly [key in `focusPath${AnyTree['tableName']}`]: RA; } & { - readonly /** Collapsed ranks in a given tree */ - [key in `collapsedRanks${AnyTree['tableName']}`]: RA; + /** Collapsed ranks in a given tree */ + readonly [key in `collapsedRanks${AnyTree['tableName']}`]: RA; } & { - readonly /** Open nodes in a given tree */ - [key in `conformations${AnyTree['tableName']}`]: Conformations; + /** Open nodes in a given tree */ + readonly [key in `conformations${AnyTree['tableName']}`]: Conformations; } & { readonly hideEmptyNodes: boolean; readonly isSplit: boolean; readonly isHorizontal: boolean; }; readonly workBenchSortConfig: { - readonly /** + /** * WorkBench column sort setting in a given dataset * {Collection ID}_{Dataset ID} */ - [key in `${number}_${number}`]: RA< + readonly [key in `${number}_${number}`]: RA< Pick & { readonly physicalCol: number; } @@ -151,7 +151,7 @@ export type CacheDefinitions = { readonly filters: AppResourceFilters; readonly showHiddenTables: boolean; }; - readonly pageSizes: RR; + readonly pageSizes: RR; readonly formEditor: { readonly layout: 'horizontal' | 'vertical'; }; diff --git a/specifyweb/frontend/js_src/lib/utils/cache/index.ts b/specifyweb/frontend/js_src/lib/utils/cache/index.ts index f1a0d685c81..3d9592da8a3 100644 --- a/specifyweb/frontend/js_src/lib/utils/cache/index.ts +++ b/specifyweb/frontend/js_src/lib/utils/cache/index.ts @@ -87,7 +87,7 @@ function fetchBucket(formattedKey: string): void { */ export const getCache = < CATEGORY extends string & keyof CacheDefinitions, - KEY extends string & keyof CacheDefinitions[CATEGORY] + KEY extends string & keyof CacheDefinitions[CATEGORY], >( category: CATEGORY, key: KEY @@ -116,7 +116,7 @@ function genericGet( export const setCache = < CATEGORY extends string & keyof CacheDefinitions, - KEY extends string & keyof CacheDefinitions[CATEGORY] + KEY extends string & keyof CacheDefinitions[CATEGORY], >( category: CATEGORY, key: KEY, diff --git a/specifyweb/frontend/js_src/lib/utils/parser/definitions.ts b/specifyweb/frontend/js_src/lib/utils/parser/definitions.ts index dfde5e4e104..93bd96ed913 100644 --- a/specifyweb/frontend/js_src/lib/utils/parser/definitions.ts +++ b/specifyweb/frontend/js_src/lib/utils/parser/definitions.ts @@ -73,9 +73,9 @@ export type Parser = Partial<{ * Format a value before validating it. Formatters are applied in the order * they are defined */ - readonly formatters: RA; + readonly formatters: RA<(typeof formatter)[string]>; // Validate the value - readonly validators: RA; + readonly validators: RA<(typeof validators)[string]>; // Format the value after formatting it readonly parser: (value: unknown) => unknown; // Format the value for use in read only contexts @@ -91,7 +91,7 @@ export type Parser = Partial<{ const numberPrintFormatter = (value: unknown, { step }: Parser): string => typeof value === 'number' && typeof step === 'number' && step > 0 ? f.round(value, step).toString() - : (value as number)?.toString() ?? ''; + : ((value as number)?.toString() ?? ''); type ExtendedJavaType = JavaType | 'day' | 'month' | 'year'; @@ -116,8 +116,8 @@ export const parsers = f.store( value === undefined ? '' : Boolean(value) - ? queryText.yes() - : commonText.no(), + ? queryText.yes() + : commonText.no(), value: false, }, diff --git a/specifyweb/frontend/js_src/lib/utils/types.ts b/specifyweb/frontend/js_src/lib/utils/types.ts index 90cef29f30b..ba056608fee 100644 --- a/specifyweb/frontend/js_src/lib/utils/types.ts +++ b/specifyweb/frontend/js_src/lib/utils/types.ts @@ -17,7 +17,7 @@ export type RA = readonly V[]; export type GetSet = readonly [T, (value: T) => void]; export type GetOrSet = readonly [ T, - (value: T | ((oldValue: T) => T)) => void + (value: T | ((oldValue: T) => T)) => void, ]; export type ValueOf = T[keyof T]; @@ -48,7 +48,7 @@ export const filterArray = (array: RA): RA => /** Make some keys on a record optional */ export type PartialBy< RECORD extends IR, - OPTIONAL_KEYS extends keyof RECORD + OPTIONAL_KEYS extends keyof RECORD, > = Omit & Partial>; /** @@ -58,8 +58,8 @@ export type DeepPartial> = { readonly [KEY in keyof RECORD]?: RECORD[KEY] extends RA> ? RA> : RECORD[KEY] extends IR - ? DeepPartial - : RECORD[KEY]; + ? DeepPartial + : RECORD[KEY]; }; // eslint-disable-next-line functional/prefer-readonly-type @@ -88,7 +88,7 @@ export type Writable = { */ export type RestrictedTuple< VALUES extends string, - RESULT extends RA = readonly [] + RESULT extends RA = readonly [], > = ValueOf<{ readonly [KEY in VALUES]: Exclude extends never ? readonly [KEY, ...RESULT] @@ -126,7 +126,7 @@ export const isFunction = ( */ export function overwriteReadOnly< KEY extends string, - OBJECT extends { readonly [key in KEY]?: unknown } + OBJECT extends { readonly [key in KEY]?: unknown }, >(object: OBJECT, key: KEY, value: unknown): void { // @ts-expect-error Overwriting read-only object[key] = value; diff --git a/specifyweb/frontend/js_src/lib/utils/utils.ts b/specifyweb/frontend/js_src/lib/utils/utils.ts index 976f9752123..d9a2350e8ba 100644 --- a/specifyweb/frontend/js_src/lib/utils/utils.ts +++ b/specifyweb/frontend/js_src/lib/utils/utils.ts @@ -118,7 +118,7 @@ export const spanNumber = /** Get Dictionary's key in a case insensitive way */ export const caseInsensitiveHash = < KEY extends string, - DICTIONARY extends RR + DICTIONARY extends RR, >( dictionary: DICTIONARY, searchKey: @@ -148,8 +148,8 @@ export const sortFunction = return typeof leftValue === 'string' && typeof rightValue === 'string' ? (leftValue.localeCompare(rightValue) as -1 | 0 | 1) : (leftValue ?? 0) > (rightValue ?? 0) - ? 1 - : -1; + ? 1 + : -1; }; /** Like sortFunction, but can sort based on multiple fields */ @@ -182,8 +182,8 @@ export const multiSortFunction = return typeof leftValue === 'string' && typeof rightValue === 'string' ? (leftValue.localeCompare(rightValue) as -1 | 0 | 1) : leftValue > rightValue - ? 1 - : -1; + ? 1 + : -1; } return 0; }; @@ -203,7 +203,7 @@ export const split = ( .reduce< readonly [ left: RA, - right: RA + right: RA, ] >( ([left, right], [item, isRight]) => [ @@ -251,7 +251,7 @@ export function mappedFind( */ export function removeKey< DICTIONARY extends IR, - OMIT extends keyof DICTIONARY + OMIT extends keyof DICTIONARY, >(object: DICTIONARY, ...toOmit: RA): Omit { if (toOmit.length === 1) { const { [toOmit[0]]: _, ...newObject } = object; @@ -322,13 +322,13 @@ export const moveItem = ( ...array.slice(index + 1), ] : index + 1 >= array.length - ? array - : [ - ...array.slice(0, index), - array[index + 1], - array[index], - ...array.slice(index + 2), - ]; + ? array + : [ + ...array.slice(0, index), + array[index + 1], + array[index], + ...array.slice(index + 2), + ]; /** Creates a new object with a given key replaced */ export const replaceKey = >( @@ -366,8 +366,8 @@ export const keysToLowerCase = >( : (value as KeysToLowerCase) ) : typeof value === 'object' && value !== null - ? keysToLowerCase(value as IR) - : value, + ? keysToLowerCase(value as IR) + : value, ]) ) as unknown as KeysToLowerCase; diff --git a/specifyweb/frontend/locale/README.md b/specifyweb/frontend/locale/README.md index 26d6412ee69..f4244390096 100644 --- a/specifyweb/frontend/locale/README.md +++ b/specifyweb/frontend/locale/README.md @@ -5,9 +5,9 @@ file that contains the `msgid` and `msgstr` for the strings used across the back-end files. -According to the convention, `msgid` and `msgstr` have the same -value for the English language. All additional languages will use the same -`msgid`, but change `msgstr` to a needed value. +According to the convention, `msgid` and `msgstr` have the same value for the +English language. All additional languages will use the same `msgid`, but change +`msgstr` to a needed value. Back-end files can mark strings as translatable by enclosing the string within the `_` function. @@ -30,25 +30,23 @@ After adding new translatable strings, run the following command from inside the If you have multiple locales, specify the locale name of each. Example: `-l en_US -l ru_RU -l ca`. -Later, in production, run the following command from inside the -`specifyweb` directory to compile the strings into an optimized `.mo` binary -file: +Later, in production, run the following command from inside the `specifyweb` +directory to compile the strings into an optimized `.mo` binary file: ```bash ../ve/bin/python ../manage.py compilemessages ``` -[Here is the explanation](https://stackoverflow.com/a/56024182/8584605) for -why that has to be done from inside the `specifyweb` directory. +[Here is the explanation](https://stackoverflow.com/a/56024182/8584605) for why +that has to be done from inside the `specifyweb` directory. ## Adding new languages Add `(langauge_code, langauge_label)` tuple to the `LANGUAGES` array in `./specifyweb/settings/__init__.py`. Then run the `makemessages` command mentioned above, but add the `-l ` argument to it. This would -create a directory for the new language with a -`.po` file inside. Then, proceed fill in the `msgstr` lines with the -translated values. +create a directory for the new language with a `.po` file inside. Then, proceed +fill in the `msgstr` lines with the translated values. NOTE: Keep in mind the difference between language codes and locale names. [More info](https://docs.djangoproject.com/en/3.1/topics/i18n/#term-locale-name) @@ -69,7 +67,6 @@ NOTE: Keep in mind the difference between language codes and locale names. ).map((match, index) => Array.from(match).slice(1).find(Boolean).trim()); ``` - ## Additional resources - [Comprehensive tutorial](https://lokalise.com/blog/advanced-django-internationalization/) diff --git a/specifyweb/hibernateboolsbackend/readme.md b/specifyweb/hibernateboolsbackend/readme.md index 6882d5762c4..a73d7c1332a 100644 --- a/specifyweb/hibernateboolsbackend/readme.md +++ b/specifyweb/hibernateboolsbackend/readme.md @@ -1,5 +1,4 @@ # HibernateBoolsBackend -Enhances the standard django MySQL backend with the ability -to understand the bit columns used by Hibernate to store -boolean values. +Enhances the standard django MySQL backend with the ability to understand the +bit columns used by Hibernate to store boolean values. diff --git a/specifyweb/report_runner/templates/report_template.xml b/specifyweb/report_runner/templates/report_template.xml index da4f8018923..2154a8110a9 100644 --- a/specifyweb/report_runner/templates/report_template.xml +++ b/specifyweb/report_runner/templates/report_template.xml @@ -1,65 +1,67 @@ - - + + + name="{{name}}" + columnCount="1" + printOrder="Vertical" + orientation="Portrait" + pageWidth="595" + pageHeight="842" + columnWidth="535" + columnSpacing="0" + leftMargin="30" + rightMargin="30" + topMargin="20" + bottomMargin="20" + whenNoDataType="NoPages" + isTitleNewPage="false" + isSummaryNewPage="false" +> {% for f in fields %} - + {% endfor %} - - + + - + - <band height="50" isSplitAllowed="true" > + <band height="50" isSplitAllowed="true"> </band> - + - + - + - + - + - + - + diff --git a/specifyweb/workbench/templates/upload_new.html b/specifyweb/workbench/templates/upload_new.html index ba3289be892..84d183e2229 100644 --- a/specifyweb/workbench/templates/upload_new.html +++ b/specifyweb/workbench/templates/upload_new.html @@ -1,5 +1,4 @@
- {% csrf_token %} - {{ form }} - + {% csrf_token %} {{ form }} +
diff --git a/specifyweb/workbench/templates/validate_row.html b/specifyweb/workbench/templates/validate_row.html index ba3289be892..84d183e2229 100644 --- a/specifyweb/workbench/templates/validate_row.html +++ b/specifyweb/workbench/templates/validate_row.html @@ -1,5 +1,4 @@
- {% csrf_token %} - {{ form }} - + {% csrf_token %} {{ form }} +