Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions assets/js/components/record_details/CommitteeApproval.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class CommitteeApprovalManageSection extends Component {
// Public EP-approved record — show a compact provenance note.
if (committeeApproval.is_public_approved_record) {
const {
approval_label: approvalLabel,
approved_report_number: pubRn,
draft_record_id: draftRecordId,
can_view_reviewed_version: canViewReviewedVersion,
Expand All @@ -73,7 +74,11 @@ export class CommitteeApprovalManageSection extends Component {
return (
<Grid.Column className="pb-20 pt-0">
<Divider horizontal>
<Header as="h4">{i18next.t("Approval request workflow")}</Header>
<Header as="h4">
{i18next.t("{{approvalLabel}} request workflow", {
approvalLabel,
})}
</Header>
</Divider>

<p className="text-muted text-align-center">
Expand Down Expand Up @@ -104,6 +109,8 @@ export class CommitteeApprovalManageSection extends Component {
const {
can_submit: canSubmit,
can_create_public: canCreatePublicFlag,
approval_label: approvalLabel,
committee_name: committeeName,
open_request: openRequest,
approved_report_number: approvedReportNumber,
receiver_group: receiverGroup,
Expand Down Expand Up @@ -151,7 +158,11 @@ export class CommitteeApprovalManageSection extends Component {
return (
<Grid.Column className="pb-20 pt-0">
<Divider horizontal>
<Header as="h4">{i18next.t("Approval request workflow")}</Header>
<Header as="h4">
{i18next.t("{{approvalLabel}} request workflow", {
approvalLabel,
})}
</Header>
</Divider>

<Step.Group
Expand Down Expand Up @@ -191,7 +202,12 @@ export class CommitteeApprovalManageSection extends Component {
) : step1Completed ? (
i18next.t("Request submitted.")
) : (
i18next.t("Submit the document for EP committee review.")
i18next.t(
"Submit the document for {{committeeName}} review.",
{
committeeName,
}
)
)}
</Step.Description>
</div>
Expand Down Expand Up @@ -228,7 +244,11 @@ export class CommitteeApprovalManageSection extends Component {
<Step.Content>
<div className="committee-action-step">
<div>
<Step.Title>{i18next.t("EP Board review")}</Step.Title>
<Step.Title>
{i18next.t("{{committeeName}} review", {
committeeName,
})}
</Step.Title>
<Step.Description>
{step2Completed ? (
requestLink ? (
Expand All @@ -245,7 +265,10 @@ export class CommitteeApprovalManageSection extends Component {
)
) : (
i18next.t(
"The EP secretariat will review the submission."
"The {{committeeName}} will review the submission.",
{
committeeName,
}
)
)}
</Step.Description>
Expand Down Expand Up @@ -295,9 +318,7 @@ export class CommitteeApprovalManageSection extends Component {
i18next.t("Public record created.")
)
) : (
i18next.t(
"Publish the EP-approved record publicly on CDS."
)
i18next.t("Publish the approved record publicly on CDS.")
)}
</Step.Description>
</div>
Expand Down
33 changes: 22 additions & 11 deletions assets/js/components/record_details/NewVersionButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ import { http } from "react-invenio-forms";
import { Button, Icon, Modal, Popup } from "semantic-ui-react";
import { i18next } from "@translations/invenio_rdm_records/i18next";

const readCommitteeApprovalState = () => {
const recordManagementDiv = document.getElementById("recordManagement");
return recordManagementDiv
? JSON.parse(recordManagementDiv.dataset.committeeApproval || "null")
: null;
};

export const NewVersionButton = ({ onError, record, disabled, ...uiProps }) => {
const [loading, setLoading] = useState(false);
const [showModal, setShowModal] = useState(false);

const committeeApprovalStatus = useMemo(() => {
const recordManagementDiv = document.getElementById("recordManagement");
return recordManagementDiv
? JSON.parse(recordManagementDiv.dataset.committeeApproval || "null")
?.open_request?.status
: null;
}, []);
const committeeApproval = useMemo(readCommitteeApprovalState, []);
const committeeApprovalStatus = committeeApproval?.open_request?.status;
const approvalLabel =
committeeApproval?.approval_label || i18next.t("Committee approval");

const handleClick = useCallback(async () => {
if (
Expand Down Expand Up @@ -80,17 +84,24 @@ export const NewVersionButton = ({ onError, record, disabled, ...uiProps }) => {
<Icon name="warning sign" color="yellow" className="mr-10" />

{committeeApprovalStatus === "submitted" &&
i18next.t("EP approval request pending")}
i18next.t("{{approvalLabel}} request pending", {
approvalLabel,
})}
{committeeApprovalStatus === "accepted" &&
i18next.t("EP approval already complete")}
i18next.t("{{approvalLabel}} already complete", {
approvalLabel,
})}
</Modal.Header>
<Modal.Content>
{committeeApprovalStatus === "submitted" && (
<>
<p>
{i18next.t(
"An EP approval request is already pending for an existing version of this record. " +
"A new version will not be taken into account for the approval request."
"An {{approvalLabel}} request is already pending for an existing version of this record. " +
"A new version will not be taken into account for the {{approvalLabel}} request.",
{
approvalLabel,
}
)}
</p>
<p>
Expand Down
18 changes: 17 additions & 1 deletion assets/js/invenio_app_rdm/overridableRegistry/mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
// CDS RDM is free software; you can redistribute it and/or modify it
// under the terms of the GPL-2.0 License; see LICENSE file for more details.

import React from "react";
import React, { useContext } from "react";
import { DatasetContext } from "@js/invenio_requests/data";
import { i18next as requestsI18next } from "@translations/invenio_requests/i18next";
import { Label } from "semantic-ui-react";
import { BasicCERNInformation } from "../../components/deposit/BasicInformation";
import { CDSCarouselItem } from "../../components/communities_carousel/overrides/CarouselItem";
import { CDSRecordsList } from "../../components/frontpage/overrides/RecordsList";
Expand All @@ -29,6 +32,17 @@ const RecordManagementContainer = (props) => (
</>
);

const CommunitySubmissionRequestTypeLabel = () => {
const dataset = useContext(DatasetContext);
const approvalLabel = dataset?.request?.approval_label;

return (
<Label horizontal className="primary theme-secondary" size="small">
{approvalLabel || requestsI18next.t("Draft review")}
</Label>
);
};

export const overriddenComponents = {
"InvenioAppRdm.RecordsList.layout": CDSRecordsList,
"InvenioAppRdm.RecordsResultsListItem.layout": CDSRecordsResultsListItem,
Expand All @@ -48,6 +62,8 @@ export const overriddenComponents = {
"InvenioRdmRecords.RecordLandingPage.RecordManagement.NewVersionButton":
NewVersionButton,
"InvenioRequests.LockRequest": LockRequestComponent,
"RequestTypeLabel.layout.community-submission":
CommunitySubmissionRequestTypeLabel,
"InvenioAppRdm.RecordVersionsList.Item.container": RecordVersionItemContent,
"InvenioRequests.TimelineEventBody": TimelineEventBodyComponent,
};
11 changes: 8 additions & 3 deletions invenio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ from cds_rdm.notifications.committee_approval import (
CommitteeApprovalDeclineNotificationBuilder,
CommitteeApprovalSubmitNotificationBuilder,
)
from cds_rdm.requests.committee_approval import CommitteeApprovalCommunitySubmission
from cds_rdm.api import CDSRDMRecord, CDSRDMDraft
from invenio_cern_sync.sso import cern_keycloak, cern_remote_app_name
from invenio_cern_sync.users.profile import CERNUserProfileSchema
Expand Down Expand Up @@ -461,7 +462,8 @@ CDS_COMMITTEE_APPROVAL_COMMUNITIES = {
# UUIDs are used (not slugs) because slugs can be renamed.
#
# "4b121eb9-3559-487d-9f73-8af1027668e9": {
# "label": "EP approval", # shown in UI buttons/headings
# "label": "EP approval", # shown in request buttons/headings
# "committee_name": "EP Board", # shown in review-step labels/text
# "referee_group": "cds-ph-ep-publication", # CERN e-group slug
# "report_number": {
# "prefix": "CERN-EP", # literal prefix, e.g. "CERN-EP"
Expand All @@ -473,7 +475,10 @@ CDS_COMMITTEE_APPROVAL_COMMUNITIES = {
"""Communities enrolled in the Publication Approval Workflow.

Keyed by community UUID. Each entry must have:
- ``label``: human-readable name shown in the UI (e.g. "EP approval")
- ``label``: human-readable workflow label shown in the UI
(e.g. "EP approval")
- ``committee_name`` (optional): reviewer/board name shown in review-step
labels and text (e.g. "EP Board")
- ``referee_group``: CERN e-group whose members act as referees
- ``report_number``: dict with:
- ``prefix`` (str): fixed prefix, e.g. ``"CERN-EP"``
Expand All @@ -487,7 +492,7 @@ enforced across all enrolled communities.
CHECKS_ENABLED = True
"""Enable metadata checks."""

RDM_COMMUNITY_SUBMISSION_REQUEST_CLS = checks_requests.CommunitySubmission
RDM_COMMUNITY_SUBMISSION_REQUEST_CLS = CommitteeApprovalCommunitySubmission

RDM_COMMUNITY_INCLUSION_REQUEST_CLS = checks_requests.CommunityInclusion
# require a community when publishing
Expand Down
29 changes: 29 additions & 0 deletions site/cds_rdm/requests/committee_approval.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from invenio_i18n import lazy_gettext as _
from invenio_notifications.services.uow import NotificationOp
from invenio_pidstore.models import PersistentIdentifier, PIDStatus
from invenio_rdm_records.checks import requests as checks_requests
from invenio_rdm_records.proxies import current_rdm_records_service
from invenio_rdm_records.records.api import RDMRecord
from invenio_rdm_records.requests.base import BaseRequest as RDMBaseRequest
Expand Down Expand Up @@ -77,6 +78,16 @@ def _resolve_community_config(request):
)


def _community_submission_approval_label(request):
"""Return the configured label for a community submission request."""
community_id = (request.get("receiver") or {}).get("community")
return (
current_app.config.get("CDS_COMMITTEE_APPROVAL_COMMUNITIES", {})
.get(str(community_id), {})
.get("label")
)


class CommitteeApprovalSubmitAction(actions.CreateAndSubmitAction):
"""Submit action — validate community enrollment and notify referees."""

Expand Down Expand Up @@ -343,6 +354,8 @@ class CommitteeApprovalRequest(RDMBaseRequest):

# Payload fields collected from the submission form.
payload_schema: Final[dict] = {
# Captured at submission for request-page and email display.
"approval_label": fields.Str(load_default=None),
# Populated on accept by the system.
"approved_report_number": fields.Str(load_default=None),
# Form fields.
Expand All @@ -354,3 +367,19 @@ class CommitteeApprovalRequest(RDMBaseRequest):
"controversy": fields.Bool(load_default=False),
"additional_communication": fields.Str(load_default=None),
}


class CommitteeApprovalCommunitySubmission(checks_requests.CommunitySubmission):
"""Community submission that exposes its configured UI label."""

@classmethod
def _create_marshmallow_schema(cls):
"""Add the configured label when serializing existing requests."""
schema = super()._create_marshmallow_schema()
return schema.from_dict(
{
"approval_label": fields.Function(
serialize=_community_submission_approval_label
)
}
)
20 changes: 19 additions & 1 deletion site/cds_rdm/requests/committee_approval_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
from invenio_requests.proxies import current_requests_service


def _approval_label(community_config=None):
"""Return the UI label for this workflow."""
return (community_config or {}).get("label")


def _committee_name(community_config=None):
"""Return the configured reviewer/board name for this workflow."""
return (community_config or {}).get("committee_name")


def _get_enrolled_community(record_ui):
"""Return (community_id, community_config) for enrolled communities, else (None, None)."""
ep_communities = current_app.config.get("CDS_COMMITTEE_APPROVAL_COMMUNITIES", {})
Expand Down Expand Up @@ -139,6 +149,8 @@ def get_committee_approval_state(record_ui, record=None):
Returns a dict with:
- can_submit: bool
- can_create_public: bool
- approval_label: str
- committee_name: str or None
- community_enrolled: bool
- is_public_approved_record: bool
- open_request: dict or None — {id, status, links}
Expand All @@ -150,6 +162,7 @@ def get_committee_approval_state(record_ui, record=None):
"""
# Read committee_approval from the parent.
ea = _get_parent_committee_approval(record)
community_id, community_config = _get_enrolled_community(record_ui)

# Early exit: this IS the public committee-approved copy.
# The public record's parent has source_internal_version set.
Expand All @@ -167,6 +180,8 @@ def get_committee_approval_state(record_ui, record=None):
return {
"can_submit": False,
"can_create_public": False,
"approval_label": _approval_label(community_config),
"committee_name": _committee_name(community_config),
"community_enrolled": False,
"is_public_approved_record": True,
"open_request": None,
Expand All @@ -180,11 +195,12 @@ def get_committee_approval_state(record_ui, record=None):
}

# Check community enrollment.
community_id, community_config = _get_enrolled_community(record_ui)
if community_id is None:
return {
"can_submit": False,
"can_create_public": False,
"approval_label": _approval_label(),
"committee_name": None,
"community_enrolled": False,
"is_public_approved_record": False,
"open_request": None,
Expand Down Expand Up @@ -217,6 +233,8 @@ def get_committee_approval_state(record_ui, record=None):
return {
"can_submit": can_submit,
"can_create_public": can_create_public,
"approval_label": _approval_label(community_config),
"committee_name": _committee_name(community_config),
"community_enrolled": True,
"is_public_approved_record": False,
"open_request": open_request,
Expand Down
10 changes: 10 additions & 0 deletions site/cds_rdm/requests/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ def submit_committee_approval(pid_value):
)

title = record.data.get("metadata", {}).get("title", "")
default_community_id = (
record._record.parent.get("communities", {}) or {}
).get("default")
approval_label = (
current_app.config.get("CDS_COMMITTEE_APPROVAL_COMMUNITIES", {})
.get(default_community_id, {})
.get("label")
or "Committee approval"
)
payload["approval_label"] = approval_label
req = current_requests_service.create(
identity=g.identity,
data={
Expand Down
Loading
Loading