diff --git a/specifyweb/frontend/js_src/lib/components/BatchEdit/MissingRanks.tsx b/specifyweb/frontend/js_src/lib/components/BatchEdit/MissingRanks.tsx index e73d0c2a7fc..2fbd1182e36 100644 --- a/specifyweb/frontend/js_src/lib/components/BatchEdit/MissingRanks.tsx +++ b/specifyweb/frontend/js_src/lib/components/BatchEdit/MissingRanks.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { batchEditText } from '../../localization/batchEdit'; import { commonText } from '../../localization/common'; import { interactionsText } from '../../localization/interactions'; -import type { RA,RR } from '../../utils/types'; +import type { RA, RR } from '../../utils/types'; import { H2, H3, Ul } from '../Atoms'; import { Button } from '../Atoms/Button'; import { Input, Label } from '../Atoms/Form'; diff --git a/specifyweb/frontend/js_src/lib/components/FormSliders/IntegratedRecordSelector.tsx b/specifyweb/frontend/js_src/lib/components/FormSliders/IntegratedRecordSelector.tsx index 2970054414e..08a0e65e2f7 100644 --- a/specifyweb/frontend/js_src/lib/components/FormSliders/IntegratedRecordSelector.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormSliders/IntegratedRecordSelector.tsx @@ -169,261 +169,263 @@ export function IntegratedRecordSelector({ isLoanPrep && (collection.related?.isNew() === true || collection.related?.needsSaved); - const [isWarningOpen, handleWarning,closeWarning] = useBooleanState() + const [isWarningOpen, handleWarning, closeWarning] = useBooleanState(); - return ( - - { - if (isInteraction) { - setInteractionResource(resources[0]); - handleOpenDialog(); - } - if (!isInteraction && formType !== 'formTable') - collection.add(resources); - handleAdding(resources); - }} - onDelete={(...args): void => { - if (isCollapsed) handleExpand(); - handleDelete?.(...args); - }} - onFetch={handleFetch} - onSlide={(index): void => { - handleExpand(); - if (typeof urlParameter === 'string') setIndex(index.toString()); - }} - {...rest} - > - {({ - dialogs, - slider, - resource, - onAdd: handleAdd, - onRemove: handleRemove, - showSearchDialog, - isLoading, - }): JSX.Element => ( - <> - {isInteraction && - typeof collection.related === 'object' && - isDialogOpen ? ( - - } - interactionResource={interactionResource} - itemCollection={ - collection as Collection - } - onClose={handleCloseDialog} - /> - ) : undefined} - {formType === 'form' ? ( - - ( - <> - + { + if (isInteraction) { + setInteractionResource(resources[0]); + handleOpenDialog(); + } + if (!isInteraction && formType !== 'formTable') + collection.add(resources); + handleAdding(resources); + }} + onDelete={(...args): void => { + if (isCollapsed) handleExpand(); + handleDelete?.(...args); + }} + onFetch={handleFetch} + onSlide={(index): void => { + handleExpand(); + if (typeof urlParameter === 'string') setIndex(index.toString()); + }} + {...rest} + > + {({ + dialogs, + slider, + resource, + onAdd: handleAdd, + onRemove: handleRemove, + showSearchDialog, + isLoading, + }): JSX.Element => ( + <> + {isInteraction && + typeof collection.related === 'object' && + isDialogOpen ? ( + + } + interactionResource={interactionResource} + itemCollection={ + collection as Collection + } + onClose={handleCloseDialog} + /> + ) : undefined} + {formType === 'form' ? ( + + ( + <> + + {!isDependent && + hasTablePermission( + relationship.relatedTable.name, + 'read' + ) && + typeof handleAdd === 'function' ? ( + 0) || + isTaxonTreeDefItemTable } + onClick={showSearchDialog} /> - {!isDependent && - hasTablePermission( - relationship.relatedTable.name, - 'read' - ) && - typeof handleAdd === 'function' ? ( - 0) || - isTaxonTreeDefItemTable + ) : undefined} + {hasTablePermission( + relationship.relatedTable.name, + 'create' + ) && typeof handleAdd === 'function' ? ( + isCOJO ? ( + } - onClick={showSearchDialog} /> - ) : undefined} - {hasTablePermission( - relationship.relatedTable.name, - 'create' - ) && typeof handleAdd === 'function' ? ( - isCOJO ? ( - - } - /> - ) : ( - 0) || - isTaxonTreeDefItemTable - } - onClick={(): void => { - const resource = - new collection.table.specifyTable.Resource(); - - if ( - isDependent || - viewName === relationship.relatedTable.view - ) { - focusFirstField(); - handleAdd([resource]); - return; - } - - if (state.type === 'AddResourceState') - setState({ type: 'MainState' }); - else - setState({ - type: 'AddResourceState', - resource, - handleAdd, - }); - }} - /> - ) - ) : undefined} - {hasTablePermission( - relationship.relatedTable.name, - isDependent ? 'delete' : 'read' - ) && typeof handleRemove === 'function' ? ( - 0) || + isTaxonTreeDefItemTable } onClick={(): void => { - if (isAttachmentTable) { - handleWarning() - } else { - handleRemove('minusButton'); + const resource = + new collection.table.specifyTable.Resource(); + + if ( + isDependent || + viewName === relationship.relatedTable.view + ) { + focusFirstField(); + handleAdd([resource]); + return; } + + if (state.type === 'AddResourceState') + setState({ type: 'MainState' }); + else + setState({ + type: 'AddResourceState', + resource, + handleAdd, + }); }} /> - ) : undefined} - { + if (isAttachmentTable) { + handleWarning(); + } else { + handleRemove('minusButton'); + } + }} /> - {isAttachmentTable && ( - - )} - {specifyNetworkBadge} - {!isToOne && slider} - - )} - isCollapsed={isCollapsed} - isDependent={isDependent} - isLoading={isLoading} - isSubForm={dialog === false} - key={resource?.cid} - preHeaderButtons={collapsibleButton} - resource={resource} - title={relationship.label} - onAdd={undefined} - onDeleted={ - collection.models.length <= 1 ? handleClose : undefined - } - onSaved={handleClose} - viewName={viewName} - /* - * Don't save the resource on save button click if it is a dependent - * resource - */ - onClose={handleClose} - /> - - ) : null} - {formType === 'formTable' ? ( - + {isAttachmentTable && ( + + )} + {specifyNetworkBadge} + {!isToOne && slider} + + )} isCollapsed={isCollapsed} + isDependent={isDependent} + isLoading={isLoading} + isSubForm={dialog === false} + key={resource?.cid} preHeaderButtons={collapsibleButton} - sortField={sortField} - viewName={viewName} - onAdd={ - isTaxonTreeDefItemTable - ? undefined - : (resources): void => { - if (!isInteraction) collection.add(resources); - handleAdd?.(resources); - } + resource={resource} + title={relationship.label} + onAdd={undefined} + onDeleted={ + collection.models.length <= 1 ? handleClose : undefined } + onSaved={handleClose} + viewName={viewName} + /* + * Don't save the resource on save button click if it is a dependent + * resource + */ onClose={handleClose} - onDelete={(resource, index): void => { - if (isAttachmentTable) { - handleWarning() - } else { - collection.remove(resource); - if (isCollapsed) handleExpand(); - handleDelete?.(index, 'minusButton'); - } - }} - onFetchMore={handleFetch} - /> - ) : null} - {dialogs} - {state.type === 'AddResourceState' && - typeof handleAdd === 'function' ? ( - setState({ type: 'MainState' })} - onDeleted={undefined} - onSaved={(): void => { - state.handleAdd([state.resource]); - setState({ type: 'MainState' }); - }} /> - ) : null} - {isWarningOpen && typeof handleRemove === 'function' && isAttachmentTable? - - : undefined - } - - )} - - - ); - } + + ) : null} + {formType === 'formTable' ? ( + { + if (!isInteraction) collection.add(resources); + handleAdd?.(resources); + } + } + onClose={handleClose} + onDelete={(resource, index): void => { + if (isAttachmentTable) { + handleWarning(); + } else { + collection.remove(resource); + if (isCollapsed) handleExpand(); + handleDelete?.(index, 'minusButton'); + } + }} + onFetchMore={handleFetch} + /> + ) : null} + {dialogs} + {state.type === 'AddResourceState' && + typeof handleAdd === 'function' ? ( + setState({ type: 'MainState' })} + onDeleted={undefined} + onSaved={(): void => { + state.handleAdd([state.resource]); + setState({ type: 'MainState' }); + }} + /> + ) : null} + {isWarningOpen && + typeof handleRemove === 'function' && + isAttachmentTable ? ( + + ) : undefined} + + )} + + + ); +} diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx index e2428ab6ff5..54b60311193 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialog.tsx @@ -176,7 +176,8 @@ export function PrepDialog({ const items = filterArray( preparations.map((preparation, index) => { - if (selected[index] === 0 || Number.isNaN(selected[index])) return undefined; + if (selected[index] === 0 || Number.isNaN(selected[index])) + return undefined; const result = new itemTable.Resource(); result.set( diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx index d9cb47f06c8..32ea7169b79 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/PrepDialogRow.tsx @@ -82,11 +82,13 @@ export function PrepDialogRow({ {preparation.taxon ? ( - + {localized(preparation.taxon)} ) : ( - {interactionsText.notAvailable()} + {interactionsText.notAvailable()} )} {preparation.prepType} diff --git a/specifyweb/frontend/js_src/lib/components/Reports/index.tsx b/specifyweb/frontend/js_src/lib/components/Reports/index.tsx index a2e6d3c879b..971a3557b20 100644 --- a/specifyweb/frontend/js_src/lib/components/Reports/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/Reports/index.tsx @@ -248,9 +248,9 @@ function ReportRow({ - + diff --git a/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx b/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx index f0c77508b93..0b7ae8fb7f9 100644 --- a/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/SearchDialog/index.tsx @@ -93,7 +93,7 @@ export function SearchDialog( }} /> ) : ( - + ); } @@ -186,7 +186,7 @@ function SearchForm({ onClose: handleClose, onUseQueryBuilder: handleUseQueryBuilder, onAdd: handleAdd, - multiple + multiple, }: { readonly forceCollection: number | undefined; readonly extraFilters: RA> | undefined; @@ -198,7 +198,7 @@ function SearchForm({ readonly onAdd?: | ((resources: RA>) => void) | undefined; - readonly multiple?: boolean + readonly multiple?: boolean; }): JSX.Element | null { const templateResource = React.useMemo( () => @@ -242,11 +242,13 @@ function SearchForm({ {queryText.queryBuilder()} - {multiple === true && } + {multiple === true && ( + + )} {commonText.search()} diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/__tests__/navigator.test.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/__tests__/navigator.test.ts index b9e32ed6b84..196d7d4214d 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/__tests__/navigator.test.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/__tests__/navigator.test.ts @@ -20,8 +20,8 @@ theories(getMappingLineData, [ ], out: [ { - defaultValue: 'determinations', customSelectSubtype: 'simple', + defaultValue: 'determinations', selectLabel: localized('Collection Object'), fieldsData: { catalogNumber: { @@ -74,15 +74,6 @@ theories(getMappingLineData, [ isDefault: false, isRelationship: false, }, - leftSideRels: { - isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: true, - isRequired: false, - optionLabel: 'Left Side Rels', - tableName: 'CollectionRelationship', - }, altCatalogNumber: { optionLabel: 'Prev/Exch #', isEnabled: true, @@ -115,15 +106,6 @@ theories(getMappingLineData, [ isDefault: false, isRelationship: false, }, - rightSideRels: { - isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: true, - isRequired: false, - optionLabel: 'Right Side Rels', - tableName: 'CollectionRelationship', - }, fieldNumber: { optionLabel: 'Voucher', isEnabled: true, @@ -168,6 +150,24 @@ theories(getMappingLineData, [ isRelationship: true, tableName: 'CollectionObjectAttribute', }, + collection: { + optionLabel: 'Collection', + isEnabled: true, + isRequired: false, + isHidden: false, + isDefault: false, + isRelationship: true, + tableName: 'Collection', + }, + collectionObjectAttachments: { + optionLabel: 'Collection Object Attachments', + isEnabled: true, + isRequired: false, + isHidden: false, + isDefault: false, + isRelationship: true, + tableName: 'CollectionObjectAttachment', + }, collectionObjectCitations: { optionLabel: 'Collection Object Citations', isEnabled: true, @@ -213,23 +213,14 @@ theories(getMappingLineData, [ isRelationship: true, tableName: 'CollectingEvent', }, - collection: { - isDefault: false, + leftSideRels: { + optionLabel: 'Left Side Rels', isEnabled: true, - isHidden: false, - isRelationship: true, isRequired: false, - optionLabel: 'Collection', - tableName: 'Collection', - }, - collectionObjectAttachments: { - isDefault: false, - isEnabled: true, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Collection Object Attachments', - tableName: 'CollectionObjectAttachment', + tableName: 'CollectionRelationship', }, preparations: { optionLabel: 'Preparations', @@ -240,6 +231,15 @@ theories(getMappingLineData, [ isRelationship: true, tableName: 'Preparation', }, + rightSideRels: { + optionLabel: 'Right Side Rels', + isEnabled: true, + isRequired: false, + isHidden: false, + isDefault: false, + isRelationship: true, + tableName: 'CollectionRelationship', + }, voucherRelationships: { optionLabel: 'Voucher Relationships', isEnabled: true, @@ -253,8 +253,8 @@ theories(getMappingLineData, [ tableName: 'CollectionObject', }, { - defaultValue: '#1', customSelectSubtype: 'toMany', + defaultValue: '#1', selectLabel: localized('Determination'), fieldsData: { '#1': { @@ -273,8 +273,8 @@ theories(getMappingLineData, [ tableName: 'Determination', }, { - defaultValue: 'taxon', customSelectSubtype: 'simple', + defaultValue: 'taxon', selectLabel: localized('Determination'), fieldsData: { determinedDate: { @@ -310,6 +310,15 @@ theories(getMappingLineData, [ isRelationship: true, tableName: 'Agent', }, + determiners: { + optionLabel: 'Determiners', + isEnabled: true, + isRequired: false, + isHidden: false, + isDefault: false, + isRelationship: true, + tableName: 'Determiner', + }, taxon: { optionLabel: 'Taxon', isEnabled: true, @@ -323,8 +332,8 @@ theories(getMappingLineData, [ tableName: 'Determination', }, { - defaultValue: '$Family', customSelectSubtype: 'tree', + defaultValue: '$Family', selectLabel: localized('Taxon'), fieldsData: { $Kingdom: { @@ -391,8 +400,8 @@ theories(getMappingLineData, [ tableName: 'Taxon', }, { - defaultValue: 'name', customSelectSubtype: 'simple', + defaultValue: 'name', selectLabel: localized('Taxon'), fieldsData: { author: { @@ -462,13 +471,14 @@ theories(getMappingLineData, [ { customSelectSubtype: 'simple', defaultValue: 'determinations', + selectLabel: localized('Collection Object'), fieldsData: { '-formatted': { - isDefault: false, - isEnabled: true, - isRelationship: false, optionLabel: '(formatted)', tableName: 'CollectionObject', + isRelationship: false, + isDefault: false, + isEnabled: true, }, absoluteAges: { isDefault: false, @@ -479,71 +489,142 @@ theories(getMappingLineData, [ optionLabel: 'Absolute Ages', tableName: 'AbsoluteAge', }, - accession: { - isDefault: false, + catalogNumber: { + optionLabel: 'Cat #', isEnabled: true, - isHidden: false, - isRelationship: true, isRequired: false, - optionLabel: 'Accession #', - tableName: 'Accession', - }, - altCatalogNumber: { + isHidden: false, isDefault: false, + isRelationship: false, + }, + 'catalogedDate-fullDate': { + optionLabel: 'Cat Date', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Prev/Exch #', }, - catalogNumber: { - isDefault: false, + 'catalogedDate-day': { + optionLabel: 'Cat Date (Day)', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Cat #', }, - 'catalogedDate-day': { + 'catalogedDate-month': { + optionLabel: 'Cat Date (Month)', + isEnabled: true, + isRequired: false, + isHidden: false, isDefault: false, + isRelationship: false, + }, + 'catalogedDate-year': { + optionLabel: 'Cat Date (Year)', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, + }, + reservedText: { + optionLabel: 'CT Scan', + isEnabled: true, isRequired: false, - optionLabel: 'Cat Date (Day)', + isHidden: false, + isDefault: false, + isRelationship: false, }, - 'catalogedDate-fullDate': { + 'timestampModified-fullDate': { + optionLabel: 'Date Edited', + isEnabled: true, + isRequired: false, + isHidden: false, isDefault: false, + isRelationship: false, + }, + 'timestampModified-day': { + optionLabel: 'Date Edited (Day)', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, + }, + 'timestampModified-month': { + optionLabel: 'Date Edited (Month)', + isEnabled: true, isRequired: false, - optionLabel: 'Cat Date', + isHidden: false, + isDefault: false, + isRelationship: false, }, - 'catalogedDate-month': { + 'timestampModified-year': { + optionLabel: 'Date Edited (Year)', + isEnabled: true, + isRequired: false, + isHidden: false, isDefault: false, + isRelationship: false, + }, + guid: { + optionLabel: 'GUID', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, + }, + altCatalogNumber: { + optionLabel: 'Prev/Exch #', + isEnabled: true, isRequired: false, - optionLabel: 'Cat Date (Month)', + isHidden: false, + isDefault: false, + isRelationship: false, }, - 'catalogedDate-year': { + projectNumber: { + optionLabel: 'Project Number', + isEnabled: true, + isRequired: false, + isHidden: false, isDefault: false, + isRelationship: false, + }, + remarks: { + optionLabel: 'Remarks', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, + }, + reservedText2: { + optionLabel: 'Reserved Text2', + isEnabled: true, isRequired: false, - optionLabel: 'Cat Date (Year)', + isHidden: false, + isDefault: false, + isRelationship: false, }, - cataloger: { + fieldNumber: { + optionLabel: 'Voucher', + isEnabled: true, + isRequired: false, + isHidden: false, isDefault: false, + isRelationship: false, + }, + accession: { + optionLabel: 'Accession #', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Cataloger', - tableName: 'Agent', + tableName: 'Accession', }, cojo: { isDefault: false, @@ -554,49 +635,49 @@ theories(getMappingLineData, [ optionLabel: 'Cojo', tableName: 'CollectionObjectGroupJoin', }, - collectingEvent: { - isDefault: false, + cataloger: { + optionLabel: 'Cataloger', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, + tableName: 'Agent', + }, + collectionObjectAttribute: { + optionLabel: 'Col Obj Attribute', + isEnabled: true, isRequired: false, - optionLabel: 'Field No: Locality', - tableName: 'CollectingEvent', + isHidden: false, + isDefault: false, + isRelationship: true, + tableName: 'CollectionObjectAttribute', }, collection: { - isDefault: false, + optionLabel: 'Collection', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Collection', tableName: 'Collection', }, collectionObjectAttachments: { - isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: true, - isRequired: false, optionLabel: 'Collection Object Attachments', - tableName: 'CollectionObjectAttachment', - }, - collectionObjectAttribute: { - isDefault: false, isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Col Obj Attribute', - tableName: 'CollectionObjectAttribute', + tableName: 'CollectionObjectAttachment', }, collectionObjectCitations: { - isDefault: false, + optionLabel: 'Collection Object Citations', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Collection Object Citations', tableName: 'CollectionObjectCitation', }, collectionObjectType: { @@ -609,73 +690,40 @@ theories(getMappingLineData, [ tableName: 'CollectionObjectType', }, determinations: { - isDefault: true, + optionLabel: 'Determinations', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: true, isRelationship: true, - isRequired: false, - optionLabel: 'Determinations', tableName: 'Determination', }, dnaSequences: { - isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: true, - isRequired: false, optionLabel: 'DNA Sequences', - tableName: 'DNASequence', - }, - fieldNumber: { - isDefault: false, isEnabled: true, - isHidden: false, - isRelationship: false, isRequired: false, - optionLabel: 'Voucher', - }, - guid: { - isDefault: false, - isEnabled: true, isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'GUID', - }, - leftSideRels: { isDefault: false, - isEnabled: true, - isHidden: false, isRelationship: true, - isRequired: false, - optionLabel: 'Left Side Rels', - tableName: 'CollectionRelationship', + tableName: 'DNASequence', }, modifiedByAgent: { - isDefault: false, + optionLabel: 'Edited By', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Edited By', tableName: 'Agent', }, - preparations: { - isDefault: false, + collectingEvent: { + optionLabel: 'Field No: Locality', isEnabled: true, - isHidden: false, - isRelationship: true, isRequired: false, - optionLabel: 'Preparations', - tableName: 'Preparation', - }, - projectNumber: { - isDefault: false, - isEnabled: true, isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Project Number', + isDefault: false, + isRelationship: true, + tableName: 'CollectingEvent', }, relativeAges: { isDefault: false, @@ -686,301 +734,263 @@ theories(getMappingLineData, [ optionLabel: 'Relative Ages', tableName: 'RelativeAge', }, - remarks: { - isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Remarks', - }, - reservedText: { - isDefault: false, + leftSideRels: { + optionLabel: 'Left Side Rels', isEnabled: true, - isHidden: false, - isRelationship: false, isRequired: false, - optionLabel: 'CT Scan', - }, - reservedText2: { - isDefault: false, - isEnabled: true, isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Reserved Text2', - }, - rightSideRels: { isDefault: false, - isEnabled: true, - isHidden: false, isRelationship: true, - isRequired: false, - optionLabel: 'Right Side Rels', tableName: 'CollectionRelationship', }, - 'timestampModified-day': { - isDefault: false, + preparations: { + optionLabel: 'Preparations', isEnabled: true, - isHidden: false, - isRelationship: false, isRequired: false, - optionLabel: 'Date Edited (Day)', - }, - 'timestampModified-fullDate': { - isDefault: false, - isEnabled: true, isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Date Edited', - }, - 'timestampModified-month': { isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Date Edited (Month)', + isRelationship: true, + tableName: 'Preparation', }, - 'timestampModified-year': { - isDefault: false, + rightSideRels: { + optionLabel: 'Right Side Rels', isEnabled: true, - isHidden: false, - isRelationship: false, isRequired: false, - optionLabel: 'Date Edited (Year)', + isHidden: false, + isDefault: false, + isRelationship: true, + tableName: 'CollectionRelationship', }, voucherRelationships: { - isDefault: false, + optionLabel: 'Voucher Relationships', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Voucher Relationships', tableName: 'VoucherRelationship', }, }, - selectLabel: localized('Collection Object'), tableName: 'CollectionObject', }, { customSelectSubtype: 'simple', defaultValue: 'taxon', + selectLabel: localized('Determination'), fieldsData: { '-formatted': { - isDefault: false, - isEnabled: true, - isRelationship: false, optionLabel: '(aggregated)', tableName: 'Determination', - }, - 'determinedDate-day': { + isRelationship: false, isDefault: false, isEnabled: true, + }, + isCurrent: { + optionLabel: 'Current', + isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Date (Day)', }, 'determinedDate-fullDate': { - isDefault: false, + optionLabel: 'Date', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, + }, + 'determinedDate-day': { + optionLabel: 'Date (Day)', + isEnabled: true, isRequired: false, - optionLabel: 'Date', + isHidden: false, + isDefault: false, + isRelationship: false, }, 'determinedDate-month': { - isDefault: false, + optionLabel: 'Date (Month)', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Date (Month)', }, 'determinedDate-year': { + optionLabel: 'Date (Year)', + isEnabled: true, + isRequired: false, + isHidden: false, isDefault: false, + isRelationship: false, + }, + guid: { + optionLabel: 'GUID', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, + }, + typeStatusName: { + optionLabel: 'Type Status', + isEnabled: true, isRequired: false, - optionLabel: 'Date (Year)', + isHidden: false, + isDefault: false, + isRelationship: false, }, determiner: { - isDefault: false, + optionLabel: 'Determiner', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Determiner', tableName: 'Agent', }, determiners: { - isDefault: false, + optionLabel: 'Determiners', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: true, - isRequired: false, - optionLabel: 'Determiners', tableName: 'Determiner', }, - guid: { - isDefault: false, + preferredTaxon: { + optionLabel: 'Preferred Taxon', isEnabled: true, - isHidden: false, - isRelationship: false, isRequired: false, - optionLabel: 'GUID', - }, - isCurrent: { - isDefault: false, - isEnabled: true, isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Current', - }, - preferredTaxon: { isDefault: false, - isEnabled: true, - isHidden: false, isRelationship: true, - isRequired: false, - optionLabel: 'Preferred Taxon', tableName: 'Taxon', }, taxon: { - isDefault: true, + optionLabel: 'Taxon', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: true, isRelationship: true, - isRequired: false, - optionLabel: 'Taxon', tableName: 'Taxon', }, - typeStatusName: { - isDefault: false, - isEnabled: true, - isHidden: false, - isRelationship: false, - isRequired: false, - optionLabel: 'Type Status', - }, }, - selectLabel: localized('Determination'), tableName: 'Determination', }, { customSelectSubtype: 'tree', defaultValue: '$Family', + selectLabel: localized('Taxon'), fieldsData: { '$-any': { + optionLabel: '(any rank)', + isRelationship: true, isDefault: false, isEnabled: true, - isRelationship: true, - optionLabel: '(any rank)', tableName: 'Taxon', }, - $Class: { - isDefault: false, + $Kingdom: { + optionLabel: 'Kingdom', isRelationship: true, - optionLabel: 'Class', + isDefault: false, tableName: 'Taxon', }, - $Family: { - isDefault: true, + $Phylum: { + optionLabel: 'Phylum', isRelationship: true, - optionLabel: 'Family', - tableName: 'Taxon', - }, - $Genus: { isDefault: false, - isRelationship: true, - optionLabel: 'Genus', tableName: 'Taxon', }, - $Kingdom: { - isDefault: false, + $Class: { + optionLabel: 'Class', isRelationship: true, - optionLabel: 'Kingdom', + isDefault: false, tableName: 'Taxon', }, $Order: { - isDefault: false, - isRelationship: true, optionLabel: 'Order', - tableName: 'Taxon', - }, - $Phylum: { - isDefault: false, isRelationship: true, - optionLabel: 'Phylum', + isDefault: false, tableName: 'Taxon', }, - $Species: { - isDefault: false, + $Family: { + optionLabel: 'Family', isRelationship: true, - optionLabel: 'Species', + isDefault: true, tableName: 'Taxon', }, $Subfamily: { + optionLabel: 'Subfamily', + isRelationship: true, isDefault: false, + tableName: 'Taxon', + }, + $Genus: { + optionLabel: 'Genus', isRelationship: true, - optionLabel: 'Subfamily', + isDefault: false, tableName: 'Taxon', }, $Subgenus: { + optionLabel: 'Subgenus', + isRelationship: true, isDefault: false, + tableName: 'Taxon', + }, + $Species: { + optionLabel: 'Species', isRelationship: true, - optionLabel: 'Subgenus', + isDefault: false, tableName: 'Taxon', }, $Subspecies: { - isDefault: false, - isRelationship: true, optionLabel: 'Subspecies', + isRelationship: true, + isDefault: false, tableName: 'Taxon', }, }, - selectLabel: localized('Taxon'), tableName: 'Taxon', }, { customSelectSubtype: 'simple', defaultValue: 'name', + selectLabel: localized('Taxon'), fieldsData: { author: { - isDefault: false, + optionLabel: 'Author', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Author', }, fullName: { - isDefault: false, + optionLabel: 'Full Name', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Full Name', }, commonName: { - isDefault: false, + optionLabel: 'Common Name', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Common Name', }, guid: { - isDefault: false, + optionLabel: 'GUID', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'GUID', }, isAccepted: { isDefault: false, @@ -991,47 +1001,46 @@ theories(getMappingLineData, [ optionLabel: 'Is Preferred', }, isHybrid: { - isDefault: false, + optionLabel: 'Is Hybrid', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Is Hybrid', }, name: { - isDefault: true, + optionLabel: 'Name', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: true, isRelationship: false, - isRequired: false, - optionLabel: 'Name', }, rankId: { - isDefault: false, + optionLabel: 'Rank ID', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Rank ID', }, remarks: { - isDefault: false, + optionLabel: 'Remarks', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Remarks', }, source: { - isDefault: false, + optionLabel: 'Source', isEnabled: true, + isRequired: false, isHidden: false, + isDefault: false, isRelationship: false, - isRequired: false, - optionLabel: 'Source', }, }, - selectLabel: localized('Taxon'), tableName: 'Taxon', }, ], diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts index f15346f1760..5b3e098584f 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/navigatorSpecs.ts @@ -56,7 +56,7 @@ const wbPlanView: NavigatorSpec = { * Hide nested -to-many relationships as they are not * supported by the WorkBench */ - allowNestedToMany: false, + allowNestedToMany: true, ensurePermission: () => userPreferences.get('workBench', 'wbPlanView', 'showNoAccessTables') ? 'create' diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanBuilder.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanBuilder.ts index 8be421c3cd2..636526249f6 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanBuilder.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanBuilder.ts @@ -1,5 +1,5 @@ import type { IR, RA, RR } from '../../utils/types'; -import { group, removeKey, split, toLowerCase } from '../../utils/utils'; +import { group, split, toLowerCase } from '../../utils/utils'; import type { AnyTree } from '../DataModel/helperTypes'; import type { SpecifyTable } from '../DataModel/specifyTable'; import { strictGetTable } from '../DataModel/tables'; @@ -143,13 +143,10 @@ function toUploadTable( [ fieldName.toLowerCase(), indexMappings(lines).map(([_index, lines]) => - removeKey( - toUploadTable( - table.strictGetRelationship(fieldName).relatedTable, - lines, - mustMatchPreferences - ), - 'toMany' + toUploadTable( + table.strictGetRelationship(fieldName).relatedTable, + lines, + mustMatchPreferences ) ), ] as const diff --git a/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanParser.ts b/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanParser.ts index 5d354807723..d05fc192601 100644 --- a/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanParser.ts +++ b/specifyweb/frontend/js_src/lib/components/WbPlanView/uploadPlanParser.ts @@ -1,5 +1,5 @@ -import type { IR, RA, RR } from '../../utils/types'; -import type { AnyTree } from '../DataModel/helperTypes'; +import type { IR, PartialBy, RA, RR } from '../../utils/types'; +import { AnyTree } from '../DataModel/helperTypes'; import type { SpecifyTable } from '../DataModel/specifyTable'; import { strictGetTable } from '../DataModel/tables'; import type { Tables } from '../DataModel/types'; @@ -24,7 +24,11 @@ export type ColumnDefinition = | string | (ColumnOptions & { readonly column: string }); -export type NestedUploadTable = Omit; +/* + * NOTE: This comment was added after workbench supports nested-to-manys. + * Type is made Partial to not chock on legacy upload plans + */ +export type NestedUploadTable = PartialBy; export type UploadTable = { readonly wbcols: IR; @@ -147,23 +151,21 @@ const parseUploadTable = ( [...mappingPath, table.strictGetRelationship(relationshipName).name] ) ), - ...('toMany' in uploadPlan - ? Object.entries(uploadPlan.toMany).flatMap( - ([relationshipName, mappings]) => - Object.values(mappings).flatMap((mapping, index) => - parseUploadTable( - table.strictGetRelationship(relationshipName).relatedTable, - mapping, - makeMustMatch, - [ - ...mappingPath, - table.strictGetRelationship(relationshipName).name, - formatToManyIndex(index + 1), - ] - ) - ) + ...Object.entries(uploadPlan.toMany ?? []).flatMap( + ([relationshipName, mappings]) => + Object.values(mappings).flatMap((mapping, index) => + parseUploadTable( + table.strictGetRelationship(relationshipName).relatedTable, + mapping, + makeMustMatch, + [ + ...mappingPath, + table.strictGetRelationship(relationshipName).name, + formatToManyIndex(index + 1), + ] + ) ) - : []), + ), ]; function parseUploadTableTypes( diff --git a/specifyweb/frontend/js_src/lib/localization/attachments.ts b/specifyweb/frontend/js_src/lib/localization/attachments.ts index ea0db3bde7b..d99287b0699 100644 --- a/specifyweb/frontend/js_src/lib/localization/attachments.ts +++ b/specifyweb/frontend/js_src/lib/localization/attachments.ts @@ -683,9 +683,9 @@ export const attachmentsText = createDictionary({ 'en-us': 'Download all found attachments', }, deleteAttachmentWarning: { - 'en-us': 'Are you sure you want to delete this attachment?' + 'en-us': 'Are you sure you want to delete this attachment?', }, attachmentDelition: { - 'en-us': 'Attachment deletion' - } + 'en-us': 'Attachment deletion', + }, } as const); diff --git a/specifyweb/frontend/js_src/lib/localization/interactions.ts b/specifyweb/frontend/js_src/lib/localization/interactions.ts index 34160d9b5c0..83d75f4c79e 100644 --- a/specifyweb/frontend/js_src/lib/localization/interactions.ts +++ b/specifyweb/frontend/js_src/lib/localization/interactions.ts @@ -388,6 +388,6 @@ export const interactionsText = createDictionary({ 'uk-ua': 'Продовжуйте без підготовки', }, notAvailable: { - 'en-us': 'Not available' - } + 'en-us': 'Not available', + }, } as const); diff --git a/specifyweb/frontend/js_src/lib/tests/fixtures/uploadplan.1.json b/specifyweb/frontend/js_src/lib/tests/fixtures/uploadplan.1.json index f0cc682997a..ea0336746b4 100644 --- a/specifyweb/frontend/js_src/lib/tests/fixtures/uploadplan.1.json +++ b/specifyweb/frontend/js_src/lib/tests/fixtures/uploadplan.1.json @@ -160,7 +160,8 @@ "toMany": {} } } - } + }, + "toMany": {} }, { "wbcols": {}, @@ -179,7 +180,8 @@ "toMany": {} } } - } + }, + "toMany": {} }, { "wbcols": {}, @@ -198,7 +200,8 @@ "toMany": {} } } - } + }, + "toMany": {} }, { "wbcols": {}, @@ -217,7 +220,8 @@ "toMany": {} } } - } + }, + "toMany": {} } ] } @@ -246,7 +250,8 @@ "toMany": {} } } - } + }, + "toMany": {} } ] } @@ -328,7 +333,8 @@ "toMany": {} } } - } + }, + "toMany": {} }, { "wbcols": { @@ -346,7 +352,8 @@ "toMany": {} } } - } + }, + "toMany": {} } ], "preparations": [ @@ -364,7 +371,8 @@ "toMany": {} } } - } + }, + "toMany": {} } ] }