diff --git a/CHANGELOG.md b/CHANGELOG.md index c0ab2c8f..741082ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * [UIBULKED-585](https://folio-org.atlassian.net/browse/UUIBULKED-585) Adding missing translation and filters. * [UIBULKED-561](https://folio-org.atlassian.net/browse/UUIBULKED-561) Add administrative data accordion to MARC bulk edit form. * [UIBULKED-562](https://folio-org.atlassian.net/browse/UIBULKED-562) Include statistical code option on Instances bulk edit forms. +* [UIBULKED-568](https://folio-org.atlassian.net/browse/UIBULKED-568) Populating Are you sure? form ## [4.2.2](https://github.com/folio-org/ui-bulk-edit/tree/v4.2.2) (2024-11-15) diff --git a/src/components/BulkEditLogs/BulkEditLogsActions/BulkEditLogsActions.js b/src/components/BulkEditLogs/BulkEditLogsActions/BulkEditLogsActions.js index 2b4f8c38..3da8acff 100644 --- a/src/components/BulkEditLogs/BulkEditLogsActions/BulkEditLogsActions.js +++ b/src/components/BulkEditLogs/BulkEditLogsActions/BulkEditLogsActions.js @@ -33,9 +33,7 @@ const BulkEditLogsActions = ({ item }) => { queryKey: QUERY_KEY_DOWNLOAD_LOGS, enabled: false, id: item.id, - fileInfo: { - fileContentType: linkNamesMap[triggeredFile], - }, + fileContentType: linkNamesMap[triggeredFile], onSuccess: data => { saveAs(new Blob([data]), getFileName(item, triggeredFile)); setTriggeredFile(null); diff --git a/src/components/BulkEditPane/BulkEditInAppLayer/BulkEditInAppLayer.js b/src/components/BulkEditPane/BulkEditInAppLayer/BulkEditInAppLayer.js index cf37c46c..634fae42 100644 --- a/src/components/BulkEditPane/BulkEditInAppLayer/BulkEditInAppLayer.js +++ b/src/components/BulkEditPane/BulkEditInAppLayer/BulkEditInAppLayer.js @@ -9,13 +9,11 @@ import { getMappedContentUpdates, isContentUpdatesFormValid } from '../BulkEditListResult/BulkEditInApp/ContentUpdatesForm/helpers'; -import { - QUERY_KEY_DOWNLOAD_PREVIEW_MODAL, - useContentUpdate, -} from '../../../hooks/api'; +import { useContentUpdate } from '../../../hooks/api'; import { useConfirmChanges } from '../../../hooks/useConfirmChanges'; -import { savePreviewFile } from '../../../utils/files'; import { useOptionsWithTenants } from '../../../hooks/useOptionsWithTenants'; +import { BulkEditPreviewModalFooter } from '../BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModalFooter'; +import { useCommitChanges } from '../../../hooks/useCommitChanges'; export const BulkEditInAppLayer = ({ @@ -37,28 +35,20 @@ export const BulkEditInAppLayer = ({ isPreviewLoading, bulkDetails, totalRecords, - downloadFile, confirmChanges, closePreviewModal, - } = useConfirmChanges({ - queryDownloadKey: QUERY_KEY_DOWNLOAD_PREVIEW_MODAL, - bulkOperationId, - onDownloadSuccess: (fileData, searchParams) => { - const { approach, initialFileName } = searchParams; + } = useConfirmChanges({ bulkOperationId }); - savePreviewFile({ - bulkOperationId, - fileData, - approach, - initialFileName, - }); - }, + const { commitChanges } = useCommitChanges({ + bulkOperationId, + onChangesCommited: () => { + closePreviewModal(); + onInAppLayerClose(); + } }); - const handleChangesCommited = () => { - closePreviewModal(); - onInAppLayerClose(); - }; + const isCsvFileReady = bulkDetails?.linkToModifiedRecordsCsvFile + || !isPreviewLoading; const handleConfirm = () => { const contentUpdateBody = getContentUpdatesBody({ @@ -93,9 +83,14 @@ export const BulkEditInAppLayer = ({ isPreviewLoading={isPreviewLoading} bulkDetails={bulkDetails} open={isPreviewModalOpened} - onDownload={downloadFile} - onKeepEditing={closePreviewModal} - onChangesCommited={handleChangesCommited} + modalFooter={ + + } /> ); diff --git a/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModal.js b/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModal.js index d5023f6a..cf0f8791 100644 --- a/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModal.js +++ b/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModal.js @@ -1,88 +1,26 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useHistory } from 'react-router-dom'; -import { useQueryClient } from 'react-query'; import PropTypes from 'prop-types'; import { Modal } from '@folio/stripes/components'; -import { buildSearch } from '@folio/stripes-acq-components'; import { Preloader } from '@folio/stripes-data-transfer-components'; -import { - APPROACHES, - EDITING_STEPS, - FILE_KEYS, - JOB_STATUSES, -} from '../../../../constants'; -import { BULK_OPERATION_DETAILS_KEY, useBulkOperationStart } from '../../../../hooks/api'; -import { BulkEditPreviewModalFooter } from './BulkEditPreviewModalFooter'; -import { useSearchParams } from '../../../../hooks'; import { BulkEditPreviewModalList } from './BulkEditPreviewModalList'; -import { useErrorMessages } from '../../../../hooks/useErrorMessages'; export const BulkEditPreviewModal = ({ open, - bulkDetails, isPreviewLoading, + modalFooter, onKeepEditing, - onDownload, - onChangesCommited, }) => { - const history = useHistory(); - const { criteria, approach } = useSearchParams(); - const { showErrorMessage } = useErrorMessages(); - const { bulkOperationStart } = useBulkOperationStart(); - const queryClient = useQueryClient(); - - const hasLinkForDownload = bulkDetails?.[FILE_KEYS.PROPOSED_CHANGES_LINK_MARC] || bulkDetails?.[FILE_KEYS.PROPOSED_CHANGES_LINK]; - - const downloadLabel = approach === APPROACHES.MARC - ? - : ; - - const handleBulkOperationStart = async () => { - try { - await bulkOperationStart({ - id: bulkDetails?.id, - approach: APPROACHES.IN_APP, - step: EDITING_STEPS.COMMIT, - }); - - queryClient.resetQueries(BULK_OPERATION_DETAILS_KEY); - - onChangesCommited(); - - history.replace({ - pathname: `/bulk-edit/${bulkDetails?.id}/preview`, - search: buildSearch({ - progress: criteria, - }, history.location.search), - }); - } catch (e) { - showErrorMessage(e); - } - }; - - const isModalButtonDisabled = !hasLinkForDownload || isPreviewLoading || bulkDetails?.status !== JOB_STATUSES.REVIEW_CHANGES; - return ( } aria-label="PreviewModal" - footer={ - - } + footer={modalFooter} dismissible onClose={onKeepEditing} > @@ -100,8 +38,6 @@ export const BulkEditPreviewModal = ({ BulkEditPreviewModal.propTypes = { open: PropTypes.bool, isPreviewLoading: PropTypes.bool, - bulkDetails: PropTypes.object, + modalFooter: PropTypes.node, onKeepEditing: PropTypes.func, - onChangesCommited: PropTypes.func, - onDownload: PropTypes.func, }; diff --git a/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModalFooter.js b/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModalFooter.js index ac959b46..4800c640 100644 --- a/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModalFooter.js +++ b/src/components/BulkEditPane/BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModalFooter.js @@ -5,25 +5,67 @@ import { FormattedMessage } from 'react-intl'; import { Button } from '@folio/stripes/components'; import css from './BulkEditInAppPreviewModal.css'; - +import { useSearchParams } from '../../../../hooks'; +import { APPROACHES, FILE_EXTENSION, FILE_SEARCH_PARAMS } from '../../../../constants'; +import { + QUERY_KEY_DOWNLOAD_ADMINISTRATIVE_PREVIEW_MODAL, + QUERY_KEY_DOWNLOAD_MARC_PREVIEW_MODAL, + useFileDownload +} from '../../../../hooks/api'; +import { changeExtension, savePreviewFile } from '../../../../utils/files'; export const BulkEditPreviewModalFooter = ({ - onDownload, - downloadLabel, - isCommitBtnDisabled, - isDownloadBtnDisabled, + bulkOperationId, + buttonsDisabled, onKeepEditing, - onSave, + onCommitChanges, }) => { + const { approach, initialFileName } = useSearchParams(); + + const { refetch: downloadCsvPreview } = useFileDownload({ + queryKey: QUERY_KEY_DOWNLOAD_ADMINISTRATIVE_PREVIEW_MODAL, + enabled: false, + id: bulkOperationId, + fileContentType: FILE_SEARCH_PARAMS.PROPOSED_CHANGES_FILE, + onSuccess: (fileData) => { + savePreviewFile({ + bulkOperationId, + fileData, + initialFileName, + extension: FILE_EXTENSION.CSV, + }); + }, + }); + + const { refetch: downloadMarcPreview } = useFileDownload({ + queryKey: QUERY_KEY_DOWNLOAD_MARC_PREVIEW_MODAL, + enabled: false, + id: bulkOperationId, + fileContentType: FILE_SEARCH_PARAMS.PROPOSED_CHANGES_MARC_FILE, + onSuccess: (fileData) => { + savePreviewFile({ + bulkOperationId, + fileData, + initialFileName: changeExtension(initialFileName, FILE_EXTENSION.MRC), + extension: FILE_EXTENSION.MRC, + }); + }, + }); + return (
- - + )} +
@@ -31,10 +73,8 @@ export const BulkEditPreviewModalFooter = ({ }; BulkEditPreviewModalFooter.propTypes = { - isDownloadBtnDisabled: PropTypes.bool, - isCommitBtnDisabled: PropTypes.bool, - downloadLabel: PropTypes.node, + bulkOperationId: PropTypes.string.isRequired, + buttonsDisabled: PropTypes.bool, onKeepEditing: PropTypes.func, - onDownload: PropTypes.func, - onSave: PropTypes.func, + onCommitChanges: PropTypes.func, }; diff --git a/src/components/BulkEditPane/BulkEditMarcLayer/BulkEditMarcLayer.js b/src/components/BulkEditPane/BulkEditMarcLayer/BulkEditMarcLayer.js index 3d2939ea..934226cb 100644 --- a/src/components/BulkEditPane/BulkEditMarcLayer/BulkEditMarcLayer.js +++ b/src/components/BulkEditPane/BulkEditMarcLayer/BulkEditMarcLayer.js @@ -1,23 +1,26 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; - import { useIntl } from 'react-intl'; import uniqueId from 'lodash/uniqueId'; + import { BulkEditLayer } from '../BulkEditListResult/BulkEditInAppLayer/BulkEditLayer'; import { BulkEditMarc } from '../BulkEditListResult/BulkEditMarc/BulkEditMarc'; import { BulkEditPreviewModal } from '../BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModal'; import { getMarcFieldTemplate, getTransformedField } from '../BulkEditListResult/BulkEditMarc/helpers'; import { useMarcContentUpdate } from '../../../hooks/api/useMarcContentUpdate'; import { useConfirmChanges } from '../../../hooks/useConfirmChanges'; -import { QUERY_KEY_DOWNLOAD_MARC_PREVIEW_MODAL, useContentUpdate } from '../../../hooks/api'; -import { savePreviewFile } from '../../../utils/files'; +import { useContentUpdate } from '../../../hooks/api'; import { - getContentUpdatesBody, getMappedContentUpdates, + getContentUpdatesBody, + getMappedContentUpdates, isContentUpdatesFormValid } from '../BulkEditListResult/BulkEditInApp/ContentUpdatesForm/helpers'; import { getMarcFormErrors } from '../BulkEditListResult/BulkEditMarc/validation'; import { getAdministrativeDataOptions } from '../../../constants'; import { sortAlphabetically } from '../../../utils/sortAlphabetically'; +import { BulkEditPreviewModalFooter } from '../BulkEditListResult/BulkEditInAppPreviewModal/BulkEditPreviewModalFooter'; +import { useCommitChanges } from '../../../hooks/useCommitChanges'; + export const BulkEditMarcLayer = ({ bulkOperationId, @@ -48,28 +51,20 @@ export const BulkEditMarcLayer = ({ isPreviewLoading, bulkDetails, totalRecords, - downloadFile, confirmChanges, closePreviewModal, - } = useConfirmChanges({ - queryDownloadKey: QUERY_KEY_DOWNLOAD_MARC_PREVIEW_MODAL, - bulkOperationId, - onDownloadSuccess: (fileData, searchParams) => { - const { approach, initialFileName } = searchParams; + } = useConfirmChanges({ bulkOperationId }); - savePreviewFile({ - bulkOperationId, - fileData, - approach, - initialFileName, - }); - }, + const { commitChanges } = useCommitChanges({ + bulkOperationId, + onChangesCommited: () => { + closePreviewModal(); + onMarcLayerClose(); + } }); - const handleChangesCommited = () => { - closePreviewModal(); - onMarcLayerClose(); - }; + const hasBothFiles = bulkDetails?.linkToModifiedRecordsCsvFile && bulkDetails?.linkToModifiedRecordsMarcFile; + const areMarcAndCsvReady = hasBothFiles || !isPreviewLoading; const handleConfirm = () => { const bulkOperationMarcRules = marcFields @@ -116,11 +111,16 @@ export const BulkEditMarcLayer = ({ + } /> ); diff --git a/src/components/BulkEditPane/BulkEditPane.js b/src/components/BulkEditPane/BulkEditPane.js index 875baf18..c4d48bd3 100644 --- a/src/components/BulkEditPane/BulkEditPane.js +++ b/src/components/BulkEditPane/BulkEditPane.js @@ -103,9 +103,7 @@ export const BulkEditPane = () => { queryKey: QUERY_KEY_DOWNLOAD_ACTION_MENU, enabled: !!fileInfo, id: bulkOperationId, - fileInfo: { - fileContentType: FILE_SEARCH_PARAMS[fileInfo?.param]?.replace('_MARC', ''), - }, + fileContentType: FILE_SEARCH_PARAMS[fileInfo?.param]?.replace('_MARC', ''), onSuccess: data => { /* istanbul ignore next */ saveAs(new Blob([data]), fileInfo?.bulkDetails[FILE_TO_LINK[fileInfo?.param]].split('/')[1]); diff --git a/src/constants/files.js b/src/constants/files.js index aaa4bd0e..ac2499e1 100644 --- a/src/constants/files.js +++ b/src/constants/files.js @@ -14,6 +14,11 @@ export const FILE_KEYS = { TRIGGERING_FILE: 'linkToTriggeringCsvFile', }; +export const FILE_EXTENSION = { + CSV: 'csv', + MRC: 'mrc', +}; + // use as API key for /download export const FILE_SEARCH_PARAMS = { MATCHED_RECORDS_FILE: 'MATCHED_RECORDS_FILE', @@ -21,6 +26,7 @@ export const FILE_SEARCH_PARAMS = { COMMITTED_RECORDS_FILE: 'COMMITTED_RECORDS_FILE', COMMITTING_CHANGES_ERROR_FILE: 'COMMITTING_CHANGES_ERROR_FILE', PROPOSED_CHANGES_FILE: 'PROPOSED_CHANGES_FILE', + PROPOSED_CHANGES_MARC_FILE: 'PROPOSED_CHANGES_MARC_FILE', COMMITTED_RECORDS_FILE_MARC: 'COMMITTED_RECORDS_FILE_MARC', }; diff --git a/src/hooks/api/useFileDownload.js b/src/hooks/api/useFileDownload.js index 5804046e..62de5e90 100644 --- a/src/hooks/api/useFileDownload.js +++ b/src/hooks/api/useFileDownload.js @@ -5,11 +5,12 @@ import { useErrorMessages } from '../useErrorMessages'; export const QUERY_KEY_DOWNLOAD_LOGS = 'downloadLogs'; export const QUERY_KEY_DOWNLOAD_ACTION_MENU = 'downloadActionMenu'; export const QUERY_KEY_DOWNLOAD_PREVIEW_MODAL = 'downloadPreviewModal'; +export const QUERY_KEY_DOWNLOAD_ADMINISTRATIVE_PREVIEW_MODAL = 'downloadPreviewModal'; export const QUERY_KEY_DOWNLOAD_MARC_PREVIEW_MODAL = 'downloadMarcPreviewModal'; export const useFileDownload = ({ id, - fileInfo, + fileContentType, onSuccess, onSettled, queryKey, @@ -21,11 +22,11 @@ export const useFileDownload = ({ const { refetch, isFetching } = useQuery( { - queryKey: [namespaceKey, id, fileInfo], + queryKey: [namespaceKey, id, fileContentType], queryFn: () => ky.get(`bulk-operations/${id}/download`, { - searchParams: { fileContentType: fileInfo?.fileContentType }, + searchParams: { fileContentType }, }).blob(), - enabled: !!fileInfo, + enabled: !!fileContentType, onSuccess: response => { showErrorMessage(response); onSuccess?.(response); diff --git a/src/hooks/useCommitChanges.js b/src/hooks/useCommitChanges.js new file mode 100644 index 00000000..3a462b9e --- /dev/null +++ b/src/hooks/useCommitChanges.js @@ -0,0 +1,46 @@ +import { useHistory } from 'react-router-dom'; +import { useQueryClient } from 'react-query'; + +import { buildSearch } from '@folio/stripes-acq-components'; + +import { useSearchParams } from './useSearchParams'; +import { useErrorMessages } from './useErrorMessages'; +import { BULK_OPERATION_DETAILS_KEY, useBulkOperationStart } from './api'; +import { APPROACHES, EDITING_STEPS } from '../constants'; + + +export const useCommitChanges = ({ + bulkOperationId, + onChangesCommited, +}) => { + const history = useHistory(); + const queryClient = useQueryClient(); + const { criteria } = useSearchParams(); + const { showErrorMessage } = useErrorMessages(); + const { bulkOperationStart } = useBulkOperationStart(); + + const commitChanges = async () => { + try { + await bulkOperationStart({ + id: bulkOperationId, + approach: APPROACHES.IN_APP, + step: EDITING_STEPS.COMMIT, + }); + + await queryClient.resetQueries(BULK_OPERATION_DETAILS_KEY); + + onChangesCommited(); + + history.replace({ + pathname: `/bulk-edit/${bulkOperationId}/preview`, + search: buildSearch({ + progress: criteria, + }, history.location.search), + }); + } catch (e) { + showErrorMessage(e); + } + }; + + return { commitChanges }; +}; diff --git a/src/hooks/useConfirmChanges.js b/src/hooks/useConfirmChanges.js index 554b33ac..9b9fc635 100644 --- a/src/hooks/useConfirmChanges.js +++ b/src/hooks/useConfirmChanges.js @@ -7,27 +7,19 @@ import { BULK_OPERATION_DETAILS_KEY, useBulkOperationDetails, useBulkOperationStart, - useFileDownload } from './api'; import { APPROACHES, EDITING_STEPS, - FILE_SEARCH_PARAMS, JOB_STATUSES, } from '../constants'; -import { useSearchParams } from './useSearchParams'; import { useErrorMessages } from './useErrorMessages'; import { pollForStatus } from '../utils/pollForStatus'; -export const useConfirmChanges = ({ - queryDownloadKey, - bulkOperationId, - onDownloadSuccess, -}) => { +export const useConfirmChanges = ({ bulkOperationId }) => { const queryClient = useQueryClient(); const ky = useOkapiKy(); - const searchParams = useSearchParams(); const { showErrorMessage } = useErrorMessages(); const [isPreviewModalOpened, setIsPreviewModalOpened] = useState(false); @@ -74,24 +66,12 @@ export const useConfirmChanges = ({ }); }; - const { refetch: downloadFile, isFetching: isFileDownloading } = useFileDownload({ - queryKey: queryDownloadKey, - enabled: false, // to prevent automatic file fetch in preview modal - id: bulkOperationId, - fileInfo: { - fileContentType: FILE_SEARCH_PARAMS.PROPOSED_CHANGES_FILE, - }, - onSuccess: (data) => onDownloadSuccess(data, searchParams), - }); - return { totalRecords, bulkDetails, isPreviewModalOpened, isPreviewLoading, setIsPreviewLoading, - isFileDownloading, - downloadFile, openPreviewModal, closePreviewModal, confirmChanges, diff --git a/src/utils/files.js b/src/utils/files.js index 9a69ce50..e67ce4ab 100644 --- a/src/utils/files.js +++ b/src/utils/files.js @@ -1,7 +1,6 @@ import { saveAs } from 'file-saver'; import { getFormattedFilePrefixDate } from './date'; -import { APPROACHES } from '../constants'; export const getFileName = (item, triggeredFile) => { @@ -32,16 +31,10 @@ export const changeExtension = (fileName, extension) => { export const savePreviewFile = ({ bulkOperationId, fileData, - approach, + extension, initialFileName, }) => { - const extension = approach === APPROACHES.MARC ? 'mrc' : 'csv'; - - const initialFileNameByApproach = approach === APPROACHES.MARC - ? changeExtension(initialFileName, extension) - : initialFileName; - - const fileName = initialFileNameByApproach || `Query-${bulkOperationId}.${extension}`; + const fileName = initialFileName || `Query-${bulkOperationId}.${extension}`; saveAs(new Blob([fileData]), `${getFormattedFilePrefixDate()}-Updates-Preview-${fileName}`); }; diff --git a/translations/ui-bulk-edit/en.json b/translations/ui-bulk-edit/en.json index 1d8c16bd..1ed4501c 100644 --- a/translations/ui-bulk-edit/en.json +++ b/translations/ui-bulk-edit/en.json @@ -440,7 +440,7 @@ "previewModal.message.empty.marc": "All instances have source FOLIO. Use “Instances and Administrative data” option for bulk edit.", "previewModal.previewToBeChanged": "Preview of records to be changed", "previewModal.keepEditing": "Keep editing", - "previewModal.downloadPreview": "Download preview", + "previewModal.downloadPreview": "Download preview in CSV format", "previewModal.downloadPreview.marc": "Download preview in MARC format", "previewModal.saveAndClose": "Commit changes", "previewModal.areYouSure": "Are you sure?",