587 lines
20 KiB
JavaScript
587 lines
20 KiB
JavaScript
import * as React from 'react';
|
|
import { useNotification, useTracking, useAPIErrorHandler, useGuidedTour } from '@strapi/admin/strapi-admin';
|
|
import { useIntl } from 'react-intl';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useRelationModal } from '../pages/EditView/components/FormInputs/Relations/RelationModal.mjs';
|
|
import { usePreviewContext } from '../preview/pages/Preview.mjs';
|
|
import { useDeleteDocumentMutation, useDeleteManyDocumentsMutation, useDiscardDocumentMutation, usePublishDocumentMutation, usePublishManyDocumentsMutation, useUpdateDocumentMutation, useUnpublishDocumentMutation, useUnpublishManyDocumentsMutation, useCreateDocumentMutation, useAutoCloneDocumentMutation, useCloneDocumentMutation, useLazyGetDocumentQuery } from '../services/documents.mjs';
|
|
import { getTranslation } from '../utils/translations.mjs';
|
|
|
|
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
|
id: 'notification.error',
|
|
defaultMessage: 'An error occurred, please try again'
|
|
};
|
|
/**
|
|
* @alpha
|
|
* @public
|
|
* @description Contains all the operations that can be performed on a single document.
|
|
* Designed to be able to be used anywhere within a Strapi app. The hooks will handle
|
|
* notifications should the operation fail, however the response is always returned incase
|
|
* the user needs to handle side-effects.
|
|
* @example
|
|
* ```tsx
|
|
* import { Form } from '@strapi/admin/admin';
|
|
*
|
|
* const { id, model, collectionType } = useParams<{ id: string; model: string; collectionType: string }>();
|
|
* const { update } = useDocumentActions();
|
|
*
|
|
* const handleSubmit = async (data) => {
|
|
* await update({ collectionType, model, documentId: id }, data);
|
|
* }
|
|
*
|
|
* return <Form method="PUT" onSubmit={handleSubmit} />
|
|
* ```
|
|
*
|
|
* @see {@link https://contributor.strapi.io/docs/core/content-manager/hooks/use-document-operations} for more information
|
|
*/ const useDocumentActions = ()=>{
|
|
const { toggleNotification } = useNotification();
|
|
const { formatMessage } = useIntl();
|
|
const { trackUsage } = useTracking();
|
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
|
const navigate = useNavigate();
|
|
const setCurrentStep = useGuidedTour('useDocumentActions', (state)=>state.setCurrentStep);
|
|
// Get metadata from context providers for tracking purposes
|
|
const previewContext = usePreviewContext('useDocumentActions', ()=>true, false);
|
|
const relationContext = useRelationModal('useDocumentActions', ()=>true, false);
|
|
const fromPreview = previewContext != undefined;
|
|
const fromRelationModal = relationContext != undefined;
|
|
const [deleteDocument, { isLoading: isDeleting }] = useDeleteDocumentMutation();
|
|
const _delete = React.useCallback(async ({ collectionType, model, documentId, params }, trackerProperty)=>{
|
|
try {
|
|
trackUsage('willDeleteEntry', trackerProperty);
|
|
const res = await deleteDocument({
|
|
collectionType,
|
|
model,
|
|
documentId,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.delete'),
|
|
defaultMessage: 'Deleted document'
|
|
})
|
|
});
|
|
trackUsage('didDeleteEntry', trackerProperty);
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
trackUsage('didNotDeleteEntry', {
|
|
error: err,
|
|
...trackerProperty
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
trackUsage,
|
|
deleteDocument,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [deleteManyDocuments, { isLoading: isDeletingMany }] = useDeleteManyDocumentsMutation();
|
|
const deleteMany = React.useCallback(async ({ model, documentIds, params })=>{
|
|
try {
|
|
trackUsage('willBulkDeleteEntries');
|
|
const res = await deleteManyDocuments({
|
|
model,
|
|
documentIds,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
toggleNotification({
|
|
type: 'success',
|
|
title: formatMessage({
|
|
id: getTranslation('success.records.delete'),
|
|
defaultMessage: 'Successfully deleted.'
|
|
}),
|
|
message: ''
|
|
});
|
|
trackUsage('didBulkDeleteEntries');
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
trackUsage('didNotBulkDeleteEntries');
|
|
throw err;
|
|
}
|
|
}, [
|
|
trackUsage,
|
|
deleteManyDocuments,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [discardDocument, { isLoading: isDiscardingDocument }] = useDiscardDocumentMutation();
|
|
const discard = React.useCallback(async ({ collectionType, model, documentId, params })=>{
|
|
try {
|
|
const res = await discardDocument({
|
|
collectionType,
|
|
model,
|
|
documentId,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: 'content-manager.success.record.discard',
|
|
defaultMessage: 'Changes discarded'
|
|
})
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
discardDocument,
|
|
formatAPIError,
|
|
formatMessage,
|
|
toggleNotification
|
|
]);
|
|
const [publishDocument, { isLoading: isPublishing }] = usePublishDocumentMutation();
|
|
const publish = React.useCallback(async ({ collectionType, model, documentId, params }, data)=>{
|
|
try {
|
|
trackUsage('willPublishEntry', {
|
|
documentId
|
|
});
|
|
const res = await publishDocument({
|
|
collectionType,
|
|
model,
|
|
documentId,
|
|
data,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
trackUsage('didPublishEntry', {
|
|
documentId,
|
|
fromPreview,
|
|
fromRelationModal
|
|
});
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.publish'),
|
|
defaultMessage: 'Published document'
|
|
})
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
trackUsage,
|
|
publishDocument,
|
|
fromPreview,
|
|
fromRelationModal,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [publishManyDocuments, { isLoading: isPublishingMany }] = usePublishManyDocumentsMutation();
|
|
const publishMany = React.useCallback(async ({ model, documentIds, params })=>{
|
|
try {
|
|
// TODO Confirm tracking events for bulk publish?
|
|
const res = await publishManyDocuments({
|
|
model,
|
|
documentIds,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.publish'),
|
|
defaultMessage: 'Published document'
|
|
})
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
// trackUsage,
|
|
publishManyDocuments,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [updateDocument, { isLoading: isUpdating }] = useUpdateDocumentMutation();
|
|
const update = React.useCallback(async ({ collectionType, model, documentId, params }, data, trackerProperty)=>{
|
|
try {
|
|
trackUsage('willEditEntry', trackerProperty);
|
|
const res = await updateDocument({
|
|
collectionType,
|
|
model,
|
|
documentId,
|
|
data,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
trackUsage('didNotEditEntry', {
|
|
error: res.error,
|
|
...trackerProperty
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
trackUsage('didEditEntry', {
|
|
...trackerProperty,
|
|
documentId: res.data.data.documentId,
|
|
fromPreview,
|
|
fromRelationModal
|
|
});
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.save'),
|
|
defaultMessage: 'Saved document'
|
|
})
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
trackUsage('didNotEditEntry', {
|
|
error: err,
|
|
...trackerProperty
|
|
});
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
trackUsage,
|
|
updateDocument,
|
|
fromPreview,
|
|
fromRelationModal,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [unpublishDocument] = useUnpublishDocumentMutation();
|
|
const unpublish = React.useCallback(async ({ collectionType, model, documentId, params }, discardDraft = false)=>{
|
|
try {
|
|
trackUsage('willUnpublishEntry');
|
|
const res = await unpublishDocument({
|
|
collectionType,
|
|
model,
|
|
documentId,
|
|
params,
|
|
data: {
|
|
discardDraft
|
|
}
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
trackUsage('didUnpublishEntry');
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.unpublish'),
|
|
defaultMessage: 'Unpublished document'
|
|
})
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
trackUsage,
|
|
unpublishDocument,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [unpublishManyDocuments, { isLoading: isUnpublishingMany }] = useUnpublishManyDocumentsMutation();
|
|
const unpublishMany = React.useCallback(async ({ model, documentIds, params })=>{
|
|
try {
|
|
trackUsage('willBulkUnpublishEntries');
|
|
const res = await unpublishManyDocuments({
|
|
model,
|
|
documentIds,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
trackUsage('didBulkUnpublishEntries');
|
|
toggleNotification({
|
|
type: 'success',
|
|
title: formatMessage({
|
|
id: getTranslation('success.records.unpublish'),
|
|
defaultMessage: 'Successfully unpublished.'
|
|
}),
|
|
message: ''
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
trackUsage('didNotBulkUnpublishEntries');
|
|
throw err;
|
|
}
|
|
}, [
|
|
trackUsage,
|
|
unpublishManyDocuments,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError
|
|
]);
|
|
const [createDocument] = useCreateDocumentMutation();
|
|
const create = React.useCallback(async ({ model, params }, data, trackerProperty)=>{
|
|
try {
|
|
const res = await createDocument({
|
|
model,
|
|
data,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
trackUsage('didNotCreateEntry', {
|
|
error: res.error,
|
|
...trackerProperty
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
trackUsage('didCreateEntry', {
|
|
...trackerProperty,
|
|
documentId: res.data.data.documentId,
|
|
fromPreview,
|
|
fromRelationModal
|
|
});
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.save'),
|
|
defaultMessage: 'Saved document'
|
|
})
|
|
});
|
|
setCurrentStep('contentManager.success');
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
trackUsage('didNotCreateEntry', {
|
|
error: err,
|
|
...trackerProperty
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
createDocument,
|
|
formatAPIError,
|
|
formatMessage,
|
|
fromPreview,
|
|
fromRelationModal,
|
|
setCurrentStep,
|
|
toggleNotification,
|
|
trackUsage
|
|
]);
|
|
const [autoCloneDocument] = useAutoCloneDocumentMutation();
|
|
const autoClone = React.useCallback(async ({ model, sourceId })=>{
|
|
try {
|
|
const res = await autoCloneDocument({
|
|
model,
|
|
sourceId
|
|
});
|
|
if ('error' in res) {
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.clone'),
|
|
defaultMessage: 'Cloned document'
|
|
})
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
autoCloneDocument,
|
|
formatMessage,
|
|
toggleNotification
|
|
]);
|
|
const [cloneDocument] = useCloneDocumentMutation();
|
|
const clone = React.useCallback(async ({ model, documentId, params }, body, trackerProperty)=>{
|
|
try {
|
|
const { id: _id, ...restBody } = body;
|
|
/**
|
|
* If we're cloning we want to post directly to this endpoint
|
|
* so that the relations even if they're not listed in the EditView
|
|
* are correctly attached to the entry.
|
|
*/ const res = await cloneDocument({
|
|
model,
|
|
sourceId: documentId,
|
|
data: restBody,
|
|
params
|
|
});
|
|
if ('error' in res) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatAPIError(res.error)
|
|
});
|
|
trackUsage('didNotCreateEntry', {
|
|
error: res.error,
|
|
...trackerProperty
|
|
});
|
|
return {
|
|
error: res.error
|
|
};
|
|
}
|
|
trackUsage('didCreateEntry', trackerProperty);
|
|
toggleNotification({
|
|
type: 'success',
|
|
message: formatMessage({
|
|
id: getTranslation('success.record.clone'),
|
|
defaultMessage: 'Cloned document'
|
|
})
|
|
});
|
|
// Redirect to normal edit view
|
|
navigate(`../../${res.data.data.documentId}`, {
|
|
relative: 'path'
|
|
});
|
|
return res.data;
|
|
} catch (err) {
|
|
toggleNotification({
|
|
type: 'danger',
|
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
|
});
|
|
trackUsage('didNotCreateEntry', {
|
|
error: err,
|
|
...trackerProperty
|
|
});
|
|
throw err;
|
|
}
|
|
}, [
|
|
cloneDocument,
|
|
trackUsage,
|
|
toggleNotification,
|
|
formatMessage,
|
|
formatAPIError,
|
|
navigate
|
|
]);
|
|
const [getDoc] = useLazyGetDocumentQuery();
|
|
const getDocument = React.useCallback(async (args)=>{
|
|
const { data } = await getDoc(args);
|
|
return data;
|
|
}, [
|
|
getDoc
|
|
]);
|
|
return {
|
|
isLoading: isPublishing || isUpdating || isDiscardingDocument || isDeleting || isDeletingMany || isUnpublishingMany || isPublishingMany,
|
|
autoClone,
|
|
clone,
|
|
create,
|
|
delete: _delete,
|
|
deleteMany,
|
|
discard,
|
|
getDocument,
|
|
publish,
|
|
publishMany,
|
|
unpublish,
|
|
unpublishMany,
|
|
update
|
|
};
|
|
};
|
|
|
|
export { useDocumentActions };
|
|
//# sourceMappingURL=useDocumentActions.mjs.map
|