Skip to content

Commit

Permalink
Block Directory: Fix installations for 'template-locked' mode (#69394)
Browse files Browse the repository at this point in the history
* Use stable reference fallback for getDownloadableBlocks
* Do nothing when there are no installed block types
* Update block directory selectors
* Remove unused utility method and tests

Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: karthikeya-io <[email protected]>
  • Loading branch information
4 people authored Mar 5, 2025
1 parent c6b1d9b commit 6dcf50f
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 84 deletions.
57 changes: 44 additions & 13 deletions packages/block-directory/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import { createSelector, createRegistrySelector } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import hasBlockType from './utils/has-block-type';
const EMPTY_ARRAY = [];

/**
* Returns true if application is requesting for downloadable blocks.
Expand All @@ -30,7 +27,7 @@ export function isRequestingDownloadableBlocks( state, filterValue ) {
* @return {Array} Downloadable blocks.
*/
export function getDownloadableBlocks( state, filterValue ) {
return state.downloadableBlocks[ filterValue ]?.results ?? [];
return state.downloadableBlocks[ filterValue ]?.results ?? EMPTY_ARRAY;
}

/**
Expand All @@ -56,16 +53,33 @@ export function getInstalledBlockTypes( state ) {
export const getNewBlockTypes = createRegistrySelector( ( select ) =>
createSelector(
( state ) => {
const usedBlockTree = select( blockEditorStore ).getBlocks();
const installedBlockTypes = getInstalledBlockTypes( state );
if ( ! installedBlockTypes.length ) {
return EMPTY_ARRAY;
}

return installedBlockTypes.filter( ( blockType ) =>
hasBlockType( blockType, usedBlockTree )
const { getBlockName, getClientIdsWithDescendants } =
select( blockEditorStore );
const installedBlockNames = installedBlockTypes.map(
( blockType ) => blockType.name
);
const foundBlockNames = getClientIdsWithDescendants().flatMap(
( clientId ) => {
const blockName = getBlockName( clientId );
return installedBlockNames.includes( blockName )
? blockName
: [];
}
);
const newBlockTypes = installedBlockTypes.filter( ( blockType ) =>
foundBlockNames.includes( blockType.name )
);

return newBlockTypes.length > 0 ? newBlockTypes : EMPTY_ARRAY;
},
( state ) => [
getInstalledBlockTypes( state ),
select( blockEditorStore ).getBlocks(),
select( blockEditorStore ).getClientIdsWithDescendants(),
]
)
);
Expand All @@ -81,16 +95,33 @@ export const getNewBlockTypes = createRegistrySelector( ( select ) =>
export const getUnusedBlockTypes = createRegistrySelector( ( select ) =>
createSelector(
( state ) => {
const usedBlockTree = select( blockEditorStore ).getBlocks();
const installedBlockTypes = getInstalledBlockTypes( state );
if ( ! installedBlockTypes.length ) {
return EMPTY_ARRAY;
}

return installedBlockTypes.filter(
( blockType ) => ! hasBlockType( blockType, usedBlockTree )
const { getBlockName, getClientIdsWithDescendants } =
select( blockEditorStore );
const installedBlockNames = installedBlockTypes.map(
( blockType ) => blockType.name
);
const foundBlockNames = getClientIdsWithDescendants().flatMap(
( clientId ) => {
const blockName = getBlockName( clientId );
return installedBlockNames.includes( blockName )
? blockName
: [];
}
);
const unusedBlockTypes = installedBlockTypes.filter(
( blockType ) => ! foundBlockNames.includes( blockType.name )
);

return unusedBlockTypes.length > 0 ? unusedBlockTypes : EMPTY_ARRAY;
},
( state ) => [
getInstalledBlockTypes( state ),
select( blockEditorStore ).getBlocks(),
select( blockEditorStore ).getClientIdsWithDescendants(),
]
)
);
Expand Down
6 changes: 6 additions & 0 deletions packages/block-directory/src/store/test/fixtures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ export const blockList = [
innerBlocks: [],
},
];

export const blockListIds = blockList.map( ( block ) => block.clientId );
export const blockListNameMap = blockList.reduce( ( acc, block ) => {
acc[ block.clientId ] = block.name;
return acc;
}, {} );
23 changes: 18 additions & 5 deletions packages/block-directory/src/store/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
* Internal dependencies
*/
import {
blockList,
blockListIds,
blockListNameMap,
blockTypeInstalled,
blockTypeUnused,
downloadableBlock,
Expand Down Expand Up @@ -90,7 +91,10 @@ describe( 'selectors', () => {
describe( 'getNewBlockTypes', () => {
it( 'should retrieve the block types that are installed and in the post content', () => {
getNewBlockTypes.registry = {
select: jest.fn( () => ( { getBlocks: () => blockList } ) ),
select: jest.fn( () => ( {
getBlockName: ( clientId ) => blockListNameMap[ clientId ],
getClientIdsWithDescendants: () => blockListIds,
} ) ),
};
const state = {
blockManagement: {
Expand All @@ -107,7 +111,10 @@ describe( 'selectors', () => {

it( 'should return an empty array if no blocks are used', () => {
getNewBlockTypes.registry = {
select: jest.fn( () => ( { getBlocks: () => [] } ) ),
select: jest.fn( () => ( {
getBlockName: ( clientId ) => blockListNameMap[ clientId ],
getClientIdsWithDescendants: () => [],
} ) ),
};
const state = {
blockManagement: {
Expand All @@ -125,7 +132,10 @@ describe( 'selectors', () => {
describe( 'getUnusedBlockTypes', () => {
it( 'should retrieve the block types that are installed but not used', () => {
getUnusedBlockTypes.registry = {
select: jest.fn( () => ( { getBlocks: () => blockList } ) ),
select: jest.fn( () => ( {
getBlockName: ( clientId ) => blockListNameMap[ clientId ],
getClientIdsWithDescendants: () => blockListIds,
} ) ),
};
const state = {
blockManagement: {
Expand All @@ -142,7 +152,10 @@ describe( 'selectors', () => {

it( 'should return all block types if no blocks are used', () => {
getUnusedBlockTypes.registry = {
select: jest.fn( () => ( { getBlocks: () => [] } ) ),
select: jest.fn( () => ( {
getBlockName: ( clientId ) => blockListNameMap[ clientId ],
getClientIdsWithDescendants: () => [],
} ) ),
};
const state = {
blockManagement: {
Expand Down
24 changes: 0 additions & 24 deletions packages/block-directory/src/store/utils/has-block-type.js

This file was deleted.

42 changes: 0 additions & 42 deletions packages/block-directory/src/store/utils/test/has-block-type.js

This file was deleted.

1 comment on commit 6dcf50f

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 6dcf50f.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/13677638564
📝 Reported issues:

Please sign in to comment.