Skip to content
Merged
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
11 changes: 6 additions & 5 deletions packages/editor/src/components/post-publish-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,19 @@ export class PostPublishButton extends Component {
} = this.props;

const isButtonDisabled =
( isSaving ||
isPostSavingLocked ||
( ( isSaving ||
! isSaveable ||
isPostSavingLocked ||
( ! isPublishable && ! forceIsDirty ) ) &&
( ! hasNonPostEntityChanges || isSavingNonPostEntityChanges );
( ! hasNonPostEntityChanges || isSavingNonPostEntityChanges ) );

const isToggleDisabled =
( isPublished ||
isPostSavingLocked ||
( ( isPublished ||
isSaving ||
! isSaveable ||
( ! isPublishable && ! forceIsDirty ) ) &&
( ! hasNonPostEntityChanges || isSavingNonPostEntityChanges );
( ! hasNonPostEntityChanges || isSavingNonPostEntityChanges ) );

// If the new status has not changed explicitly, we derive it from
// other factors, like having a publish action, etc.. We need to preserve
Expand Down
4 changes: 3 additions & 1 deletion packages/editor/src/components/post-publish-button/label.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default function PublishButtonLabel() {
postStatusHasChanged,
postStatus,
postType,
isPostSavingLocked,
} = useSelect( ( select ) => {
const {
isCurrentPostPublished,
Expand All @@ -52,6 +53,7 @@ export default function PublishButtonLabel() {
isAutosaving: isAutosavingPost(),
hasNonPostEntityChanges:
select( editorStore ).hasNonPostEntityChanges(),
isPostSavingLocked: select( editorStore ).isPostSavingLocked(),
postStatusHasChanged: !! getPostEdits()?.status,
postStatus: getEditedPostAttribute( 'status' ),
};
Expand Down Expand Up @@ -82,7 +84,7 @@ export default function PublishButtonLabel() {
: __( 'Submit for Review' );
}
if (
hasNonPostEntityChanges ||
( hasNonPostEntityChanges && ! isPostSavingLocked ) ||
isPublished ||
( postStatusHasChanged &&
! [ 'future', 'publish' ].includes( postStatus ) ) ||
Expand Down
5 changes: 4 additions & 1 deletion packages/editor/src/components/post-saved-state/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export default function PostSavedState( { forceIsDirty } ) {
isPublished,
isSaveable,
isSaving,
isSavingLocked,
isScheduled,
hasPublishAction,
showIconLabels,
Expand All @@ -60,6 +61,7 @@ export default function PostSavedState( { forceIsDirty } ) {
isEditedPostDirty,
isSavingPost,
isEditedPostSaveable,
isPostSavingLocked,
getCurrentPost,
isAutosavingPost,
getEditedPostAttribute,
Expand All @@ -73,6 +75,7 @@ export default function PostSavedState( { forceIsDirty } ) {
isPublished: isCurrentPostPublished(),
isSaving: isSavingPost(),
isSaveable: isEditedPostSaveable(),
isSavingLocked: isPostSavingLocked(),
isScheduled: isCurrentPostScheduled(),
hasPublishAction:
getCurrentPost()?._links?.[ 'wp:action-publish' ] ?? false,
Expand Down Expand Up @@ -140,7 +143,7 @@ export default function PostSavedState( { forceIsDirty } ) {

const isSaved = forceSavedMessage || ( ! isNew && ! isDirty );
const isSavedState = isSaving || isSaved;
const isDisabled = isSaving || isSaved || ! isSaveable;
const isDisabled = isSaving || isSaved || ! isSaveable || isSavingLocked;
let text;

if ( isSaving ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ exports[`PostSavedState returns a disabled button if the post is not saveable 1`

exports[`PostSavedState should return Save button if edits to be saved 1`] = `
<button
aria-disabled="false"
aria-label="Save draft"
class="components-button editor-post-save-draft is-compact is-tertiary"
type="button"
Expand Down
19 changes: 2 additions & 17 deletions packages/editor/src/components/provider/use-upload-save-lock.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,11 @@ const LOCK_NAME = 'upload-in-progress';
/**
* A hook that locks post saving and autosaving while media uploads are in progress.
* This prevents users from publishing or saving while files are still uploading.
*
* Only active when client-side media processing is enabled.
*/
export default function useUploadSaveLock() {
const isClientSideMediaProcessingEnabled =
window.__clientSideMediaProcessing || window.__heicUploadSupport;

const isUploading = useSelect(
( select ) => {
if ( ! isClientSideMediaProcessingEnabled ) {
return false;
}
return select( uploadStore ).isUploading();
},
[ isClientSideMediaProcessingEnabled ]
( select ) => select( uploadStore ).isUploading(),
[]
);

const {
Expand All @@ -40,10 +30,6 @@ export default function useUploadSaveLock() {
} = useDispatch( editorStore );

useEffect( () => {
if ( ! isClientSideMediaProcessingEnabled ) {
return;
}

if ( isUploading ) {
lockPostSaving( LOCK_NAME );
lockPostAutosaving( LOCK_NAME );
Expand All @@ -57,7 +43,6 @@ export default function useUploadSaveLock() {
unlockPostAutosaving( LOCK_NAME );
};
}, [
isClientSideMediaProcessingEnabled,
isUploading,
lockPostSaving,
unlockPostSaving,
Expand Down
55 changes: 26 additions & 29 deletions packages/editor/src/utils/media-upload/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { v4 as uuid } from 'uuid';
import { select, dispatch } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { uploadMedia } from '@wordpress/media-utils';
import { isClientSideMediaSupported } from '@wordpress/upload-media';

/**
* Internal dependencies
Expand Down Expand Up @@ -51,8 +52,9 @@ export default function mediaUpload( {
} = dispatch( editorStore );

const wpAllowedMimeTypes = getEditorSettings().allowedMimeTypes;
const isClientSideMediaActive =
window.__clientSideMediaProcessing && isClientSideMediaSupported();
const lockKey = `image-upload-${ uuid() }`;
let imageIsUploading = false;
maxUploadFileSize =
maxUploadFileSize || getEditorSettings().maxUploadFileSize;
const currentPost = getCurrentPost();
Expand All @@ -61,44 +63,31 @@ export default function mediaUpload( {
typeof currentPost?.id === 'number'
? currentPost.id
: currentPost?.wp_id;
const setSaveLock = () => {
if ( window.__clientSideMediaProcessing ) {
return; // Skip - handled by useUploadSaveLock in editor provider
}
lockPostSaving( lockKey );
lockPostAutosaving( lockKey );
imageIsUploading = true;
};

const postData = currentPostId ? { post: currentPostId } : {};
const clearSaveLock = () => {
if ( window.__clientSideMediaProcessing ) {
return; // Skip - handled by useUploadSaveLock in editor provider
}
unlockPostSaving( lockKey );
unlockPostAutosaving( lockKey );
imageIsUploading = false;
};

// Lock saving immediately when the upload starts.
// When client-side media processing is enabled, save locking
// is handled by useUploadSaveLock in the editor provider.
if ( ! isClientSideMediaActive ) {
lockPostSaving( lockKey );
lockPostAutosaving( lockKey );
}

const postData = currentPostId ? { post: currentPostId } : {};

uploadMedia( {
allowedTypes,
filesList,
onFileChange: ( file ) => {
// When client-side media processing is enabled, save locking
// is handled by useUploadSaveLock in the editor provider.
if ( ! window.__clientSideMediaProcessing ) {
if ( ! imageIsUploading ) {
setSaveLock();
} else {
clearSaveLock();
}
}
onFileChange?.( file );
onFileChange: ( files ) => {
onFileChange?.( files );

// Files are initially received by `onFileChange` as a blob.
// After that the function is called a second time with the file as an entity.
// After that the function is called again with the file as an entity.
// For core-data, we only care about receiving/invalidating entities.
const entityFiles = file.filter( ( _file ) => _file?.id );
const entityFiles = files.filter( ( _file ) => _file?.id );
if ( entityFiles?.length ) {
const invalidateCache = true;
receiveEntityRecords(
Expand All @@ -109,6 +98,14 @@ export default function mediaUpload( {
invalidateCache
);
}

// Unlock saving once all files have been uploaded (all have IDs).
if (
! isClientSideMediaActive &&
entityFiles.length === files.length
) {
clearSaveLock();
}
},
onSuccess,
additionalData: {
Expand All @@ -117,7 +114,7 @@ export default function mediaUpload( {
},
maxUploadFileSize,
onError: ( { message } ) => {
if ( ! window.__clientSideMediaProcessing ) {
if ( ! isClientSideMediaActive ) {
clearSaveLock();
}
onError( message );
Expand Down
18 changes: 10 additions & 8 deletions test/e2e/specs/editor/various/publishing.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ test.describe( 'Publishing', () => {
.getByRole( 'textbox', { name: 'Add title' } )
.fill( 'E2E Test Post' );

// Open publish panel before locking so the button is still clickable.
await page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Publish' } )
.click();

await page.evaluate( () =>
window.wp.data
.dispatch( 'core/editor' )
.lockPostSaving( 'futurelock' )
);

// Open publish panel.
await page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Publish' } )
.click();

// Publish button should be disabled.
// Publish button in the panel should be disabled.
await expect(
page
.getByRole( 'region', { name: 'Editor publish' } )
Expand All @@ -57,11 +57,13 @@ test.describe( 'Publishing', () => {

await pageUtils.pressKeys( 'primary+s' );

// Both the Save draft button and keyboard shortcut should
// be disabled when post saving is locked.
await expect(
page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Save draft' } )
).toBeEnabled();
).toBeDisabled();
} );
} );
} );
Expand Down
Loading
Loading