diff --git a/specifyweb/frontend/js_src/lib/components/Attachments/RecordSetAttachment.tsx b/specifyweb/frontend/js_src/lib/components/Attachments/RecordSetAttachment.tsx index 597e4ed3665..c41f2c2da3e 100644 --- a/specifyweb/frontend/js_src/lib/components/Attachments/RecordSetAttachment.tsx +++ b/specifyweb/frontend/js_src/lib/components/Attachments/RecordSetAttachment.tsx @@ -109,7 +109,8 @@ export function RecordSetAttachments({ const isComplete = fetchedCount.current === recordCount; - const [showCreateRecordSetDialog, setShowCreateRecordSetDialog] = React.useState(false); + const [showCreateRecordSetDialog, setShowCreateRecordSetDialog] = + React.useState(false); return ( <> @@ -133,16 +134,17 @@ export function RecordSetAttachments({ - (recordSetId === undefined && !isComplete) ? - setShowCreateRecordSetDialog(true) - : - loading( - downloadAllAttachments( - (recordSetId !== undefined && !isComplete) ? [] : attachmentsRef.current?.attachments ?? [], - name, - recordSetId, - ) - ) + recordSetId === undefined && !isComplete + ? setShowCreateRecordSetDialog(true) + : loading( + downloadAllAttachments( + recordSetId !== undefined && !isComplete + ? [] + : (attachmentsRef.current?.attachments ?? []), + name, + recordSetId + ) + ) } > {attachmentsText.downloadAll()} @@ -157,15 +159,15 @@ export function RecordSetAttachments({ header={ attachmentsRef.current?.attachments === undefined ? attachmentsText.attachments() - : (isComplete ? - commonText.countLine({ - resource: attachmentsText.attachments(), - count: attachmentsRef.current.attachments.length - }) : - commonText.countLineOrMore({ - resource: attachmentsText.attachments(), - count: attachmentsRef.current.attachments.length - })) + : isComplete + ? commonText.countLine({ + resource: attachmentsText.attachments(), + count: attachmentsRef.current.attachments.length, + }) + : commonText.countLineOrMore({ + resource: attachmentsText.attachments(), + count: attachmentsRef.current.attachments.length, + }) } onClose={handleHideAttachments} > @@ -215,13 +217,11 @@ function CreateRecordSetDialog({ }): JSX.Element { return ( {commonText.close()} - } + buttons={{commonText.close()}} header={attachmentsText.downloadAll()} onClose={onClose} > {attachmentsText.createRecordSetToDownloadAll()} ); -} \ No newline at end of file +} diff --git a/specifyweb/frontend/js_src/lib/components/BatchEdit/index.tsx b/specifyweb/frontend/js_src/lib/components/BatchEdit/index.tsx index 31b410f3be4..59cb682763b 100644 --- a/specifyweb/frontend/js_src/lib/components/BatchEdit/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/BatchEdit/index.tsx @@ -247,7 +247,6 @@ const containsSystemTables = (queryFieldSpec: QueryFieldSpec) => { return Boolean(baseIsBlocked || pathHasBlockedSystem); }; - const hasHierarchyBaseTable = (queryFieldSpec: QueryFieldSpec) => Object.keys(schema.domainLevelIds).includes( queryFieldSpec.baseTable.name.toLowerCase() as 'collection' diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts b/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts index f7581eb2b30..868b11dac2a 100644 --- a/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts +++ b/specifyweb/frontend/js_src/lib/components/DataModel/businessRules.ts @@ -7,7 +7,11 @@ import { softFail } from '../Errors/Crash'; import { isTreeResource } from '../InitialContext/treeRanks'; import type { BusinessRuleDefs } from './businessRuleDefs'; import { businessRuleDefs } from './businessRuleDefs'; -import { backboneFieldSeparator, backendFilter, djangoLookupSeparator } from './helpers'; +import { + backboneFieldSeparator, + backendFilter, + djangoLookupSeparator, +} from './helpers'; import type { AnySchema, AnyTree, @@ -316,10 +320,7 @@ export class BusinessRuleManager { ) ); - const stringValuesAreEqual = ( - left: string, - right: string - ): boolean => + const stringValuesAreEqual = (left: string, right: string): boolean => rule.isDatabaseConstraint ? left.localeCompare(right, undefined, { sensitivity: 'accent' }) === 0 : left === right; diff --git a/specifyweb/frontend/js_src/lib/components/Preferences/Renderers.tsx b/specifyweb/frontend/js_src/lib/components/Preferences/Renderers.tsx index 0af5d46b5a2..8266eb3d410 100644 --- a/specifyweb/frontend/js_src/lib/components/Preferences/Renderers.tsx +++ b/specifyweb/frontend/js_src/lib/components/Preferences/Renderers.tsx @@ -24,7 +24,7 @@ import type { RA } from '../../utils/types'; import { Input, Select, Textarea } from '../Atoms/Form'; import { iconClassName } from '../Atoms/Icons'; import { ReadOnlyContext } from '../Core/Contexts'; -import type { AnySchema } from '../DataModel/helperTypes'; +import type { AnySchema, AnyTree } from '../DataModel/helperTypes'; import type { SpecifyTable } from '../DataModel/specifyTable'; import { tables } from '../DataModel/tables'; import type { Collection } from '../DataModel/types'; @@ -33,6 +33,7 @@ import { useMenuItems, useUserTools } from '../Header/menuItemProcessing'; import { AttachmentPicker } from '../Molecules/AttachmentPicker'; import { AutoComplete } from '../Molecules/AutoComplete'; import { ListEdit } from '../Toolbar/ListEdit'; +import { getTreeDefinitions, treeRanksPromise } from '../InitialContext/treeRanks'; import type { PreferenceItem, PreferenceRendererProps } from './types'; import { userPreferences } from './userPreferences'; @@ -378,3 +379,58 @@ export function DefaultPreferenceItemRender({ /> ); } + +type Rank = { readonly rankId: number; readonly name: string }; + +/* + * This grabs the ranks from the API and displays them in a dropdown + * The ranks are sorted in ascending order by `rankId` so they appear in the correct order for the user + */ +export function ThresholdRank({ + value, + onChange, + tableName, +}: PreferenceRendererProps & { + readonly tableName: AnyTree['tableName']; +}): JSX.Element { + const [items, setItems] = React.useState([]); + + React.useEffect(() => { + let isMounted = true; + treeRanksPromise + .then(() => { + const definitions = getTreeDefinitions(tableName); + const activeDefinition = definitions[0]; + /** + * Only expose ranks from the treedef tied to the current discipline. + * Otherwise ranks from unrelated trees leak into the dropdown. + */ + const ranks = activeDefinition?.ranks ?? []; + if (!isMounted) return; + setItems( + ranks + .map(({ rankId, name }) => ({ + rankId, + name, + })) + .sort((rankA, rankB) => rankA.rankId - rankB.rankId) + ); + }) + .catch((error: unknown) => { + console.error('Error fetching ThresholdRank items:', error); + if (isMounted) setItems([]); + }); + return () => { + isMounted = false; + }; + }, [tableName]); + + return ( + + ); +} diff --git a/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx b/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx index 52d5f72b442..37ffc882d70 100644 --- a/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx +++ b/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx @@ -50,6 +50,7 @@ import { defaultFont, FontFamilyPreferenceItem, HeaderItemsPreferenceItem, + ThresholdRank, WelcomePageModePreferenceItem, } from './Renderers'; import type { GenericPreferences, PreferencesVisibilityContext } from './types'; @@ -1474,6 +1475,17 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + rankThreshold: definePref({ + title: preferencesText.rankThreshold(), + description: preferencesText.rankThresholdDescription(), + requiresReload: true, + visible: true, + defaultValue: 0, + renderer: (props) => ( + + ), + container: 'label', + }), }, }, taxon: { @@ -1502,6 +1514,15 @@ export const userPreferenceDefinitions = { defaultValue: true, type: 'java.lang.Boolean', }), + rankThreshold: definePref({ + title: preferencesText.rankThreshold(), + description: preferencesText.rankThresholdDescription(), + requiresReload: true, + visible: true, + defaultValue: 0, + renderer: (props) => , + container: 'label', + }), }, }, storage: { @@ -1523,6 +1544,17 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + rankThreshold: definePref({ + title: preferencesText.rankThreshold(), + description: preferencesText.rankThresholdDescription(), + requiresReload: true, + visible: true, + defaultValue: 0, + renderer: (props) => ( + + ), + container: 'label', + }), }, }, geologicTimePeriod: { @@ -1544,6 +1576,17 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + rankThreshold: definePref({ + title: preferencesText.rankThreshold(), + description: preferencesText.rankThresholdDescription(), + requiresReload: true, + visible: true, + defaultValue: 0, + renderer: (props) => ( + + ), + container: 'label', + }), }, }, lithoStrat: { @@ -1565,6 +1608,17 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + rankThreshold: definePref({ + title: preferencesText.rankThreshold(), + description: preferencesText.rankThresholdDescription(), + requiresReload: true, + visible: true, + defaultValue: 0, + renderer: (props) => ( + + ), + container: 'label', + }), }, }, tectonicUnit: { @@ -1586,6 +1640,17 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + rankThreshold: definePref({ + title: preferencesText.rankThreshold(), + description: preferencesText.rankThresholdDescription(), + requiresReload: true, + visible: true, + defaultValue: 0, + renderer: (props) => ( + + ), + container: 'label', + }), }, }, }, diff --git a/specifyweb/frontend/js_src/lib/components/Preferences/__tests__/ThresholdRank.test.tsx b/specifyweb/frontend/js_src/lib/components/Preferences/__tests__/ThresholdRank.test.tsx new file mode 100644 index 00000000000..0ce4c624967 --- /dev/null +++ b/specifyweb/frontend/js_src/lib/components/Preferences/__tests__/ThresholdRank.test.tsx @@ -0,0 +1,64 @@ +import { render, screen, waitFor } from '@testing-library/react'; +import React from 'react'; + +import { preferencesText } from '../../../localization/preferences'; +import { overrideAjax } from '../../../tests/ajax'; +import { requireContext } from '../../../tests/helpers'; +import * as treeRanks from '../../InitialContext/treeRanks'; +import { ThresholdRank } from '../Renderers'; +import type { PreferenceItem } from '../types'; + +overrideAjax('/context/schema_localization.json', {}); +requireContext(); + +const mockedGetTreeDefinitions = jest.spyOn( + treeRanks, + 'getTreeDefinitions' +); + +describe('ThresholdRank', () => { + beforeEach(() => { + mockedGetTreeDefinitions.mockReset(); + }); + + test('only renders ranks from the active tree definition', async () => { + mockedGetTreeDefinitions.mockReturnValue([ + { + definition: { id: 1 } as any, + ranks: [ + { rankId: 50, name: 'Active Rank B' }, + { rankId: 10, name: 'Active Rank A' }, + ] as any, + }, + { + definition: { id: 2 } as any, + ranks: [{ rankId: 5, name: 'Inactive Rank' }] as any, + }, + ]); + + const definition: PreferenceItem = { + title: preferencesText.rankThreshold(), + requiresReload: false, + visible: true, + defaultValue: 0, + values: [], + }; + render( + + ); + + await waitFor(() => expect(screen.getAllByRole('option')).toHaveLength(3)); + + const labels = screen.getAllByRole('option').map((option) => option.textContent); + expect(labels).toEqual(['None', 'Active Rank A', 'Active Rank B']); + expect(screen.queryByText('Inactive Rank')).not.toBeInTheDocument(); + }); +}); diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx index 6b1402cbf11..b343a725731 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx +++ b/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx @@ -19,7 +19,6 @@ import { idFromUrl } from '../DataModel/resource'; import { deserializeResource } from '../DataModel/serializers'; import { softError } from '../Errors/assert'; import { ResourceView } from '../Forms/ResourceView'; -import { getPref } from '../InitialContext/remotePrefs'; import { hasTablePermission } from '../Permissions/helpers'; import { useHighContrast } from '../Preferences/Hooks'; import { userPreferences } from '../Preferences/userPreferences'; @@ -98,9 +97,12 @@ export function Tree< 'synonymColor' ); - const statsThreshold = getPref( - `TreeEditor.Rank.Threshold.${tableName as 'Geography'}` + const [statsThreshold] = userPreferences.use( + 'treeEditor', + treeToPref[tableName], + 'rankThreshold' ); + const getStats = React.useCallback( async (nodeId: number | 'null', rankId: number): Promise => rankId >= statsThreshold diff --git a/specifyweb/frontend/js_src/lib/localization/preferences.ts b/specifyweb/frontend/js_src/lib/localization/preferences.ts index d6a595fc932..6c81771b8d3 100644 --- a/specifyweb/frontend/js_src/lib/localization/preferences.ts +++ b/specifyweb/frontend/js_src/lib/localization/preferences.ts @@ -128,6 +128,25 @@ export const preferencesText = createDictionary({ 'de-ch': 'Nicht erforderliche Animationen und Übergänge deaktivieren.', 'pt-br': 'Desabilite animações e transições não essenciais.', }, + rankThreshold: { + 'en-us': 'Show object count below', + }, + rankThresholdDescription: { + 'en-us': + 'Show the count of linked Collection Objects for all ranks below this one.', + 'ru-ru': + 'Показывать количество объектов коллекции для всех рангов, включая и ниже этого.', + 'es-es': + 'Mostrar la cantidad de objetos de colección para todos los rangos, incluidos y por debajo de este.', + 'fr-fr': + "Afficher le nombre d'objets de collection pour tous les rangs, y compris et en dessous de celui-ci.", + 'uk-ua': + "Показати кількість об'єктів колекції для всіх рангів, включаючи та нижче цього.", + 'de-ch': + 'Anzahl der Sammlungsobjekte für alle Ränge einschließlich und unterhalb dieses Rangs anzeigen.', + 'pt-br': + 'Mostrar a contagem de Objetos de Coleção para todos os ranks, incluindo e abaixo deste.', + }, reduceTransparency: { 'en-us': 'Reduce transparency', 'ru-ru': 'Уменьшить прозрачность', diff --git a/specifyweb/frontend/js_src/package-lock.json b/specifyweb/frontend/js_src/package-lock.json index 874f6d4c7cc..a25ba029bea 100644 --- a/specifyweb/frontend/js_src/package-lock.json +++ b/specifyweb/frontend/js_src/package-lock.json @@ -100,6 +100,7 @@ "regenerator-runtime": "^0.13.9", "style-loader": "^3.3.4", "tailwindcss": "^3.4.1", + "ts-node": "^10.9.2", "tsx": "^4.19.3", "typedoc": "^0.23.23", "typescript": "4.8.4", @@ -1971,8 +1972,6 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -1985,8 +1984,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -3983,33 +3980,25 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/@types/aria-query": { "version": "4.2.2", @@ -6659,9 +6648,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/crelt": { "version": "1.0.5", @@ -7404,8 +7391,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=0.3.1" } @@ -12063,9 +12048,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -16033,12 +16016,11 @@ "dev": true }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -16082,8 +16064,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true, - "optional": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -16096,8 +16076,6 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=0.4.0" } @@ -16106,9 +16084,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/tsconfig-paths": { "version": "3.14.1", @@ -16586,9 +16562,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.0.1", @@ -17378,8 +17352,6 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=6" } @@ -18606,8 +18578,6 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "optional": true, - "peer": true, "requires": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -18617,8 +18587,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "optional": true, - "peer": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -19877,33 +19845,25 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "@tsconfig/node16": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "@types/aria-query": { "version": "4.2.2", @@ -21886,9 +21846,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "crelt": { "version": "1.0.5" @@ -22371,9 +22329,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "diff-sequences": { "version": "28.1.1", @@ -25735,9 +25691,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "makeerror": { "version": "1.0.12", @@ -28351,12 +28305,10 @@ "dev": true }, "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "optional": true, - "peer": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -28377,25 +28329,19 @@ "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "optional": true, - "peer": true + "dev": true } } }, @@ -28731,9 +28677,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "v8-to-istanbul": { "version": "9.0.1", @@ -29266,9 +29210,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "yocto-queue": { "version": "0.1.0", diff --git a/specifyweb/frontend/js_src/package.json b/specifyweb/frontend/js_src/package.json index 404c36bbad2..33ba472764b 100644 --- a/specifyweb/frontend/js_src/package.json +++ b/specifyweb/frontend/js_src/package.json @@ -120,6 +120,7 @@ "regenerator-runtime": "^0.13.9", "style-loader": "^3.3.4", "tailwindcss": "^3.4.1", + "ts-node": "^10.9.2", "tsx": "^4.19.3", "typedoc": "^0.23.23", "typescript": "4.8.4",