-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add series data entry feature #4804
base: production
Are you sure you want to change the base?
Changes from all commits
f1c1404
0680b87
b8ba0aa
a52b782
0638e98
d4a2a1b
846bc2a
5cf1c90
97b1a7a
533511d
cc5bda5
b9400bb
aa8cf79
b05fa4a
69f22bc
e3979d4
72ab487
c6005bc
85342bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,11 @@ import { commonText } from '../../localization/common'; | |
import { formsText } from '../../localization/forms'; | ||
import { smoothScroll } from '../../utils/dom'; | ||
import { listen } from '../../utils/events'; | ||
import type { RA, WritableArray } from '../../utils/types'; | ||
import { replaceKey } from '../../utils/utils'; | ||
import { Button } from '../Atoms/Button'; | ||
import { className } from '../Atoms/className'; | ||
import { Input, Label } from '../Atoms/Form'; | ||
import { Submit } from '../Atoms/Submit'; | ||
import { LoadingContext } from '../Core/Contexts'; | ||
import type { AnySchema } from '../DataModel/helperTypes'; | ||
|
@@ -55,6 +57,8 @@ export function SaveButton<SCHEMA extends AnySchema = AnySchema>({ | |
onSaving: handleSaving, | ||
onSaved: handleSaved, | ||
onAdd: handleAdd, | ||
onCarryBulk: handleCarryBulk, | ||
isInRecordSet, | ||
}: { | ||
readonly resource: SpecifyResource<SCHEMA>; | ||
readonly form: HTMLFormElement; | ||
|
@@ -73,6 +77,8 @@ export function SaveButton<SCHEMA extends AnySchema = AnySchema>({ | |
readonly onAdd?: (newResource: SpecifyResource<SCHEMA>) => void; | ||
// Only display save blockers for a given field | ||
readonly filterBlockers?: LiteralField | Relationship; | ||
readonly onCarryBulk?: (ids: RA<number>) => void; | ||
readonly isInRecordSet?: boolean; | ||
}): JSX.Element { | ||
const id = useId('save-button'); | ||
const saveRequired = useIsModified(resource); | ||
|
@@ -195,7 +201,10 @@ export function SaveButton<SCHEMA extends AnySchema = AnySchema>({ | |
const copyButton = ( | ||
label: LocalizedString, | ||
description: LocalizedString, | ||
handleClick: () => Promise<SpecifyResource<SCHEMA>> | ||
handleClick: () => | ||
| Promise<RA<SpecifyResource<SCHEMA>>> | ||
| Promise<SpecifyResource<SCHEMA>>, | ||
CarolineDenis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
originalResourceId?: number | ||
): JSX.Element => ( | ||
<ButtonComponent | ||
className={saveBlocked ? '!cursor-not-allowed' : undefined} | ||
|
@@ -204,17 +213,69 @@ export function SaveButton<SCHEMA extends AnySchema = AnySchema>({ | |
onClick={(): void => { | ||
// Scroll to the top of the form on clone | ||
smoothScroll(form, 0); | ||
loading(handleClick().then(handleAdd)); | ||
loading( | ||
handleClick() | ||
.then((result) => { | ||
const ids: WritableArray<number> = []; | ||
if (originalResourceId !== undefined) { | ||
ids.push(originalResourceId); | ||
} | ||
if (Array.isArray(result)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. change the signature of handleAdd() to make it be callable with an array of resources rather than one resource There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and once handleAdd() is being called with an array, there won't be need for handleCarryBulk() anymore as it can be combined |
||
result.forEach((newResource) => { | ||
handleAdd?.(newResource); | ||
ids.push(newResource.id); | ||
}); | ||
} else { | ||
handleAdd?.(result); | ||
} | ||
return ids; | ||
}) | ||
.then((ids) => { | ||
if (handleCarryBulk && ids.length > 2) { | ||
handleCarryBulk(ids); | ||
} | ||
}) | ||
); | ||
}} | ||
> | ||
{label} | ||
</ButtonComponent> | ||
); | ||
|
||
const [carryForwardAmount, setCarryForwardAmount] = React.useState<number>(2); | ||
const [showBulkCarryInput, setBulkCarryInput] = React.useState(false); | ||
|
||
return ( | ||
<> | ||
{typeof handleAdd === 'function' && canCreate ? ( | ||
<> | ||
{resource.specifyTable.name === 'CollectionObject' && | ||
!isInRecordSet && | ||
!showBulkCarryInput && | ||
!resource.needsSaved ? ( | ||
<Button.Save | ||
title={commonText.bulkCarry()} | ||
onClick={() => setBulkCarryInput(true)} | ||
> | ||
{commonText.bulkCarry()} | ||
</Button.Save> | ||
) : null} | ||
{resource.specifyTable.name === 'CollectionObject' && | ||
!isInRecordSet && | ||
showBulkCarryInput ? ( | ||
<Label.Inline> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be in a dialog? |
||
{commonText.bulkCarry()} | ||
<Input.Generic | ||
type="number" | ||
value={carryForwardAmount} | ||
onValueChange={(value): void => | ||
carryForwardAmount === undefined | ||
? setCarryForwardAmount(2) | ||
: setCarryForwardAmount(Number.parseInt(value)) | ||
} | ||
/> | ||
</Label.Inline> | ||
) : null} | ||
{showClone && | ||
copyButton( | ||
formsText.clone(), | ||
|
@@ -225,7 +286,29 @@ export function SaveButton<SCHEMA extends AnySchema = AnySchema>({ | |
copyButton( | ||
formsText.carryForward(), | ||
formsText.carryForwardDescription(), | ||
async () => resource.clone(false) | ||
resource.specifyTable.name === 'CollectionObject' && | ||
carryForwardAmount > 2 | ||
? async () => { | ||
const clones = Array.from( | ||
{ length: carryForwardAmount }, | ||
async () => { | ||
const clonedResource = await resource.clone(false); | ||
const formatter = clonedResource.specifyTable | ||
.strictGetLiteralField('catalogNumber') | ||
.getUiFormatter()!; | ||
const wildCard = formatter.valueOrWild(); | ||
CarolineDenis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
await clonedResource.set( | ||
'catalogNumber', | ||
wildCard as never | ||
); | ||
await clonedResource.save(); | ||
return clonedResource; | ||
} | ||
); | ||
return Promise.all(clones); | ||
} | ||
: async () => resource.clone(false), | ||
resource.id | ||
)} | ||
{showAdd && | ||
copyButton( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
once you change the code to remove handleCarryBulk and make handleAdd receive an array of resources, you won't need to do re-fetching of resources manually here as handleAdd is already being called with fetched resource