diff --git a/specifyweb/backend/context/data/viewset_5.xml b/specifyweb/backend/context/data/viewset_5.xml index debd4b21ea9..6cda666b2ed 100644 --- a/specifyweb/backend/context/data/viewset_5.xml +++ b/specifyweb/backend/context/data/viewset_5.xml @@ -559,10 +559,6 @@ - - - - @@ -582,10 +578,6 @@ - - - - @@ -608,10 +600,6 @@ - - - - @@ -631,10 +619,6 @@ - - - - @@ -656,10 +640,6 @@ - - - - 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/FormParse/__tests__/index.test.ts b/specifyweb/frontend/js_src/lib/components/FormParse/__tests__/index.test.ts index 77693cf8d0a..859c98374e4 100644 --- a/specifyweb/frontend/js_src/lib/components/FormParse/__tests__/index.test.ts +++ b/specifyweb/frontend/js_src/lib/components/FormParse/__tests__/index.test.ts @@ -7,7 +7,6 @@ import { ensure, localized } from '../../../utils/types'; import { removeKey } from '../../../utils/utils'; import { strictParseXml } from '../../AppResources/parseXml'; import { tables } from '../../DataModel/tables'; -import { getPref } from '../../InitialContext/remotePrefs'; import { formatUrl } from '../../Router/queryString'; import type { SimpleXmlNode } from '../../Syncer/xmlToJson'; import { toSimpleXmlNode, xmlToJson } from '../../Syncer/xmlToJson'; @@ -471,25 +470,7 @@ describe('parseFormDefinition', () => { describe('getColumnDefinitions', () => { requireContext(); - test('can customize the column definition source', () => - expect( - getColumnDefinitions( - toSimpleXmlNode( - xmlToJson( - strictParseXml( - ` - A - B - ` - ) - ) - ) - ) - ).toBe('B')); - - test('fall back to first definition available', () => + test('uses the first column definition available', () => expect( getColumnDefinitions( xml( diff --git a/specifyweb/frontend/js_src/lib/components/FormParse/index.ts b/specifyweb/frontend/js_src/lib/components/FormParse/index.ts index 2ae4158a1fc..c7019c45b6c 100644 --- a/specifyweb/frontend/js_src/lib/components/FormParse/index.ts +++ b/specifyweb/frontend/js_src/lib/components/FormParse/index.ts @@ -34,7 +34,6 @@ import { setLogContext, } from '../Errors/logContext'; import { cacheableUrl } from '../InitialContext'; -import { getPref } from '../InitialContext/remotePrefs'; import { formatUrl } from '../Router/queryString'; import type { SimpleXmlNode } from '../Syncer/xmlToJson'; import { toSimpleXmlNode, xmlToJson } from '../Syncer/xmlToJson'; @@ -532,11 +531,7 @@ export async function parseFormDefinition( } function getColumnDefinitions(viewDefinition: SimpleXmlNode): string { - const definition = - getColumnDefinition( - viewDefinition, - getPref('form.definition.columnSource') - ) ?? getColumnDefinition(viewDefinition, undefined); + const definition = getColumnDefinition(viewDefinition, undefined); // Specify 7 handles forms without column definition fine, so no need to warn for this return definition ?? getParsedAttribute(viewDefinition, 'colDef') ?? ''; } diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/__snapshots__/remotePrefs.test.ts.snap b/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/__snapshots__/remotePrefs.test.ts.snap index 39fc488e115..0ba6373e6e3 100644 --- a/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/__snapshots__/remotePrefs.test.ts.snap +++ b/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/__snapshots__/remotePrefs.test.ts.snap @@ -50,13 +50,7 @@ exports[`fetches and parses remotePrefs correctly 1`] = ` "SubPaneMgr.MaxPanes": "12", "SymbiotaTask.BaseUrlPref": "http\\\\://pinkava.asu.edu/symbiota/sandbox/webservices/dwc/dwcaingesthandler.php", "SymbiotaTask.SHOW_TASK_PREF.fish": "false", - "TaxonTreeEditor.DisplayAuthor": "true", "Testing2": "", - "TreeEditor.Rank.Threshold.Geography": "100", - "TreeEditor.Rank.Threshold.GeologicTimePeriod": "0", - "TreeEditor.Rank.Threshold.LithoStrat": "200", - "TreeEditor.Rank.Threshold.Storage": "200", - "TreeEditor.Rank.Threshold.Taxon": "100", "TreeEditor.RestoreTreeExpansionState": "true", "Treeeditor.SynonymyColor.Geography": "255, 0, 0", "Treeeditor.SynonymyColor.GeologicTimePeriod": "0, 0, 255", diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/remotePrefs.test.ts b/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/remotePrefs.test.ts index c36eb85956d..d545c838da1 100644 --- a/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/remotePrefs.test.ts +++ b/specifyweb/frontend/js_src/lib/components/InitialContext/__tests__/remotePrefs.test.ts @@ -17,8 +17,8 @@ describe('Parsing Remote Prefs', () => { test('parses numeric value', () => expect(getPref('attachment.preview_size')).toBe(123)); test('uses default value if pref is not set', () => - expect(getPref('form.definition.columnSource')).toBe( - remotePrefsDefinitions()['form.definition.columnSource'].defaultValue + expect(getPref('ui.formatting.scrmonthformat')).toBe( + remotePrefsDefinitions()['ui.formatting.scrmonthformat'].defaultValue )); }); diff --git a/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts b/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts index 2574f60f53d..0ab66f5601c 100644 --- a/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts +++ b/specifyweb/frontend/js_src/lib/components/InitialContext/remotePrefs.ts @@ -126,97 +126,6 @@ export const remotePrefsDefinitions = f.store( defaultValue: 'MM/YYYY', formatters: [formatter.trim, formatter.toUpperCase], }, - 'GeologicTimePeriod.treeview_sort_field': { - description: 'Sort order for nodes in the tree viewer', - defaultValue: 'name', - formatters: [formatter.trim], - isLegacy: true, - }, - 'Taxon.treeview_sort_field': { - description: 'Sort order for nodes in the tree viewer', - defaultValue: 'name', - formatters: [formatter.trim], - isLegacy: true, - }, - 'Geography.treeview_sort_field': { - description: 'Sort order for nodes in the tree viewer', - defaultValue: 'name', - formatters: [formatter.trim], - isLegacy: true, - }, - 'LithoStrat.treeview_sort_field': { - description: 'Sort order for nodes in the tree viewer', - defaultValue: 'name', - formatters: [formatter.trim], - isLegacy: true, - }, - 'Storage.treeview_sort_field': { - description: 'Sort order for nodes in the tree viewer', - defaultValue: 'name', - formatters: [formatter.trim], - isLegacy: true, - }, - 'TectonicUnit.treeview_sort_field': { - description: 'Sort order for nodes in the tree viewer', - defaultValue: 'name', - formatters: [formatter.trim], - isLegacy: false, - }, - 'TreeEditor.Rank.Threshold.GeologicTimePeriod': { - description: - 'Show Collection Object count only for nodes with RankID >= than this value', - defaultValue: 99_999, - parser: 'java.lang.Long', - isLegacy: true, - }, - 'TreeEditor.Rank.Threshold.Taxon': { - description: - 'Show Collection Object count only for nodes with RankID >= than this value', - defaultValue: 99_999, - parser: 'java.lang.Long', - isLegacy: true, - }, - 'TreeEditor.Rank.Threshold.Geography': { - description: - 'Show Collection Object count only for nodes with RankID >= than this value', - defaultValue: 99_999, - parser: 'java.lang.Long', - isLegacy: true, - }, - 'TreeEditor.Rank.Threshold.LithoStrat': { - description: - 'Show Collection Object count only for nodes with RankID >= than this value', - defaultValue: 99_999, - parser: 'java.lang.Long', - isLegacy: true, - }, - 'TreeEditor.Rank.Threshold.Storage': { - description: - 'Show Collection Object count only for nodes with RankID >= than this value', - defaultValue: 99_999, - parser: 'java.lang.Long', - isLegacy: true, - }, - 'TreeEditor.Rank.Threshold.TectonicUnit': { - description: - 'Show Collection Object count only for nodes with RankID >= than this value', - defaultValue: 99_999, - parser: 'java.lang.Long', - isLegacy: true, - }, - - /* - * This pref was implemented in Specify 7 in https://github.com/specify/specify7/pull/2818 - * and went through many iterations and changes. - * See the Pull Request for the full context and implementation/design decision. - */ - 'TaxonTreeEditor.DisplayAuthor': { - description: - 'Display Authors of Taxons next to nodes in the Tree Viewer', - defaultValue: false, - parser: 'java.lang.Boolean', - isLegacy: true, - }, 'attachment.is_public_default': { description: 'Whether new Attachments are public by default', defaultValue: true, @@ -242,12 +151,6 @@ export const remotePrefsDefinitions = f.store( parser: 'java.lang.Boolean', isLegacy: true, }, - 'form.definition.columnSource': { - description: 'The platform to use as a source of columns', - defaultValue: 'lnx', - formatter: [formatter.trim], - isLegacy: false, - }, 'sp7.allow_adding_child_to_synonymized_parent.GeologicTimePeriod': { description: 'Allowed to add children to synopsized Geologic Time Period records', diff --git a/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx b/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx index 52d5f72b442..722657bfe27 100644 --- a/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx +++ b/specifyweb/frontend/js_src/lib/components/Preferences/UserDefinitions.tsx @@ -1474,6 +1474,15 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + statsThreshold: definePref({ + title: preferencesText.treeStatsThreshold(), + description: preferencesText.treeStatsThresholdDescription(), + requiresReload: false, + visible: false, + defaultValue: 99_999, + type: 'java.lang.Long', + container: 'label', + }), }, }, taxon: { @@ -1502,6 +1511,15 @@ export const userPreferenceDefinitions = { defaultValue: true, type: 'java.lang.Boolean', }), + statsThreshold: definePref({ + title: preferencesText.treeStatsThreshold(), + description: preferencesText.treeStatsThresholdDescription(), + requiresReload: false, + visible: false, + defaultValue: 99_999, + type: 'java.lang.Long', + container: 'label', + }), }, }, storage: { @@ -1523,6 +1541,15 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + statsThreshold: definePref({ + title: preferencesText.treeStatsThreshold(), + description: preferencesText.treeStatsThresholdDescription(), + requiresReload: false, + visible: false, + defaultValue: 99_999, + type: 'java.lang.Long', + container: 'label', + }), }, }, geologicTimePeriod: { @@ -1544,6 +1571,15 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + statsThreshold: definePref({ + title: preferencesText.treeStatsThreshold(), + description: preferencesText.treeStatsThresholdDescription(), + requiresReload: false, + visible: false, + defaultValue: 99_999, + type: 'java.lang.Long', + container: 'label', + }), }, }, lithoStrat: { @@ -1565,6 +1601,15 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + statsThreshold: definePref({ + title: preferencesText.treeStatsThreshold(), + description: preferencesText.treeStatsThresholdDescription(), + requiresReload: false, + visible: false, + defaultValue: 99_999, + type: 'java.lang.Long', + container: 'label', + }), }, }, tectonicUnit: { @@ -1586,6 +1631,15 @@ export const userPreferenceDefinitions = { renderer: ColorPickerPreferenceItem, container: 'label', }), + statsThreshold: definePref({ + title: preferencesText.treeStatsThreshold(), + description: preferencesText.treeStatsThresholdDescription(), + requiresReload: false, + visible: false, + defaultValue: 99_999, + type: 'java.lang.Long', + container: 'label', + }), }, }, }, diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/Tree.tsx index 6b1402cbf11..6ebf98e5ab4 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,8 +97,10 @@ export function Tree< 'synonymColor' ); - const statsThreshold = getPref( - `TreeEditor.Rank.Threshold.${tableName as 'Geography'}` + const [statsThreshold] = userPreferences.use( + 'treeEditor', + treeToPref[tableName], + 'statsThreshold' ); const getStats = React.useCallback( async (nodeId: number | 'null', rankId: number): Promise => diff --git a/specifyweb/frontend/js_src/lib/components/TreeView/index.tsx b/specifyweb/frontend/js_src/lib/components/TreeView/index.tsx index d068e22be85..8e8fbd15a26 100644 --- a/specifyweb/frontend/js_src/lib/components/TreeView/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/TreeView/index.tsx @@ -27,7 +27,6 @@ import type { SpecifyTable } from '../DataModel/specifyTable'; import { genericTables, getTable } from '../DataModel/tables'; import { ErrorBoundary } from '../Errors/ErrorBoundary'; import { useMenuItem } from '../Header/MenuContext'; -import { getPref } from '../InitialContext/remotePrefs'; import type { TreeInformation } from '../InitialContext/treeRanks'; import { getTreeDefinitions, @@ -155,8 +154,12 @@ function TreeView({ useTitle(treeText.treeViewTitle({ treeName: table.label })); - // Node sort order - const sortField = getPref(`${tableName as 'Geography'}.treeview_sort_field`); + // Node sort order and author display are user preferences + const sortField = userPreferences.get( + 'treeEditor', + 'behavior', + 'orderByField' + ); const includeAuthor = userPreferences.get( 'treeEditor', @@ -175,7 +178,7 @@ function TreeView({ includeAuthor: includeAuthor.toString(), }) ), - [baseUrl, sortField] + [baseUrl, includeAuthor, sortField] ); const [rows, setRows] = useAsyncState>( diff --git a/specifyweb/frontend/js_src/lib/localization/preferences.ts b/specifyweb/frontend/js_src/lib/localization/preferences.ts index d6a595fc932..7314c2cf328 100644 --- a/specifyweb/frontend/js_src/lib/localization/preferences.ts +++ b/specifyweb/frontend/js_src/lib/localization/preferences.ts @@ -1443,6 +1443,31 @@ export const preferencesText = createDictionary({ 'ru-ru': 'Сортировать по полю', 'uk-ua': 'Сортувати за полем', }, + treeStatsThreshold: { + 'en-us': 'Minimum rank for Collection Object counts', + 'ru-ru': 'Минимальный ранг для подсчета коллекционных объектов', + 'es-es': 'Rango mínimo para recuentos de objetos de colección', + 'fr-fr': 'Rang minimal pour les comptes des objets de collection', + 'uk-ua': 'Мінімальний ранг для підрахунку колекційних об’єктів', + 'de-ch': 'Minimaler Rang für Sammlungsobjektzählungen', + 'pt-br': 'Classificação mínima para contagens de objetos de coleção', + }, + treeStatsThresholdDescription: { + 'en-us': + 'Show Collection Object counts only for nodes with RankID greater than or equal to this value.', + 'ru-ru': + 'Показывать количество коллекционных объектов только для узлов с RankID больше или равным этому значению.', + 'es-es': + 'Mostrar recuentos de objetos de colección solo para nodos con RankID mayor o igual que este valor.', + 'fr-fr': + 'Afficher les comptes d’objets de collection uniquement pour les nœuds dont le RankID est supérieur ou égal à cette valeur.', + 'uk-ua': + 'Показувати кількість колекційних об’єктів лише для вузлів з RankID, що дорівнює або перевищує це значення.', + 'de-ch': + 'Zeige Zählungen von Sammlungsobjekten nur für Knoten mit einem RankID grösser oder gleich diesem Wert.', + 'pt-br': + 'Mostrar contagens de objetos de coleção apenas para nós com RankID maior ou igual a este valor.', + }, lineWrap: { 'en-us': 'Line wrap', 'ru-ru': 'Перенос строки', diff --git a/specifyweb/frontend/js_src/lib/tests/ajax/static/context/remoteprefs.properties b/specifyweb/frontend/js_src/lib/tests/ajax/static/context/remoteprefs.properties index 39b5e42ad97..e5c9ecce3df 100644 --- a/specifyweb/frontend/js_src/lib/tests/ajax/static/context/remoteprefs.properties +++ b/specifyweb/frontend/js_src/lib/tests/ajax/static/context/remoteprefs.properties @@ -15,7 +15,6 @@ Testing Treeeditor.TreeColColor2.Taxon=151, 221, 255 settings.email.smtp=authsmtp.ku.edu google.earth.secondaryurltitle=ad -TreeEditor.Rank.Threshold.Taxon=100 Treeeditor.SynonymyColor.LithoStrat=0, 0, 255 CO_CREATE_COA_32678 = false IPAD_REMOTE_IMAGE_URL_TYPE_32768=attmgr @@ -37,7 +36,6 @@ ALL_YEAR_CATS_STAT=false Exporttask.OnTaskbar=true CO_CREATE_PREP_65536=false recent_collection_id.abentley.KU_Fish_Tissue=4 -TreeEditor.Rank.Threshold.Geography=100 recent_collection_id.Vertnet.KU_Fish_Tissue=4 google.earth.useorigheaders=true google.earth.fgcolor=255, 255, 255 @@ -59,12 +57,10 @@ StartupTask.OnTaskbar.fish=true Treeeditor.TreeColColor1.LithoStrat=202, 238, 255 IPAD_REMOTE_IMAGE_URL_TYPE_4=attmgr recent_collection_id.Abornstein.KU_Fish_Tissue=4 -TreeEditor.Rank.Threshold.Storage=200 settings.email.email=abentley@ku.edu google.earth.primaryurltitle=KU BIodiversity Institute Ichthyology ui.formatting.disciplineicon.KUFishtissue=colobj_backstop loans.shipmeth=FedEx -TreeEditor.Rank.Threshold.GeologicTimePeriod=0 attachment.url=http\://biwebdb.nhm.ku.edu/web_asset_store.xml usage_tracking.send_isa_stats=true SGR_SHOW_TASK_PREF.fish=true @@ -86,7 +82,6 @@ IPAD_REMOTE_IMAGE_URL_4=http\://biimages.biodiversity.ku.edu/web_asset_store.xml SGRTask.OnTaskbar=true recent_collection_id.spfishadmin.KU_Fish_Tissue=32768 Treeeditor.TreeColColor2.LithoStrat=151, 221, 255 -TreeEditor.Rank.Threshold.LithoStrat=200 ui.formatting.disciplineicon.KUFishvoucher=colobj_backstop recent_collection_id.testuser.kui_fish_dbo_6=32768 IPAD_COLMGR_NAME_4=Andrew Bentley @@ -110,7 +105,6 @@ IPAD_CURATOR_NAME_4=William Leo Smith ui.formatting.valtextcolor=255, 0, 0 bnrIconSizeCBX=20 x 20 pixels attachment.key=c3wNpDBTLMedXWSb8w2TeSwHWVFLvBwiYmtU0CdOzLQtelcibV9sTXW7NxZlX68 -TaxonTreeEditor.DisplayAuthor=true ui.formatting.formtype=Small Font Format (ideal for Windows) Agent.Use.Variants.fish=false Interactions.Using.Interactions.fish=true