From d76789b693d879fe3c32f369b39913cd87a029a6 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:00:14 -0600 Subject: [PATCH 01/24] Update Interaction localization --- .../js_src/lib/localization/interactions.ts | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index a09c443fac0..07d5ea52d03 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -268,15 +268,42 @@ export const interactionsText = createDictionary({ 'uk-ua': '{giftTable:string} записи', 'de-ch': '{giftTable:string} Datensätze', }, + disposals: { + comment: 'Example: Disposal records', + 'en-us': '{disposalTable:string} records', + 'es-es': '{disposalTable:string} registros', + 'fr-fr': '{disposalTable:string} enregistrements', + 'ru-ru': '{disposalTable:string} записи', + 'uk-ua': '{disposalTable:string} записи', + 'de-ch': '{disposalTable:string} Datensätze', + }, + exchangeOut: { + comment: 'Example: Exchange Out records', + 'en-us': '{exchangeOutTable:string} records', + 'es-es': '{exchangeOutTable:string} registros', + 'fr-fr': '{exchangeOutTable:string} enregistrements', + 'ru-ru': '{exchangeOutTable:string} записи', + 'uk-ua': '{exchangeOutTable:string} записи', + 'de-ch': '{exchangeOutTable:string} Datensätze', + }, + exchangeIn: { + comment: 'Example: Exchange In records', + 'en-us': '{exchangeInTable:string} records', + 'es-es': '{exchangeInTable:string} registros', + 'fr-fr': '{exchangeInTable:string} enregistrements', + 'ru-ru': '{exchangeInTable:string} записи', + 'uk-ua': '{exchangeInTable:string} записи', + 'de-ch': '{exchangeInTable:string} Datensätze', + }, exchanges: { comment: 'Example: Exchange In / Exchnage Out records', - 'en-us': '{exhangeInTable:string} / {exhangeOutTable:string} records', - 'es-es': 'Registros {exhangeInTable:string} / {exhangeOutTable:string}', + 'en-us': '{exchangeInTable:string} / {exchangeOutTable:string} records', + 'es-es': 'Registros {exchangeInTable:string} / {exchangeOutTable:string}', 'fr-fr': - 'Enregistrements {exhangeInTable:string} / {exhangeOutTable:string}', - 'ru-ru': '{exhangeInTable:string} / {exhangeOutTable:string} записи', - 'uk-ua': 'Записи {exhangeInTable:string} / {exhangeOutTable:string}.', - 'de-ch': '{exhangeInTable:string} / {exhangeOutTable:string} Datensätze', + 'Enregistrements {exchangeInTable:string} / {exchangeOutTable:string}', + 'ru-ru': '{exchangeInTable:string} / {exchangeOutTable:string} записи', + 'uk-ua': 'Записи {exchangeInTable:string} / {exchangeOutTable:string}.', + 'de-ch': '{exchangeInTable:string} / {exchangeOutTable:string} Datensätze', }, unCataloged: { 'en-us': 'uncataloged', From daa990cca91182bf79ce8ac9602f95df3c2612f4 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:00:29 -0600 Subject: [PATCH 02/24] Add Disposal to Interactions dialog --- .../FormCommands/ShowTransactions.tsx | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index 242a47bd9f6..573eca94681 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -100,13 +100,27 @@ export function ShowLoansCommand({ domainFilter: false, }).then(({ records }) => records.map(deserializeResource)) : undefined, - exchanges: hasTablePermission('ExchangeOutPrep', 'read') + exchangeOuts: hasTablePermission('ExchangeOutPrep', 'read') ? fetchCollection('ExchangeOutPrep', { limit: DEFAULT_FETCH_LIMIT, preparation: preparation.get('id'), domainFilter: false, }).then(({ records }) => records.map(deserializeResource)) : undefined, + exchangeIns: hasTablePermission('ExchangeInPrep', 'read') + ? fetchCollection('ExchangeInPrep', { + limit: DEFAULT_FETCH_LIMIT, + preparation: preparation.get('id'), + domainFilter: false, + }).then(({ records }) => records.map(deserializeResource)) + : undefined, + disposals: hasTablePermission('Disposal', 'read') + ? fetchCollection('DisposalPreparation', { + limit: DEFAULT_FETCH_LIMIT, + preparation: preparation.get('id'), + domainFilter: false, + }).then(({ records }) => records.map(deserializeResource)) + : undefined, }), [preparation] ), @@ -153,21 +167,54 @@ export function ShowLoansCommand({ fieldName="gift" resources={data.gifts ?? []} /> - {Array.isArray(data.exchanges) && data.exchanges.length > 0 && ( +

+ + {interactionsText.disposals({ + disposalTable: tables.Disposal.label, + })} +

+ +

+ + {interactionsText.exchangeOut({ + exchangeOutTable: tables.ExchangeOut.label, + })} +

+ +

+ + {interactionsText.exchangeIn({ + exchangeInTable: tables.ExchangeIn.label, + })} +

+ + {/* {Array.isArray(data.exchangeOuts) && data.exchangeOuts.length > 0 && ( <>

{interactionsText.exchanges({ - exhangeInTable: tables.ExchangeIn.label, - exhangeOutTable: tables.ExchangeOut.label, + exchangeInTable: tables.ExchangeIn.label, + exchangeOutTable: tables.ExchangeOut.label, })}

- )} + )} */} ) : null; } From 480023810d9dfed1305e35336e49f8a02fe3e81e Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:06:19 -0600 Subject: [PATCH 03/24] Update interactions.ts --- specifyweb/frontend/js_src/lib/localization/interactions.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 07d5ea52d03..fc644003e4b 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -17,6 +17,9 @@ export const interactionsText = createDictionary({ 'uk-ua': 'Взаємодії', 'de-ch': 'Interaktionen', }, + noInteractions: { + 'en-us': 'There are no interactions linked to this preparation.', + }, addItems: { 'en-us': 'Add Items', 'ru-ru': 'Добавить элементы', From eaf9a6c1e2695160180efc1d86580fb9742484c5 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:07:30 -0600 Subject: [PATCH 04/24] Hide interactions when none are available --- .../FormCommands/ShowTransactions.tsx | 184 ++++++++++-------- 1 file changed, 104 insertions(+), 80 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index 573eca94681..8305e56cc28 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -127,6 +127,15 @@ export function ShowLoansCommand({ true ); + const hasAnyInteractions = data && [ + data.openLoans, + data.resolvedLoans, + data.gifts, + data.exchangeOuts, + data.exchangeIns, + data.disposals, + ].some(interactions => Array.isArray(interactions) && interactions.length > 0); + return typeof data === 'object' ? ( -

- - {interactionsText.openLoans({ - loanTable: tables.Loan.label, - })} -

- -

- - {interactionsText.resolvedLoans({ - loanTable: tables.Loan.label, - })} -

- -

- - {interactionsText.gifts({ - giftTable: tables.Gift.label, - })} -

- -

- - {interactionsText.disposals({ - disposalTable: tables.Disposal.label, - })} -

- -

- - {interactionsText.exchangeOut({ - exchangeOutTable: tables.ExchangeOut.label, - })} -

- -

- - {interactionsText.exchangeIn({ - exchangeInTable: tables.ExchangeIn.label, - })} -

- - {/* {Array.isArray(data.exchangeOuts) && data.exchangeOuts.length > 0 && ( + {!hasAnyInteractions ? ( + <>{interactionsText.noInteractions()} + ) : ( <> -

- {interactionsText.exchanges({ - exchangeInTable: tables.ExchangeIn.label, - exchangeOutTable: tables.ExchangeOut.label, - })} -

- + {Array.isArray(data.openLoans) && data.openLoans.length > 0 && ( + <> +

+ + {interactionsText.openLoans({ + loanTable: tables.Loan.label, + })} +

+ + + )} + {Array.isArray(data.resolvedLoans) && data.resolvedLoans.length > 0 && ( + <> +

+ + {interactionsText.resolvedLoans({ + loanTable: tables.Loan.label, + })} +

+ + + )} + {Array.isArray(data.gifts) && data.gifts.length > 0 && ( + <> +

+ + {interactionsText.gifts({ + giftTable: tables.Gift.label, + })} +

+ + + )} + {Array.isArray(data.disposals) && data.disposals.length > 0 && ( + <> +

+ + {interactionsText.disposals({ + disposalTable: tables.Disposal.label, + })} +

+ + + )} + {Array.isArray(data.exchangeOuts) && data.exchangeOuts.length > 0 && ( + <> +

+ + {interactionsText.exchangeOut({ + exchangeOutTable: tables.ExchangeOut.label, + })} +

+ + + )} + {Array.isArray(data.exchangeIns) && data.exchangeIns.length > 0 && ( + <> +

+ + {interactionsText.exchangeIn({ + exchangeInTable: tables.ExchangeIn.label, + })} +

+ + + )} - )} */} + )}
) : null; -} +} \ No newline at end of file From 0c27b3788689e5de0f1a8d4e12f2faffd651a684 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:11:51 -0600 Subject: [PATCH 05/24] Remove unused text --- .../frontend/js_src/lib/localization/interactions.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index fc644003e4b..a2021f6ca8c 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -298,16 +298,6 @@ export const interactionsText = createDictionary({ 'uk-ua': '{exchangeInTable:string} записи', 'de-ch': '{exchangeInTable:string} Datensätze', }, - exchanges: { - comment: 'Example: Exchange In / Exchnage Out records', - 'en-us': '{exchangeInTable:string} / {exchangeOutTable:string} records', - 'es-es': 'Registros {exchangeInTable:string} / {exchangeOutTable:string}', - 'fr-fr': - 'Enregistrements {exchangeInTable:string} / {exchangeOutTable:string}', - 'ru-ru': '{exchangeInTable:string} / {exchangeOutTable:string} записи', - 'uk-ua': 'Записи {exchangeInTable:string} / {exchangeOutTable:string}.', - 'de-ch': '{exchangeInTable:string} / {exchangeOutTable:string} Datensätze', - }, unCataloged: { 'en-us': 'uncataloged', 'ru-ru': 'не внесенный в каталог', From 81067b54830456c54c3e1e6fe8d30fc81739ba08 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 17:37:31 -0600 Subject: [PATCH 06/24] Use localized Preparation table name --- .../lib/components/FormCommands/ShowTransactions.tsx | 8 ++++++-- .../frontend/js_src/lib/localization/interactions.ts | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index 8305e56cc28..ca14dfe5c09 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -143,8 +143,12 @@ export function ShowLoansCommand({ icon={icons.chat} onClose={handleClose} > - {!hasAnyInteractions ? ( - <>{interactionsText.noInteractions()} + {!hasAnyInteractions ? ( + <> + {interactionsText.noInteractions({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} + ) : ( <> {Array.isArray(data.openLoans) && data.openLoans.length > 0 && ( diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index a2021f6ca8c..d3c1eec5565 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -18,7 +18,8 @@ export const interactionsText = createDictionary({ 'de-ch': 'Interaktionen', }, noInteractions: { - 'en-us': 'There are no interactions linked to this preparation.', + comment: 'Example: There are no interactions linked to this {preparation}', + 'en-us': 'There are no interactions linked to this {preparationTable:string}.', }, addItems: { 'en-us': 'Add Items', From 416dfb239d2766007a465b732027c66c160a4640 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 23:41:04 +0000 Subject: [PATCH 07/24] Lint code with ESLint and Prettier Triggered by 81067b54830456c54c3e1e6fe8d30fc81739ba08 on branch refs/heads/issue-6108 --- .../components/FormCommands/ShowTransactions.tsx | 14 +++++++------- .../js_src/lib/localization/interactions.ts | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index ca14dfe5c09..c8cae269c4d 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -143,13 +143,7 @@ export function ShowLoansCommand({ icon={icons.chat} onClose={handleClose} > - {!hasAnyInteractions ? ( - <> - {interactionsText.noInteractions({ - preparationTable: String(tables.Preparation.label).toLowerCase(), - })} - - ) : ( + {hasAnyInteractions ? ( <> {Array.isArray(data.openLoans) && data.openLoans.length > 0 && ( <> @@ -242,6 +236,12 @@ export function ShowLoansCommand({ )} + ) : ( + <> + {interactionsText.noInteractions({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} + )} ) : null; diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index d3c1eec5565..d3816497c13 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -19,7 +19,8 @@ export const interactionsText = createDictionary({ }, noInteractions: { comment: 'Example: There are no interactions linked to this {preparation}', - 'en-us': 'There are no interactions linked to this {preparationTable:string}.', + 'en-us': + 'There are no interactions linked to this {preparationTable:string}.', }, addItems: { 'en-us': 'Add Items', From 702e118d73e2a1c2e3bf25b036f98558be49ce39 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 18:01:04 -0600 Subject: [PATCH 08/24] Improve localization for Preparations --- .../Interactions/InteractionDialog.tsx | 16 ++++- .../components/Interactions/LoanReturn.tsx | 4 +- .../components/Interactions/PrepDialog.tsx | 5 +- .../js_src/lib/localization/interactions.ts | 65 +++---------------- 4 files changed, 28 insertions(+), 62 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx index 1ffc921b26f..ef56a36aa88 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx @@ -245,7 +245,9 @@ export function InteractionDialog({ ) : interactionsWithPrepTables.includes(actionTable.name) ? ( - {interactionsText.withoutPreparations()} + {interactionsText.withoutPreparations({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} ) : undefined} @@ -419,7 +421,11 @@ function InteractionTextEntry({ <> {state.missing.length > 0 && ( <> -

{interactionsText.preparationsNotFoundFor()}

+

+ {interactionsText.preparationsNotFoundFor({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} +

{state.missing.map((problem, index) => (

{problem}

))} @@ -427,7 +433,11 @@ function InteractionTextEntry({ )} {state.unavailable.length > 0 && ( <> -

{interactionsText.preparationsNotAvailableFor()}

+

+ {interactionsText.preparationsNotAvailableFor({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} +

{state.unavailable.map((problem, index) => (

{problem}

))} diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx index be5d446f254..c5bd043eba6 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx @@ -72,7 +72,9 @@ export function LoanReturn({ header={tables.LoanPreparation.label} onClose={handleClose} > - {interactionsText.noUnresolvedPreparations()} + {interactionsText.noUnresolvedPreparations({ + loanPreparationsLabel: String(getField(tables.Loan, 'loanPreparations').label).toLowerCase() + })} ) : ( diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx index b26023e369c..504be98a374 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx @@ -133,7 +133,10 @@ export function PrepDialog({ ) } - header={interactionsText.preparations()} + header= + {interactionsText.preparations({ + preparationTable: tables.Preparation.label, + })} onClose={handleClose} > diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index d3c1eec5565..139d7733de4 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -38,38 +38,14 @@ export const interactionsText = createDictionary({ 'de-ch': '{table:string} Datensätze', }, preparationsNotFoundFor: { - 'en-us': 'No preparations were found for the following records:', - 'de-ch': 'Für folgende Datensätze wurden keine Präparate gefunden:', - 'es-es': 'No se encontraron preparativos para los siguientes registros:', - 'fr-fr': - "Aucune préparation n'a été trouvée pour les enregistrements suivants :", - 'ru-ru': 'Никаких приготовлений не обнаружено для следующих записей:', - 'uk-ua': 'Не знайдено жодних препаратів для таких записів:', + comment: 'Example: No preparation records were found for the following records:', + 'en-us': 'No {preparationTable:string} records were found for the following records:', }, preparationsNotAvailableFor: { 'en-us': ` - No preparations are available for at least one type of preparation in the + No {preparationTable:string} records are available for at least one type of preparation in the following records: `, - 'de-ch': ` - Für mindestens eine Präparationsart sind in folgenden Datensätzen keine - Präparate vorhanden: - `, - 'es-es': ` - No hay preparados disponibles para al menos un tipo de preparado en los - siguientes registros: - `, - 'fr-fr': ` - Aucune préparation n'est disponible pour au moins un type de préparation - dans les enregistrements suivants : - `, - 'ru-ru': ` - В следующих записях отсутствуют препараты хотя бы для одного типа - препаратов: - `, - 'uk-ua': ` - У таких записах відсутні препарати принаймні для одного типу препарату: - `, }, problemsFound: { 'en-us': 'There are problems with the entry:', @@ -107,20 +83,10 @@ export const interactionsText = createDictionary({ 'de-ch': 'Durch Eingabe von {fieldName:string}s', }, withoutPreparations: { - 'en-us': 'Without preparations', - 'ru-ru': 'Без подготовки', - 'es-es': 'Sin preparativos', - 'fr-fr': 'Sans préparations', - 'uk-ua': 'Без препаратів', - 'de-ch': 'Ohne Präparate', + 'en-us': 'No {preparationTable:string}', }, continueWithoutPreparations: { - 'en-us': 'Continue without preparations', - 'de-ch': 'Weiter ohne Vorbereitungen', - 'es-es': 'Continuar sin preparativos', - 'fr-fr': 'Continuer sans préparation', - 'ru-ru': 'Продолжить без подготовки', - 'uk-ua': 'Продовжуйте без підготовки', + 'en-us': 'Continue without {preparationTable:string}', }, addUnassociated: { 'en-us': 'Add unassociated item', @@ -131,28 +97,13 @@ export const interactionsText = createDictionary({ 'de-ch': 'Nicht assoziierter Gegenstand hinzufügen', }, preparations: { - 'en-us': 'Preparations', - 'ru-ru': 'Препараты', - 'es-es': 'Preparativos', - 'fr-fr': 'Preparations', - 'uk-ua': 'препарати', - 'de-ch': 'Präparate', + 'en-us': 'Add {preparationTable:string}', }, preparationsCanNotBeReturned: { - 'en-us': 'Preparations cannot be returned in this context.', - 'ru-ru': 'В этом случае препараты не подлежат возврату.', - 'es-es': 'En este contexto, los preparados no se pueden devolver.', - 'fr-fr': 'Les preparations ne peuvent être renvoyées dans ce contexte.', - 'uk-ua': 'У цьому контексті препарати не повертаються.', - 'de-ch': 'Präparate können in diesem Kontext nicht zurückgegeben werden.', + 'en-us': '{preparationTable:string} records cannot be returned in this context.', }, noUnresolvedPreparations: { - 'en-us': 'There are no unresolved preparations for this loan.', - 'ru-ru': 'Нет никаких нерешенных приготовлений к этому кредиту.', - 'es-es': 'No hay preparativos pendientes para este préstamo.', - 'fr-fr': 'Il n’y a pas de preparations non retournées pour ce prêt.', - 'uk-ua': 'Немає жодної невирішеної підготовки щодо цієї позики.', - 'de-ch': 'Für dieses Ausleihe bestehen keine ungelösten Vorbereitungen.', + 'en-us': 'There are no unresolved {loanPreparationsLabel:string}.', }, unresolved: { 'en-us': 'Unresolved', From aa4dfda5917f5f4543de566467521356e9d44e8a Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 18:20:41 -0600 Subject: [PATCH 09/24] Update interactions.ts --- .../js_src/lib/localization/interactions.ts | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 5ecb32837d4..bb9bc9d4000 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -133,28 +133,13 @@ export const interactionsText = createDictionary({ 'de-ch': 'Lösen', }, returnAllPreparations: { - 'en-us': 'Return all preparations', - 'ru-ru': 'Добавить элементы', - 'es-es': '[X0X] Regresar', - 'fr-fr': 'Retourner toutes les préparations', - 'uk-ua': '[X0X] Повернення', - 'de-ch': 'Alle Präparate zurückgeben', + 'en-us': 'Return all {preparationTable:string} records', }, returnSelectedPreparations: { - 'en-us': 'Return selected preparations', - 'ru-ru': 'Вернуть выбранные препараты', - 'es-es': 'Devolver los preparados seleccionados', - 'fr-fr': 'Retourner les préparations sélectionnées', - 'uk-ua': 'Повернути обрані препарати', - 'de-ch': 'Ausgewählte Präparate zurückgeben', + 'en-us': 'Return selected {preparationTable:string} records', }, selectAllAvailablePreparations: { - 'en-us': 'Select all available preparations', - 'ru-ru': 'Выбрать все доступные препараты', - 'es-es': 'Seleccione todas las preparaciones disponibles', - 'fr-fr': 'Sélectionnez toutes les préparations disponibles', - 'uk-ua': 'Виберіть усі доступні препарати', - 'de-ch': 'Alle verfügbaren Präparate auswählen', + 'en-us': 'Select all available {preparationTable:string} records', }, selectAll: { 'en-us': 'Select All', From 268110e400f27cbd8e126049be5fe8552649dabc Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 18:23:04 -0600 Subject: [PATCH 10/24] Fix no interactions label --- .../lib/components/FormCommands/ShowTransactions.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index fc985f2d95e..ca14dfe5c09 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -144,6 +144,11 @@ export function ShowLoansCommand({ onClose={handleClose} > {!hasAnyInteractions ? ( + <> + {interactionsText.noInteractions({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} + ) : ( <> {Array.isArray(data.openLoans) && data.openLoans.length > 0 && ( @@ -237,12 +242,6 @@ export function ShowLoansCommand({ )} - ) : ( - <> - {interactionsText.noInteractions({ - preparationTable: String(tables.Preparation.label).toLowerCase(), - })} - )} ) : null; From 634aef19153af8c684fcd473604715d1dc9f32b8 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 18:23:24 -0600 Subject: [PATCH 11/24] Improve Preparation localization further --- .../js_src/lib/components/Interactions/LoanReturn.tsx | 10 ++++++++-- .../js_src/lib/components/Interactions/PrepDialog.tsx | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx index c5bd043eba6..7b97f3f3725 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx @@ -163,7 +163,10 @@ function PreparationReturn({ {commonText.cancel()} setState( state.map(({ unresolved, remarks }) => ({ @@ -194,7 +197,10 @@ function PreparationReturn({ {commonText.apply()} diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx index 504be98a374..1025ae8755b 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx @@ -104,7 +104,10 @@ export function PrepDialog({ {commonText.cancel()} setSelected(preparations.map(({ available }) => available)) } From b7f1896f8a9dbcec2771c48a2b809051e5803d09 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 18 Jan 2025 18:39:14 -0600 Subject: [PATCH 12/24] Finish localizing preparations --- .../js_src/lib/components/FormCommands/index.tsx | 4 +++- .../Interactions/InteractionDialog.tsx | 12 +++++++++--- .../lib/components/QueryBuilder/LoanReturn.tsx | 5 ++++- .../js_src/lib/localization/interactions.ts | 16 ++-------------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index cec79a1a757..1d1b2bf6b4a 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -98,7 +98,9 @@ const commandRenderers: { header={label} onClose={handleHide} > - {interactionsText.preparationsCanNotBeReturned()} + {interactionsText.preparationsCanNotBeReturned({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} ) : ( diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx index ef56a36aa88..d862237442e 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx @@ -199,11 +199,15 @@ export function InteractionDialog({ handleClose(); }} > - {interactionsText.continueWithoutPreparations()} + {interactionsText.continueWithoutPreparations({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} ) : ( - {interactionsText.continueWithoutPreparations()} + {interactionsText.continueWithoutPreparations({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} )} {} @@ -214,7 +218,9 @@ export function InteractionDialog({ })} onClose={handleClose} > - {interactionsText.noPreparationsWarning()} + {interactionsText.noPreparationsWarning({ + preparationTable: String(tables.Preparation.label).toLowerCase(), + })} ) ) : ( diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/LoanReturn.tsx b/specifyweb/frontend/js_src/lib/components/QueryBuilder/LoanReturn.tsx index add7e02b663..c6e06cc73c3 100644 --- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/LoanReturn.tsx +++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/LoanReturn.tsx @@ -159,7 +159,10 @@ export function QueryLoanReturn({ {commonText.cancel()} {interactionsText.return()} diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index bb9bc9d4000..1ee1287f54c 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -135,7 +135,7 @@ export const interactionsText = createDictionary({ returnAllPreparations: { 'en-us': 'Return all {preparationTable:string} records', }, - returnSelectedPreparations: { + returnSelectedPreparations: { 'en-us': 'Return selected {preparationTable:string} records', }, selectAllAvailablePreparations: { @@ -176,7 +176,6 @@ export const interactionsText = createDictionary({ prepReturnFormatter: { comment: 'Used to format preparations in the prep return dialog', 'en-us': '{tableName:string}: {resource:string}', - 'ru-ru': '[Х0Х]: [Х20Х]', 'es-es': '{tableName:string}: {resource:string}', 'fr-fr': '{tableName:string} : {resource:string}', 'uk-ua': '{tableName:string}: {resource:string}', @@ -324,18 +323,7 @@ export const interactionsText = createDictionary({ }, noPreparationsWarning: { 'en-us': - 'None of these objects have preparations. Would you like to continue?', - 'de-ch': ` - Für keines dieser Objekte liegen Vorbereitungen vor. Möchten Sie - fortfahren? - `, - 'es-es': - 'Ninguno de estos objetos tiene preparaciones. ¿Te gustaria continuar?', - 'fr-fr': "Aucun de ces objets n'a de préparation. Voulez-vous continuer?", - 'ru-ru': ` - Ни один из этих объектов не имеет подготовки. Желаете ли вы продолжить? - `, - 'uk-ua': "Жоден із цих об'єктів не має підготовки. Бажаєте продовжити?", + 'None of these objects have {preparationTable:string} records. Would you like to continue?', }, continue: { 'en-us': 'Continue', From 59802e1475245a3c6b8fc610ade9fea2677dcd7b Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 19 Jan 2025 15:18:43 -0600 Subject: [PATCH 13/24] Add tables import --- specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index 1d1b2bf6b4a..0d2c8885124 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -18,6 +18,7 @@ import { LoanReturn } from '../Interactions/LoanReturn'; import { Dialog } from '../Molecules/Dialog'; import { ReportsView } from '../Reports'; import { ShowLoansCommand } from './ShowTransactions'; +import { tables } from '../DataModel/tables'; export function GenerateLabel({ resource, From 0371f027fa8349965873396f247440e92828b18d Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 19 Jan 2025 21:22:17 +0000 Subject: [PATCH 14/24] Lint code with ESLint and Prettier Triggered by 59802e1475245a3c6b8fc610ade9fea2677dcd7b on branch refs/heads/issue-6108 --- .../frontend/js_src/lib/components/FormCommands/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index 0d2c8885124..846cb4532d5 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -12,13 +12,13 @@ import { formatDisjunction } from '../Atoms/Internationalization'; import { toTable } from '../DataModel/helpers'; import type { AnySchema } from '../DataModel/helperTypes'; import type { SpecifyResource } from '../DataModel/legacyTypes'; +import { tables } from '../DataModel/tables'; import { ErrorBoundary } from '../Errors/ErrorBoundary'; import type { UiCommands } from '../FormParse/commands'; import { LoanReturn } from '../Interactions/LoanReturn'; import { Dialog } from '../Molecules/Dialog'; import { ReportsView } from '../Reports'; import { ShowLoansCommand } from './ShowTransactions'; -import { tables } from '../DataModel/tables'; export function GenerateLabel({ resource, From 6c6d36545413149f9d42564a640723f3038c7930 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 20 Jan 2025 02:03:39 -0600 Subject: [PATCH 15/24] Show all related interactions in ShowLoans dialog Alternative implementation of #6110 for #6108 --- .../FormCommands/ShowTransactions.tsx | 340 +++++++----------- .../js_src/lib/localization/interactions.ts | 47 +-- 2 files changed, 129 insertions(+), 258 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index ca14dfe5c09..061d48c68eb 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -1,71 +1,34 @@ import React from 'react'; import { useAsyncState } from '../../hooks/useAsyncState'; +import { useBooleanState } from '../../hooks/useBooleanState'; import { commonText } from '../../localization/common'; import { interactionsText } from '../../localization/interactions'; -import { f } from '../../utils/functools'; import type { RA } from '../../utils/types'; -import { sortFunction } from '../../utils/utils'; -import { H3, Ul } from '../Atoms'; +import { H3 } from '../Atoms'; +import { Button } from '../Atoms/Button'; import { icons } from '../Atoms/Icons'; -import { Link } from '../Atoms/Link'; -import { DEFAULT_FETCH_LIMIT, fetchCollection } from '../DataModel/collection'; -import type { AnySchema } from '../DataModel/helperTypes'; +import { formatNumber } from '../Atoms/Internationalization'; +import type { CollectionFetchFilters } from '../DataModel/collection'; +import { fetchCollection } from '../DataModel/collection'; +import { backendFilter, formatRelationshipPath } from '../DataModel/helpers'; +import type { + AnyInteractionPreparation, + SerializedResource, +} from '../DataModel/helperTypes'; import type { SpecifyResource } from '../DataModel/legacyTypes'; -import { deserializeResource } from '../DataModel/serializers'; +import type { SpecifyTable } from '../DataModel/specifyTable'; import { tables } from '../DataModel/tables'; -import type { Preparation } from '../DataModel/types'; +import type { Preparation, Tables } from '../DataModel/types'; +import { RecordSelectorFromIds } from '../FormSliders/RecordSelectorFromIds'; +import type { InteractionWithPreps } from '../Interactions/helpers'; +import { + interactionPrepTables, + interactionsWithPrepTables, +} from '../Interactions/helpers'; import { Dialog } from '../Molecules/Dialog'; -import { ResourceLink } from '../Molecules/ResourceLink'; import { TableIcon } from '../Molecules/TableIcon'; import { hasTablePermission } from '../Permissions/helpers'; - -function List({ - resources, - fieldName, - displayFieldName, -}: { - readonly resources: RA>; - readonly fieldName: string; - readonly displayFieldName: string; -}): JSX.Element { - const [entries] = useAsyncState( - React.useCallback(async () => { - const interactions: RA> = await Promise.all( - resources.map(async (resource) => resource.rgetPromise(fieldName)) - ); - return interactions - .map((resource) => ({ - label: resource.get(displayFieldName), - resource, - })) - .sort(sortFunction(({ label }) => label)); - }, [resources, fieldName, displayFieldName]), - false - ); - - return resources.length === 0 ? ( - <>{commonText.noResults()} - ) : Array.isArray(entries) ? ( -
    - {entries.map(({ label, resource }, index) => ( -
  • - - {label} - -
  • - ))} -
- ) : ( - <>{commonText.loading()} - ); -} - export function ShowLoansCommand({ preparation, onClose: handleClose, @@ -73,176 +36,113 @@ export function ShowLoansCommand({ readonly preparation: SpecifyResource; readonly onClose: () => void; }): JSX.Element | null { - const [data] = useAsyncState( - React.useCallback( - async () => - f.all({ - openLoans: hasTablePermission('LoanPreparation', 'read') - ? fetchCollection('LoanPreparation', { - isResolved: false, - limit: DEFAULT_FETCH_LIMIT, - preparation: preparation.get('id'), - domainFilter: false, - }).then(({ records }) => records.map(deserializeResource)) - : undefined, - resolvedLoans: hasTablePermission('LoanPreparation', 'read') - ? fetchCollection('LoanPreparation', { - isResolved: true, - limit: DEFAULT_FETCH_LIMIT, - preparation: preparation.get('id'), - domainFilter: false, - }).then(({ records }) => records.map(deserializeResource)) - : undefined, - gifts: hasTablePermission('GiftPreparation', 'read') - ? fetchCollection('GiftPreparation', { - limit: DEFAULT_FETCH_LIMIT, - preparation: preparation.get('id'), - domainFilter: false, - }).then(({ records }) => records.map(deserializeResource)) - : undefined, - exchangeOuts: hasTablePermission('ExchangeOutPrep', 'read') - ? fetchCollection('ExchangeOutPrep', { - limit: DEFAULT_FETCH_LIMIT, - preparation: preparation.get('id'), - domainFilter: false, - }).then(({ records }) => records.map(deserializeResource)) - : undefined, - exchangeIns: hasTablePermission('ExchangeInPrep', 'read') - ? fetchCollection('ExchangeInPrep', { - limit: DEFAULT_FETCH_LIMIT, - preparation: preparation.get('id'), - domainFilter: false, - }).then(({ records }) => records.map(deserializeResource)) - : undefined, - disposals: hasTablePermission('Disposal', 'read') - ? fetchCollection('DisposalPreparation', { - limit: DEFAULT_FETCH_LIMIT, - preparation: preparation.get('id'), - domainFilter: false, - }).then(({ records }) => records.map(deserializeResource)) - : undefined, - }), - [preparation] - ), - true - ); - - const hasAnyInteractions = data && [ - data.openLoans, - data.resolvedLoans, - data.gifts, - data.exchangeOuts, - data.exchangeIns, - data.disposals, - ].some(interactions => Array.isArray(interactions) && interactions.length > 0); - - return typeof data === 'object' ? ( + return ( - {!hasAnyInteractions ? ( - <> - {interactionsText.noInteractions({ - preparationTable: String(tables.Preparation.label).toLowerCase(), - })} - - ) : ( + {interactionsWithPrepTables + .filter((interactionTable) => + hasTablePermission(interactionTable, 'read') + ) + .map((interactionTable) => ( + + ))} + + ); +} +function InterationWithPreps({ + preparation, + tableName, +}: { + readonly preparation: SpecifyResource; + readonly tableName: InteractionWithPreps['tableName']; +}): JSX.Element | null { + const [isOpen, handleOpen, handleClose, _] = useBooleanState(false); + + const [relatedInteractionIds] = useAsyncState( + React.useCallback( + async () => + fetchRelatedInterations(preparation, tableName).then((records) => + records.map(({ id }) => id) + ), + [preparation, tableName] + ), + false + ); + + return ( + <> + {relatedInteractionIds === undefined ? ( <> - {Array.isArray(data.openLoans) && data.openLoans.length > 0 && ( - <> -

- - {interactionsText.openLoans({ - loanTable: tables.Loan.label, - })} -

- - - )} - {Array.isArray(data.resolvedLoans) && data.resolvedLoans.length > 0 && ( - <> -

- - {interactionsText.resolvedLoans({ - loanTable: tables.Loan.label, - })} -

- - - )} - {Array.isArray(data.gifts) && data.gifts.length > 0 && ( - <> -

- - {interactionsText.gifts({ - giftTable: tables.Gift.label, - })} -

- - - )} - {Array.isArray(data.disposals) && data.disposals.length > 0 && ( - <> -

- - {interactionsText.disposals({ - disposalTable: tables.Disposal.label, - })} -

- - - )} - {Array.isArray(data.exchangeOuts) && data.exchangeOuts.length > 0 && ( - <> -

- - {interactionsText.exchangeOut({ - exchangeOutTable: tables.ExchangeOut.label, - })} -

- - - )} - {Array.isArray(data.exchangeIns) && data.exchangeIns.length > 0 && ( - <> -

- - {interactionsText.exchangeIn({ - exchangeInTable: tables.ExchangeIn.label, - })} -

- - - )} +

+
+ + + {interactionsText.tableLabelRecords({ + tableLabel: tables[tableName].label, + })} +
+

+ {commonText.loading()} + ) : relatedInteractionIds.length === 0 ? null : ( + +
+ + + {`${interactionsText.tableLabelRecords({ + tableLabel: tables[tableName].label, + })} (${formatNumber(relatedInteractionIds.length)})`} +
+
)} - - ) : null; -} \ No newline at end of file + {isOpen && Array.isArray(relatedInteractionIds) ? ( + undefined} + onSlide={undefined} + /> + ) : null} + + ); +} + +async function fetchRelatedInterations< + INTERACTION_TABLE extends InteractionWithPreps['tableName'], +>( + preparation: SpecifyResource, + interactionTable: INTERACTION_TABLE +): Promise>> { + const preparationField = tables[interactionTable].relationships.find( + (relationship) => + interactionPrepTables.includes( + relationship.relatedTable.name as AnyInteractionPreparation['tableName'] + ) + ); + + return fetchCollection(interactionTable, { + ...backendFilter( + formatRelationshipPath(preparationField!.name, 'preparation') + ).equals(preparation.get('id')), + domainFilter: false, + limit: 0, + } as CollectionFetchFilters).then( + ({ records }) => records + ); +} diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 1ee1287f54c..c23d34d42de 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -39,8 +39,10 @@ export const interactionsText = createDictionary({ 'de-ch': '{table:string} Datensätze', }, preparationsNotFoundFor: { - comment: 'Example: No preparation records were found for the following records:', - 'en-us': 'No {preparationTable:string} records were found for the following records:', + comment: + 'Example: No preparation records were found for the following records:', + 'en-us': + 'No {preparationTable:string} records were found for the following records:', }, preparationsNotAvailableFor: { 'en-us': ` @@ -101,7 +103,8 @@ export const interactionsText = createDictionary({ 'en-us': 'Add {preparationTable:string}', }, preparationsCanNotBeReturned: { - 'en-us': '{preparationTable:string} records cannot be returned in this context.', + 'en-us': + '{preparationTable:string} records cannot be returned in this context.', }, noUnresolvedPreparations: { 'en-us': 'There are no unresolved {loanPreparationsLabel:string}.', @@ -135,7 +138,7 @@ export const interactionsText = createDictionary({ returnAllPreparations: { 'en-us': 'Return all {preparationTable:string} records', }, - returnSelectedPreparations: { + returnSelectedPreparations: { 'en-us': 'Return selected {preparationTable:string} records', }, selectAllAvailablePreparations: { @@ -199,41 +202,9 @@ export const interactionsText = createDictionary({ 'uk-ua': 'Відкрийте записи {loanTable:string}.', 'de-ch': 'Offene {loanTable:string}-Datensätze', }, - gifts: { - comment: 'Example: Gift records', - 'en-us': '{giftTable:string} records', - 'es-es': '{giftTable:string} registros', - 'fr-fr': '{giftTable:string} enregistrements', - 'ru-ru': '{giftTable:string} записи', - 'uk-ua': '{giftTable:string} записи', - 'de-ch': '{giftTable:string} Datensätze', - }, - disposals: { - comment: 'Example: Disposal records', - 'en-us': '{disposalTable:string} records', - 'es-es': '{disposalTable:string} registros', - 'fr-fr': '{disposalTable:string} enregistrements', - 'ru-ru': '{disposalTable:string} записи', - 'uk-ua': '{disposalTable:string} записи', - 'de-ch': '{disposalTable:string} Datensätze', - }, - exchangeOut: { - comment: 'Example: Exchange Out records', - 'en-us': '{exchangeOutTable:string} records', - 'es-es': '{exchangeOutTable:string} registros', - 'fr-fr': '{exchangeOutTable:string} enregistrements', - 'ru-ru': '{exchangeOutTable:string} записи', - 'uk-ua': '{exchangeOutTable:string} записи', - 'de-ch': '{exchangeOutTable:string} Datensätze', - }, - exchangeIn: { + tableLabelRecords: { comment: 'Example: Exchange In records', - 'en-us': '{exchangeInTable:string} records', - 'es-es': '{exchangeInTable:string} registros', - 'fr-fr': '{exchangeInTable:string} enregistrements', - 'ru-ru': '{exchangeInTable:string} записи', - 'uk-ua': '{exchangeInTable:string} записи', - 'de-ch': '{exchangeInTable:string} Datensätze', + 'en-us': '{tableLabel:string} records', }, unCataloged: { 'en-us': 'uncataloged', From 3bdad09a8d775743db30f18a1498fbe182e30cb6 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 20 Jan 2025 04:16:44 -0600 Subject: [PATCH 16/24] Remove duplicates from returned Interaction request --- .../FormCommands/ShowTransactions.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index 061d48c68eb..3321ffa8a0d 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -48,8 +48,9 @@ export function ShowLoansCommand({ .filter((interactionTable) => hasTablePermission(interactionTable, 'read') ) - .map((interactionTable) => ( + .map((interactionTable, index) => ( @@ -143,6 +144,18 @@ async function fetchRelatedInterations< domainFilter: false, limit: 0, } as CollectionFetchFilters).then( - ({ records }) => records + ({ records }) => { + /** + * If there are multiple InteractionPreparations in an Interaction that + * reference the same Preparation, remove the duplicated Interaction + * records from response + */ + const recordIds: Record = {}; + return records.filter(({ id }) => { + if (recordIds[id]) return false; + recordIds[id] = true; + return true; + }); + } ); } From 34b0e8920df708e6e4782cc6d70502156cf2ce08 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Tue, 21 Jan 2025 08:50:47 -0600 Subject: [PATCH 17/24] Update specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx Co-authored-by: Max Patiiuk --- .../frontend/js_src/lib/components/FormCommands/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index 846cb4532d5..4c80357b7ac 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -100,7 +100,7 @@ const commandRenderers: { onClose={handleHide} > {interactionsText.preparationsCanNotBeReturned({ - preparationTable: String(tables.Preparation.label).toLowerCase(), + preparationTable: tables.Preparation.label.toLowerCase(), })} ) : ( From 43e4c8635d8101bb76f125b2acce5cd2c7962522 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 2 Jul 2025 20:12:27 -0500 Subject: [PATCH 18/24] Run Prettier on all files --- .../lib/components/AppResources/Aside.tsx | 4 +- .../lib/components/Attachments/Cell.tsx | 14 ++-- .../AttachmentsBulkImport/Import.tsx | 66 +++++++++---------- .../lib/components/FormCommands/index.tsx | 4 +- .../components/Interactions/PrepDialog.tsx | 14 ++-- 5 files changed, 50 insertions(+), 52 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx b/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx index 587879f3d08..33adc24310a 100644 --- a/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx +++ b/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx @@ -403,5 +403,5 @@ function ResourceItem({ } export const exportsForTests = { - mutateConformation -} \ No newline at end of file + mutateConformation, +}; diff --git a/specifyweb/frontend/js_src/lib/components/Attachments/Cell.tsx b/specifyweb/frontend/js_src/lib/components/Attachments/Cell.tsx index 4c59e2b7759..e89cedf46fa 100644 --- a/specifyweb/frontend/js_src/lib/components/Attachments/Cell.tsx +++ b/specifyweb/frontend/js_src/lib/components/Attachments/Cell.tsx @@ -36,8 +36,8 @@ export function AttachmentCell({ readonly onOpen: () => void; readonly related: GetSet | undefined>; readonly onViewRecord: - | ((table: SpecifyTable, recordId: number) => void) - | undefined; + | ((table: SpecifyTable, recordId: number) => void) + | undefined; }): JSX.Element { const table = f.maybe(attachment.tableID ?? undefined, getAttachmentTable); @@ -49,8 +49,8 @@ export function AttachmentCell({ return (
{typeof handleViewRecord === 'function' && - table !== undefined && - hasTablePermission(table.name, 'read') ? ( + table !== undefined && + hasTablePermission(table.name, 'read') ? ( { - setRelated(related); - return related; - }) + setRelated(related); + return related; + }) ) .then((related) => typeof related === 'object' diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Import.tsx b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Import.tsx index fac3b20eee2..7bd0afe0fbd 100644 --- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Import.tsx +++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/Import.tsx @@ -136,15 +136,15 @@ function AttachmentsImport({ eagerDataSet.uploadplan.staticPathKey === undefined ? { uploadFile: file } : { - uploadFile: { - ...file, - parsedName: resolveFileNames( - file.file.name, - eagerDataSet.uploadplan.formatQueryResults, - eagerDataSet.uploadplan.fieldFormatter - ), + uploadFile: { + ...file, + parsedName: resolveFileNames( + file.file.name, + eagerDataSet.uploadplan.formatQueryResults, + eagerDataSet.uploadplan.fieldFormatter + ), + }, }, - }, [eagerDataSet.uploadplan.staticPathKey] ); @@ -165,7 +165,7 @@ function AttachmentsImport({ eagerDataSet.uploadplan.staticPathKey === undefined ? undefined : staticAttachmentImportPaths[eagerDataSet.uploadplan.staticPathKey] - .baseTable; + .baseTable; const anyUploaded = React.useMemo( () => @@ -213,10 +213,10 @@ function AttachmentsImport({ {eagerDataSet.uploadplan.staticPathKey === undefined ? '' : strictGetTable(currentBaseTable).strictGetField( - staticAttachmentImportPaths[ - eagerDataSet.uploadplan.staticPathKey - ].path - ).label} + staticAttachmentImportPaths[ + eagerDataSet.uploadplan.staticPathKey + ].path + ).label} )}
@@ -267,11 +267,11 @@ function AttachmentsImport({ anyUploaded ? undefined : (uploadSpec) => { - commitChange((oldState) => ({ - ...oldState, - uploadplan: uploadSpec, - })); - } + commitChange((oldState) => ({ + ...oldState, + uploadplan: uploadSpec, + })); + } } /> @@ -340,14 +340,14 @@ function AttachmentsImport({ ...oldState, rows: oldState.rows.map((uploadable, index) => parsedName !== undefined && - (multiple || index === indexToDisambiguate) && - // Redundant check for single disambiguation, but needed for disambiguate multiples - parsedName === uploadable.uploadFile?.parsedName && - uploadable.attachmentId === undefined + (multiple || index === indexToDisambiguate) && + // Redundant check for single disambiguation, but needed for disambiguate multiples + parsedName === uploadable.uploadFile?.parsedName && + uploadable.attachmentId === undefined ? { - ...uploadable, - disambiguated: disambiguatedId, - } + ...uploadable, + disambiguated: disambiguatedId, + } : uploadable ), }; @@ -357,7 +357,7 @@ function AttachmentsImport({ /> {eagerDataSet.uploaderstatus === 'validating' && - eagerDataSet.uploadplan.staticPathKey !== undefined ? ( + eagerDataSet.uploadplan.staticPathKey !== undefined ? ( ({ - ...oldState, - uploaderstatus: 'main', - rows: validatedFiles, - }), - true - ) + (oldState) => ({ + ...oldState, + uploaderstatus: 'main', + rows: validatedFiles, + }), + true + ) } /> ) : null} diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index 846cb4532d5..f00ab471dcc 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -100,8 +100,8 @@ const commandRenderers: { onClose={handleHide} > {interactionsText.preparationsCanNotBeReturned({ - preparationTable: String(tables.Preparation.label).toLowerCase(), - })} + preparationTable: tables.Preparation.label.toLowerCase(), + })} ) : ( diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx index a7c2f4a761f..c3ae3da86e0 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx @@ -125,10 +125,9 @@ export function PrepDialog({ {commonText.cancel()} setSelected(preparations.map(({ available }) => available)) } @@ -157,10 +156,9 @@ export function PrepDialog({ ) } - header= - {interactionsText.preparations({ - preparationTable: tables.Preparation.label, - })} + header={interactionsText.preparations({ + preparationTable: tables.Preparation.label, + })} onClose={handleClose} > From c7e73f01e2a982ea48bc97038554941e18b4103a Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 2 Jul 2025 20:20:19 -0500 Subject: [PATCH 19/24] Remove unused localization strings --- .../js_src/lib/localization/interactions.ts | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 28a4f41423d..11010bcab73 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -18,11 +18,6 @@ export const interactionsText = createDictionary({ 'de-ch': 'Interaktionen', 'pt-br': 'Interações', }, - noInteractions: { - comment: 'Example: There are no interactions linked to this {preparation}', - 'en-us': - 'There are no interactions linked to this {preparationTable:string}.', - }, addItems: { 'en-us': 'Add Items', 'ru-ru': 'Добавить элементы', @@ -199,26 +194,6 @@ export const interactionsText = createDictionary({ 'de-ch': '{tableName:string}: {resource:string}', 'pt-br': '{tableName:string}: {resource:string}', }, - resolvedLoans: { - comment: 'Example: Resolved Loan records', - 'en-us': 'Resolved {loanTable:string} records', - 'es-es': 'Registros {loanTable:string} resueltos', - 'fr-fr': 'Enregistrements résolus {loanTable:string}', - 'ru-ru': 'Решено {loanTable:string} записей', - 'uk-ua': 'Вирішено записів {loanTable:string}', - 'de-ch': 'Aufgelöste {loanTable:string}-Datensätze', - 'pt-br': 'Registros resolvidos {loanTable:string}', - }, - openLoans: { - comment: 'Example: Open Loan records', - 'en-us': 'Open {loanTable:string} records', - 'es-es': 'Abrir {loanTable:string} registros', - 'fr-fr': 'Ouvrir les enregistrements {loanTable:string}', - 'ru-ru': 'Открыть {loanTable:string} записи', - 'uk-ua': 'Відкрити записи {loanTable:string}', - 'de-ch': 'Öffnen Sie {loanTable:string}-Datensätze', - 'pt-br': 'Abrir registros {loanTable:string}', - }, tableLabelRecords: { comment: 'Example: Exchange In records', 'en-us': '{tableLabel:string} records', From aadcb21bfa480ea8b68eb73470eca323b61d32ee Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 2 Jul 2025 22:11:35 -0500 Subject: [PATCH 20/24] Move handling of fetching related Interactions to parent --- .../FormCommands/ShowTransactions.tsx | 84 +++++++++++++------ .../js_src/lib/localization/interactions.ts | 5 ++ 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index 3321ffa8a0d..10212e5a0aa 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useAsyncState } from '../../hooks/useAsyncState'; +import { useMultipleAsyncState } from '../../hooks/useAsyncState'; import { useBooleanState } from '../../hooks/useBooleanState'; import { commonText } from '../../localization/common'; import { interactionsText } from '../../localization/interactions'; -import type { RA } from '../../utils/types'; +import type { RA, RR } from '../../utils/types'; import { H3 } from '../Atoms'; import { Button } from '../Atoms/Button'; import { icons } from '../Atoms/Icons'; @@ -29,6 +29,7 @@ import { import { Dialog } from '../Molecules/Dialog'; import { TableIcon } from '../Molecules/TableIcon'; import { hasTablePermission } from '../Permissions/helpers'; + export function ShowLoansCommand({ preparation, onClose: handleClose, @@ -36,6 +37,33 @@ export function ShowLoansCommand({ readonly preparation: SpecifyResource; readonly onClose: () => void; }): JSX.Element | null { + const accessibleInteractionTables = React.useMemo( + () => + interactionsWithPrepTables.filter((interactionTable) => + hasTablePermission(interactionTable, 'read') + ), + [] + ); + + const [relatedInteractions] = useMultipleAsyncState< + RR> + >( + React.useMemo( + () => + Object.fromEntries( + accessibleInteractionTables.map((interactionTable) => [ + interactionTable, + () => + fetchRelatedInterations(preparation, interactionTable).then( + (records) => records.map(({ id }) => id) + ), + ]) + ), + [preparation, accessibleInteractionTables] + ), + false + ); + return ( - {interactionsWithPrepTables - .filter((interactionTable) => - hasTablePermission(interactionTable, 'read') - ) - .map((interactionTable, index) => ( - - ))} + {relatedInteractions === undefined + ? commonText.loading() + : accessibleInteractionTables.length === + Object.keys(relatedInteractions).length && + Object.values(relatedInteractions).every( + (relatedIds) => + Array.isArray(relatedIds) && relatedIds.length === 0 + ) + ? interactionsText.noInteractions({ + preparationTable: tables.Preparation.label, + }) + : accessibleInteractionTables + .map( + (interactionTable) => + [ + interactionTable, + relatedInteractions[interactionTable], + ] as const + ) + .map(([interactionTable, relatedIds], index) => ( + + ))} ); } function InterationWithPreps({ - preparation, tableName, + relatedInteractionIds, }: { - readonly preparation: SpecifyResource; readonly tableName: InteractionWithPreps['tableName']; + readonly relatedInteractionIds: RA | undefined; }): JSX.Element | null { const [isOpen, handleOpen, handleClose, _] = useBooleanState(false); - const [relatedInteractionIds] = useAsyncState( - React.useCallback( - async () => - fetchRelatedInterations(preparation, tableName).then((records) => - records.map(({ id }) => id) - ), - [preparation, tableName] - ), - false - ); - return ( <> {relatedInteractionIds === undefined ? ( diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 11010bcab73..40b16299f56 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -36,6 +36,11 @@ export const interactionsText = createDictionary({ 'de-ch': '{table:string} Rückkehr', 'pt-br': '{table:string} Retornar', }, + noInteractions: { + comment: 'Example: There are no interactions linked to this {preparation}', + 'en-us': + 'There are no interactions linked to this {preparationTable:string}.', + }, preparationsNotFoundFor: { comment: 'Example: No preparation records were found for the following records:', From e1a61345410416f65fe5c5d7832ad0d1c01c47e1 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Thu, 3 Jul 2025 03:16:03 +0000 Subject: [PATCH 21/24] Lint code with ESLint and Prettier Triggered by aadcb21bfa480ea8b68eb73470eca323b61d32ee on branch refs/heads/issue-6108 --- .../js_src/lib/components/FormCommands/ShowTransactions.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index 10212e5a0aa..e37699fc492 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -53,7 +53,7 @@ export function ShowLoansCommand({ Object.fromEntries( accessibleInteractionTables.map((interactionTable) => [ interactionTable, - () => + async () => fetchRelatedInterations(preparation, interactionTable).then( (records) => records.map(({ id }) => id) ), @@ -94,8 +94,8 @@ export function ShowLoansCommand({ .map(([interactionTable, relatedIds], index) => ( ))} From 894782121bdb768cf55195559b80138e066a5230 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 14 Feb 2026 20:34:43 -0600 Subject: [PATCH 22/24] fix(localization): simplify preparation labels --- .../lib/components/AppResources/Aside.tsx | 1 + .../FormCommands/ShowTransactions.tsx | 4 +-- .../lib/components/FormCommands/index.tsx | 4 +-- .../Interactions/InteractionDialog.tsx | 30 ++++++------------- .../components/Interactions/LoanReturn.tsx | 17 ++--------- .../components/Interactions/PrepDialog.tsx | 8 ++--- .../js_src/lib/localization/interactions.ts | 13 ++++++-- 7 files changed, 28 insertions(+), 49 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx b/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx index 33adc24310a..371c50ab03f 100644 --- a/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx +++ b/specifyweb/frontend/js_src/lib/components/AppResources/Aside.tsx @@ -404,4 +404,5 @@ function ResourceItem({ export const exportsForTests = { mutateConformation, + useOpenCurrent, }; diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx index e37699fc492..b7808b2df2e 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/ShowTransactions.tsx @@ -80,9 +80,7 @@ export function ShowLoansCommand({ (relatedIds) => Array.isArray(relatedIds) && relatedIds.length === 0 ) - ? interactionsText.noInteractions({ - preparationTable: tables.Preparation.label, - }) + ? interactionsText.noInteractions() : accessibleInteractionTables .map( (interactionTable) => diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index f00ab471dcc..ccf2b587d12 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -99,9 +99,7 @@ const commandRenderers: { header={label} onClose={handleHide} > - {interactionsText.preparationsCanNotBeReturned({ - preparationTable: tables.Preparation.label.toLowerCase(), - })} + {interactionsText.preparationsCanNotBeReturned()} ) : ( diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx index 0a25b58835c..55db88594a8 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx @@ -422,15 +422,11 @@ export function InteractionDialog({ handleClose(); }} > - {interactionsText.continueWithoutPreparations({ - preparationTable: tables.Preparation.label.toLowerCase(), - })} + {interactionsText.continueWithoutPreparations()} ) : ( - {interactionsText.continueWithoutPreparations({ - preparationTable: tables.Preparation.label.toLowerCase(), - })} + {interactionsText.continueWithoutPreparations()} )} {} @@ -441,9 +437,7 @@ export function InteractionDialog({ })} onClose={handleClose} > - {interactionsText.noPreparationsWarning({ - preparationTable: tables.Preparation.label.toLowerCase(), - })} + {interactionsText.noPreparationsWarning()} ) ) : ( @@ -471,9 +465,7 @@ export function InteractionDialog({ ) : interactionsWithPrepTables.includes(actionTable.name) ? ( - {interactionsText.withoutPreparations({ - preparationTable: tables.Preparation.label.toLowerCase(), - })} + {interactionsText.withoutPreparations()} ) : undefined} @@ -583,7 +575,9 @@ export function InteractionDialog({
{state.missing.length > 0 && (
-

{interactionsText.preparationsNotFoundFor()}

+

+ {interactionsText.preparationsNotFoundFor()} +

{state.missing.map((problem, index) => (

{problem}

))} @@ -594,10 +588,7 @@ export function InteractionDialog({ {state.missing.length > 0 && ( <>

- {interactionsText.preparationsNotFoundFor({ - preparationTable: - tables.Preparation.label.toLowerCase(), - })} + {interactionsText.preparationsNotFoundFor()}

{state.missing.map((problem, index) => (

{problem}

@@ -607,10 +598,7 @@ export function InteractionDialog({ {state.unavailableBis.length > 0 && ( <>

- {interactionsText.preparationsNotAvailableFor({ - preparationTable: - tables.Preparation.label.toLowerCase(), - })} + {interactionsText.preparationsNotAvailableFor()}

{state.unavailableBis.map((problem, index) => (

{problem}

diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx index 322c89323bb..6c7e74284c4 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx @@ -11,7 +11,6 @@ import { replaceItem } from '../../utils/utils'; import { Button } from '../Atoms/Button'; import { Form, Input, Label } from '../Atoms/Form'; import { Submit } from '../Atoms/Submit'; -import { getField } from '../DataModel/helpers'; import type { SpecifyResource } from '../DataModel/legacyTypes'; import { tables } from '../DataModel/tables'; import type { Loan, LoanPreparation } from '../DataModel/types'; @@ -72,13 +71,7 @@ export function LoanReturn({ header={tables.LoanPreparation.label} onClose={handleClose} > - {interactionsText.noUnresolvedPreparations({ - loanPreparationsLabel: getField( - tables.Loan, - 'loanPreparations' - ).label.toLowerCase(), - loanTableLabel: tables.Loan.label, - })} + {interactionsText.noUnresolvedPreparations()} ) : ( {commonText.cancel()} setState( state.map(({ unresolved, remarks }) => ({ @@ -206,9 +197,7 @@ function PreparationReturn({ {commonText.apply()} diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx index 1bc1bb29e24..99714aa4404 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx @@ -125,9 +125,7 @@ export function PrepDialog({ {commonText.cancel()} setSelected(preparations.map(({ available }) => available)) } @@ -156,9 +154,7 @@ export function PrepDialog({ ) } - header={interactionsText.preparations({ - preparationTable: tables.Preparation.label, - })} + header={interactionsText.preparations()} onClose={handleClose} > diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index e4a87dac641..469e1e9eb30 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -38,8 +38,17 @@ export const interactionsText = createDictionary({ }, noInteractions: { comment: 'Example: There are no interactions linked to this {preparation}', - 'en-us': - 'There are no interactions linked to this {preparationTable:string}.', + 'en-us': 'There are no interactions linked to this preparation.', + }, + tableLabelRecords: { + comment: 'Example: Loan records', + 'en-us': '{tableLabel:string} records', + 'ru-ru': '{tableLabel:string} записи', + 'es-es': '{tableLabel:string} registros', + 'fr-fr': '{tableLabel:string} enregistrements', + 'uk-ua': '{tableLabel:string} записи', + 'de-ch': '{tableLabel:string} Datensätze', + 'pt-br': '{tableLabel:string} registros', }, preparationsNotFoundFor: { 'en-us': 'No preparations were found for the following records:', From 601e342ae307349a359fe106b864fef6b00c8994 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 14 Feb 2026 20:46:10 -0600 Subject: [PATCH 23/24] fix(tests): misc fixes --- specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx | 1 - .../frontend/js_src/lib/components/Interactions/LoanReturn.tsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx index ccf2b587d12..cec79a1a757 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCommands/index.tsx @@ -12,7 +12,6 @@ import { formatDisjunction } from '../Atoms/Internationalization'; import { toTable } from '../DataModel/helpers'; import type { AnySchema } from '../DataModel/helperTypes'; import type { SpecifyResource } from '../DataModel/legacyTypes'; -import { tables } from '../DataModel/tables'; import { ErrorBoundary } from '../Errors/ErrorBoundary'; import type { UiCommands } from '../FormParse/commands'; import { LoanReturn } from '../Interactions/LoanReturn'; diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx index 6c7e74284c4..f1a6d031b68 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/LoanReturn.tsx @@ -19,6 +19,7 @@ import { autoGenerateViewDefinition } from '../Forms/generateFormDefinition'; import { SpecifyForm } from '../Forms/SpecifyForm'; import { userInformation } from '../InitialContext/userInformation'; import { Dialog } from '../Molecules/Dialog'; +import { getField } from '../DataModel/helpers'; import { PrepReturnRow, updateResolvedChanged, From 3ed237a69e3f3fa4407241e7c14df51ed6776be5 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sat, 14 Feb 2026 20:51:51 -0600 Subject: [PATCH 24/24] fix(localization): remove unused strings --- .../js_src/lib/localization/interactions.ts | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 469e1e9eb30..02433d9a851 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -281,47 +281,6 @@ export const interactionsText = createDictionary({ 'de-ch': '{tableName:string}: {resource:string}', 'pt-br': '{tableName:string}: {resource:string}', }, - resolvedLoans: { - comment: 'Example: Resolved Loan records', - 'en-us': 'Resolved {loanTable:string} records', - 'es-es': 'Registros {loanTable:string} resueltos', - 'fr-fr': 'Enregistrements {loanTable:string} résolus', - 'ru-ru': 'Разрешены записи {loanTable:string}', - 'uk-ua': 'Вирішено записів {loanTable:string}', - 'de-ch': 'Aufgelöste {loanTable:string}-Datensätze', - 'pt-br': 'Registros {loanTable:string} resolvidos', - }, - openLoans: { - comment: 'Example: Open Loan records', - 'en-us': 'Open {loanTable:string} records', - 'es-es': 'Abrir {loanTable:string} registros', - 'fr-fr': 'Ouvrir les enregistrements {loanTable:string}', - 'ru-ru': 'Открыть записи {loanTable:string}', - 'uk-ua': 'Відкрити записи {loanTable:string}', - 'de-ch': '{loanTable:string}-Datensätze öffnen', - 'pt-br': 'Abrir registros {loanTable:string}', - }, - gifts: { - comment: 'Example: Gift records', - 'en-us': '{giftTable:string} records', - 'es-es': '{giftTable:string} registros', - 'fr-fr': '{giftTable:string} enregistrements', - 'ru-ru': '{giftTable:string} записи', - 'uk-ua': '{giftTable:string} записи', - 'de-ch': '{giftTable:string}-Datensätze', - 'pt-br': '{giftTable:string} registros', - }, - exchanges: { - comment: 'Example: Exchange In / Exchnage Out records', - 'en-us': '{exhangeInTable:string} / {exhangeOutTable:string} records', - 'es-es': '{exhangeInTable:string} / {exhangeOutTable:string} registros', - 'fr-fr': - '{exhangeInTable:string} / {exhangeOutTable:string} enregistrements', - 'ru-ru': '{exhangeInTable:string} / {exhangeOutTable:string} записи', - 'uk-ua': 'Записи {exhangeInTable:string} / {exhangeOutTable:string}', - 'de-ch': '{exhangeInTable:string} / {exhangeOutTable:string} Datensätze', - 'pt-br': 'Registros {exhangeInTable:string} / {exhangeOutTable:string}', - }, unCataloged: { 'en-us': 'uncataloged', 'ru-ru': 'некаталогизированный',