-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
1,091 additions
and
692 deletions.
There are no files selected for viewing
634 changes: 0 additions & 634 deletions
634
...ords/assets/semantic-ui/js/invenio_rdm_records/src/deposit/fields/Identifiers/PIDField.js
This file was deleted.
Oops, something went wrong.
228 changes: 228 additions & 0 deletions
228
...tic-ui/js/invenio_rdm_records/src/deposit/fields/Identifiers/PIDField/OptionalPIDField.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
// This file is part of Invenio-RDM-Records | ||
// Copyright (C) 2020-2025 CERN. | ||
// | ||
// Invenio-RDM-Records is free software; you can redistribute it and/or modify it | ||
// under the terms of the MIT License; see LICENSE file for more details. | ||
|
||
import _debounce from "lodash/debounce"; | ||
import PropTypes from "prop-types"; | ||
import React, { Component } from "react"; | ||
import { FieldLabel } from "react-invenio-forms"; | ||
import { Form } from "semantic-ui-react"; | ||
import { | ||
ManagedIdentifierCmp, | ||
OptionalDOIoptions, | ||
UnmanagedIdentifierCmp, | ||
} from "./components"; | ||
import { getFieldErrors } from "./components/helpers"; | ||
|
||
const PROVIDER_EXTERNAL = "external"; | ||
const UPDATE_PID_DEBOUNCE_MS = 200; | ||
|
||
/** | ||
* Render managed or unamanged PID fields and update | ||
* Formik form on input changed. | ||
* The field value has the following format: | ||
* { 'doi': { identifier: '<value>', provider: '<value>', client: '<value>' } } | ||
*/ | ||
export class OptionalPIDField extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
const { canBeManaged, canBeUnmanaged, record, field } = this.props; | ||
this.canBeManagedAndUnmanaged = canBeManaged && canBeUnmanaged; | ||
const value = field?.value; | ||
const isInternalProvider = value?.provider !== PROVIDER_EXTERNAL; | ||
const isDraft = record?.is_draft === true; | ||
const hasIdentifier = value?.identifier; | ||
const isManagedSelected = | ||
isDraft && hasIdentifier && isInternalProvider ? true : undefined; | ||
|
||
this.state = { | ||
isManagedSelected: isManagedSelected, | ||
isNoNeedSelected: undefined, | ||
}; | ||
} | ||
|
||
onExternalIdentifierChanged = (identifier) => { | ||
const { form, fieldPath } = this.props; | ||
|
||
const pid = { | ||
identifier: identifier, | ||
provider: PROVIDER_EXTERNAL, | ||
}; | ||
|
||
this.debounced && this.debounced.cancel(); | ||
this.debounced = _debounce(() => { | ||
form.setFieldValue(fieldPath, pid); | ||
}, UPDATE_PID_DEBOUNCE_MS); | ||
this.debounced(); | ||
}; | ||
|
||
render() { | ||
const { isManagedSelected, isNoNeedSelected } = this.state; | ||
const { | ||
btnLabelDiscardPID, | ||
btnLabelGetPID, | ||
canBeManaged, | ||
canBeUnmanaged, | ||
form, | ||
fieldPath, | ||
fieldLabel, | ||
isEditingPublishedRecord, | ||
managedHelpText, | ||
pidLabel, | ||
pidIcon, | ||
pidPlaceholder, | ||
required, | ||
unmanagedHelpText, | ||
pidType, | ||
field, | ||
record, | ||
optionalDOItransitions, | ||
} = this.props; | ||
|
||
let { doiDefaultSelection } = this.props; | ||
|
||
const value = field.value || {}; | ||
const currentIdentifier = value.identifier || ""; | ||
const currentProvider = value.provider || ""; | ||
|
||
let managedIdentifier = "", | ||
unmanagedIdentifier = ""; | ||
if (currentIdentifier !== "") { | ||
const isProviderExternal = currentProvider === PROVIDER_EXTERNAL; | ||
managedIdentifier = !isProviderExternal ? currentIdentifier : ""; | ||
unmanagedIdentifier = isProviderExternal ? currentIdentifier : ""; | ||
} | ||
|
||
const hasManagedIdentifier = managedIdentifier !== ""; | ||
const hasUnmanagedIdentifier = unmanagedIdentifier !== ""; | ||
const doi = record?.pids?.doi?.identifier || ""; | ||
const parentDoi = record.parent?.pids?.doi?.identifier || ""; | ||
|
||
const hasDoi = doi !== ""; | ||
const hasParentDoi = parentDoi !== ""; | ||
const isDraft = record.is_draft; | ||
|
||
const _isUnmanagedSelected = | ||
isManagedSelected === undefined | ||
? hasUnmanagedIdentifier || | ||
(currentIdentifier === "" && doiDefaultSelection === "yes") | ||
: !isManagedSelected; | ||
|
||
const _isManagedSelected = | ||
isManagedSelected === undefined | ||
? hasManagedIdentifier || | ||
(currentIdentifier === "" && doiDefaultSelection === "no") // i.e pids: {} | ||
: isManagedSelected; | ||
|
||
const _isNoNeedSelected = | ||
isNoNeedSelected === undefined | ||
? (!_isManagedSelected && !_isUnmanagedSelected) || | ||
(isDraft !== true && | ||
currentIdentifier === "" && | ||
doiDefaultSelection === "not_needed") | ||
: isNoNeedSelected; | ||
|
||
const fieldError = getFieldErrors(form, fieldPath); | ||
|
||
return ( | ||
<> | ||
<Form.Field | ||
required={required || hasParentDoi} | ||
error={fieldError ? true : false} | ||
> | ||
<FieldLabel htmlFor={fieldPath} icon={pidIcon} label={fieldLabel} /> | ||
</Form.Field> | ||
|
||
{this.canBeManagedAndUnmanaged && ( | ||
<OptionalDOIoptions | ||
optionalDOItransitions={optionalDOItransitions} | ||
isManagedSelected={_isManagedSelected} | ||
isNoNeedSelected={_isNoNeedSelected} | ||
onManagedUnmanagedChange={(userSelectedManaged, userSelectedNoNeed) => { | ||
if (userSelectedManaged) { | ||
form.setFieldValue("pids", {}); | ||
if (!required) { | ||
// We set the value as required so we can validate the action on submit | ||
form.setFieldValue("noINeedDOI", true); | ||
} | ||
} else if (userSelectedNoNeed) { | ||
form.setFieldValue("pids", {}); | ||
form.setFieldValue("noINeedDOI", false); | ||
} else { | ||
this.onExternalIdentifierChanged(""); | ||
form.setFieldValue("noINeedDOI", false); | ||
} | ||
form.setFieldError(fieldPath, false); | ||
this.setState({ | ||
isManagedSelected: userSelectedManaged, | ||
isNoNeedSelected: userSelectedNoNeed, | ||
}); | ||
}} | ||
pidLabel={pidLabel} | ||
required={required} | ||
/> | ||
)} | ||
|
||
{canBeManaged && _isManagedSelected && ( | ||
<ManagedIdentifierCmp | ||
disabled={hasDoi && isEditingPublishedRecord} | ||
btnLabelDiscardPID={btnLabelDiscardPID} | ||
btnLabelGetPID={btnLabelGetPID} | ||
form={form} | ||
fieldPath={fieldPath} | ||
identifier={managedIdentifier} | ||
helpText={managedHelpText} | ||
pidPlaceholder={pidPlaceholder} | ||
pidType={pidType} | ||
pidLabel={pidLabel} | ||
/> | ||
)} | ||
|
||
{canBeUnmanaged && (!_isManagedSelected || _isNoNeedSelected) && ( | ||
<UnmanagedIdentifierCmp | ||
identifier={unmanagedIdentifier} | ||
onIdentifierChanged={(identifier) => { | ||
this.onExternalIdentifierChanged(identifier); | ||
}} | ||
form={form} | ||
fieldPath={fieldPath} | ||
pidPlaceholder={pidPlaceholder} | ||
helpText={unmanagedHelpText} | ||
disabled={_isNoNeedSelected} | ||
/> | ||
)} | ||
</> | ||
); | ||
} | ||
} | ||
|
||
OptionalPIDField.propTypes = { | ||
field: PropTypes.object, | ||
form: PropTypes.object.isRequired, | ||
btnLabelDiscardPID: PropTypes.string.isRequired, | ||
btnLabelGetPID: PropTypes.string.isRequired, | ||
canBeManaged: PropTypes.bool.isRequired, | ||
canBeUnmanaged: PropTypes.bool.isRequired, | ||
fieldPath: PropTypes.string.isRequired, | ||
fieldLabel: PropTypes.string.isRequired, | ||
isEditingPublishedRecord: PropTypes.bool.isRequired, | ||
managedHelpText: PropTypes.string, | ||
pidIcon: PropTypes.string.isRequired, | ||
pidLabel: PropTypes.string.isRequired, | ||
pidPlaceholder: PropTypes.string.isRequired, | ||
pidType: PropTypes.string.isRequired, | ||
required: PropTypes.bool.isRequired, | ||
unmanagedHelpText: PropTypes.string, | ||
record: PropTypes.object.isRequired, | ||
doiDefaultSelection: PropTypes.object.isRequired, | ||
optionalDOItransitions: PropTypes.array.isRequired, | ||
}; | ||
|
||
OptionalPIDField.defaultProps = { | ||
managedHelpText: null, | ||
unmanagedHelpText: null, | ||
field: undefined, | ||
}; |
70 changes: 70 additions & 0 deletions
70
...semantic-ui/js/invenio_rdm_records/src/deposit/fields/Identifiers/PIDField/PIDFieldCmp.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// This file is part of Invenio-RDM-Records | ||
// Copyright (C) 2020-2023 CERN. | ||
// Copyright (C) 2020-2022 Northwestern University. | ||
// | ||
// Invenio-RDM-Records is free software; you can redistribute it and/or modify it | ||
// under the terms of the MIT License; see LICENSE file for more details. | ||
|
||
import { FastField } from "formik"; | ||
import PropTypes from "prop-types"; | ||
import React, { Component } from "react"; | ||
import { RequiredPIDField } from "./RequiredPIDField"; | ||
import { OptionalPIDField } from "./OptionalPIDField"; | ||
|
||
/** | ||
* Render the PIDField using a custom Formik component | ||
*/ | ||
export class PIDField extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.validatePropValues(); | ||
} | ||
|
||
validatePropValues = () => { | ||
const { canBeManaged, canBeUnmanaged, fieldPath } = this.props; | ||
|
||
if (!canBeManaged && !canBeUnmanaged) { | ||
throw Error(`${fieldPath} must be managed, unmanaged or both.`); | ||
} | ||
}; | ||
|
||
render() { | ||
const { fieldPath, required } = this.props; | ||
const cmp = required ? RequiredPIDField : OptionalPIDField; | ||
|
||
return <FastField name={fieldPath} component={cmp} {...this.props} />; | ||
} | ||
} | ||
|
||
PIDField.propTypes = { | ||
btnLabelDiscardPID: PropTypes.string, | ||
btnLabelGetPID: PropTypes.string, | ||
canBeManaged: PropTypes.bool, | ||
canBeUnmanaged: PropTypes.bool, | ||
fieldPath: PropTypes.string.isRequired, | ||
fieldLabel: PropTypes.string.isRequired, | ||
isEditingPublishedRecord: PropTypes.bool.isRequired, | ||
managedHelpText: PropTypes.string, | ||
pidIcon: PropTypes.string, | ||
pidLabel: PropTypes.string.isRequired, | ||
pidPlaceholder: PropTypes.string, | ||
pidType: PropTypes.string.isRequired, | ||
required: PropTypes.bool, | ||
unmanagedHelpText: PropTypes.string, | ||
record: PropTypes.object.isRequired, | ||
doiDefaultSelection: PropTypes.object.isRequired, | ||
optionalDOItransitions: PropTypes.array.isRequired, | ||
}; | ||
|
||
PIDField.defaultProps = { | ||
btnLabelDiscardPID: "Discard", | ||
btnLabelGetPID: "Reserve", | ||
canBeManaged: true, | ||
canBeUnmanaged: true, | ||
managedHelpText: null, | ||
pidIcon: "barcode", | ||
pidPlaceholder: "", | ||
required: false, | ||
unmanagedHelpText: null, | ||
}; |
Oops, something went wrong.