From 9facbade5a15c92425ec0ece23223746f22b023a Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Sun, 14 Jan 2024 22:12:31 -0600 Subject: [PATCH 01/15] Add batchInstallFontFaces function and related plumbing. --- .../font-library-modal/context.js | 34 +++++-- .../font-library-modal/resolvers.js | 11 ++- .../font-library-modal/utils/index.js | 95 ++++++++++++++----- 3 files changed, 106 insertions(+), 34 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index e0749845788d60..986a8ae12bc74c 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -14,7 +14,7 @@ import { * Internal dependencies */ import { - fetchInstallFont, + fetchInstallFontFamily, fetchUninstallFonts, fetchFontCollections, fetchFontCollection, @@ -26,7 +26,9 @@ import { mergeFontFamilies, loadFontFaceInBrowser, getDisplaySrcFromFontFace, - makeFormDataFromFontFamily, + makeFontFacesFormData, + makeFontFamilyFormData, + batchInstallFontFaces, } from './utils'; import { toggleFont } from './utils/toggleFont'; import getIntersectingFontFaces from './utils/get-intersecting-font-faces'; @@ -63,9 +65,8 @@ function FontLibraryProvider( { children } ) { } = useEntityRecords( 'postType', 'wp_font_family', { refreshKey } ); const libraryFonts = - ( libraryPosts || [] ).map( ( post ) => - JSON.parse( post.content.raw ) - ) || []; + ( libraryPosts || [] ).map( ( post ) => post.font_family_settings ) || + []; // Global Styles (settings) font families const [ fontFamilies, setFontFamilies ] = useGlobalSetting( @@ -196,9 +197,24 @@ function FontLibraryProvider( { children } ) { setIsInstalling( true ); try { // Prepare formData to install. - const formData = makeFormDataFromFontFamily( font ); + const fontFamilyFormData = makeFontFamilyFormData( font ); + const fontFacesFormData = makeFontFacesFormData( font ); + const fontFamilyId = await fetchInstallFontFamily( + fontFamilyFormData + ) + .then( ( response ) => response.id ) + .catch( ( e ) => { + // eslint-disable-next-line no-console + console.error( e ); + throw Error( 'Unable to install font family.' ); + } ); + // Install the fonts (upload the font files to the server and create the post in the database). - const response = await fetchInstallFont( formData ); + const response = await batchInstallFontFaces( + fontFamilyId, + fontFacesFormData + ); + const fontsInstalled = response?.successes || []; // Get intersecting font faces between the fonts we tried to installed and the fonts that were installed // (to avoid activating a non installed font). @@ -213,14 +229,14 @@ function FontLibraryProvider( { children } ) { 'settings.typography.fontFamilies', ] ); refreshLibrary(); - setIsInstalling( false ); return response; } catch ( error ) { - setIsInstalling( false ); return { errors: [ error ], }; + } finally { + setIsInstalling( false ); } } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js index 2e7f413a6fa45b..d03140a5a83335 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js @@ -7,7 +7,7 @@ */ import apiFetch from '@wordpress/api-fetch'; -export async function fetchInstallFont( data ) { +export async function fetchInstallFontFamily( data ) { const config = { path: '/wp/v2/font-families', method: 'POST', @@ -16,6 +16,15 @@ export async function fetchInstallFont( data ) { return apiFetch( config ); } +export async function fetchInstallFontFace( fontFamilyId, data ) { + const config = { + path: `/wp/v2/font-families/${ fontFamilyId }/font-faces`, + method: 'POST', + body: data, + }; + return apiFetch( config ); +} + export async function fetchUninstallFonts( fonts ) { const data = { font_families: fonts, diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index 0aa0f7edb4aec9..b722fc3d26084e 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -8,6 +8,7 @@ import { privateApis as componentsPrivateApis } from '@wordpress/components'; */ import { FONT_WEIGHTS, FONT_STYLES } from './constants'; import { unlock } from '../../../../lock-unlock'; +import { fetchInstallFontFamily } from '../resolvers'; /** * Browser dependencies @@ -135,39 +136,85 @@ export function getDisplaySrcFromFontFace( input, urlPrefix ) { return src; } -export function makeFormDataFromFontFamily( fontFamily ) { +export function makeFontFamilyFormData( fontFamily ) { const formData = new FormData(); const { kebabCase } = unlock( componentsPrivateApis ); - const newFontFamily = { - ...fontFamily, + const { fontFace, category, ...familyWithValidParameters } = fontFamily; + const fontFamilySettings = { + ...familyWithValidParameters, slug: kebabCase( fontFamily.slug ), }; - if ( newFontFamily?.fontFace ) { - const newFontFaces = newFontFamily.fontFace.map( - ( face, faceIndex ) => { - if ( face.file ) { - // Slugified file name because the it might contain spaces or characters treated differently on the server. - const fileId = `file-${ faceIndex }`; - // Add the files to the formData - formData.append( fileId, face.file, face.file.name ); - // remove the file object from the face object the file is referenced by the uploadedFile key - const { file, ...faceWithoutFileProperty } = face; - const newFace = { - ...faceWithoutFileProperty, - uploadedFile: fileId, - }; - return newFace; - } - return face; + formData.append( + 'font_family_settings', + JSON.stringify( fontFamilySettings ) + ); + return formData; +} + +export function makeFontFacesFormData( font ) { + if ( font?.fontFace ) { + const fontFacesFormData = font.fontFace.map( ( face, faceIndex ) => { + const formData = new FormData(); + if ( face.file ) { + // Slugified file name because the it might contain spaces or characters treated differently on the server. + const fileId = `file-${ faceIndex }`; + // Add the files to the formData + formData.append( fileId, face.file, face.file.name ); + // remove the file object from the face object the file is referenced by the uploadedFile key + const { file, ...faceWithoutFileProperty } = face; + const fontFaceSettings = { + ...faceWithoutFileProperty, + src: fileId, + }; + formData.append( + 'font_face_settings', + JSON.stringify( fontFaceSettings ) + ); + } else { + formData.append( 'font_face_settings', JSON.stringify( face ) ); } - ); - newFontFamily.fontFace = newFontFaces; + return formData; + } ); + + return fontFacesFormData; } +} - formData.append( 'font_family_settings', JSON.stringify( newFontFamily ) ); - return formData; +export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { + const promises = fontFacesData.map( ( faceData ) => + fetchInstallFontFamily( fontFamilyId, faceData ) + ); + const responses = await Promise.allSettled( promises ); + + const results = { + errors: [], + successes: [], + }; + + responses.forEach( ( result, index ) => { + if ( result.status === 'fulfilled' ) { + const response = result.value; + if ( response.ok ) { + results.successes.push( response.data ); + } else { + // Handle HTTP error statuses + results.errors.push( { + error: `HTTP error: ${ response.status }`, + data: fontFacesData[ index ], + } ); + } + } else { + // Handle network errors or other fetch-related errors + results.errors.push( { + error: `Fetch error: ${ result.reason }`, + data: fontFacesData[ index ], + } ); + } + } ); + + return results; } /* From 3c657712f3d412bf65c44299913d930fc1941ea6 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Sun, 14 Jan 2024 22:25:42 -0600 Subject: [PATCH 02/15] Fix resolver name. --- .../global-styles/font-library-modal/utils/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index b722fc3d26084e..9c7af7d63b569d 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -8,7 +8,7 @@ import { privateApis as componentsPrivateApis } from '@wordpress/components'; */ import { FONT_WEIGHTS, FONT_STYLES } from './constants'; import { unlock } from '../../../../lock-unlock'; -import { fetchInstallFontFamily } from '../resolvers'; +import { fetchInstallFontFace } from '../resolvers'; /** * Browser dependencies @@ -184,7 +184,7 @@ export function makeFontFacesFormData( font ) { export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { const promises = fontFacesData.map( ( faceData ) => - fetchInstallFontFamily( fontFamilyId, faceData ) + fetchInstallFontFace( fontFamilyId, faceData ) ); const responses = await Promise.allSettled( promises ); From 2ba4fc45a77c8ab1e4b11f6eb196f937348be675 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 15 Jan 2024 13:22:36 -0600 Subject: [PATCH 03/15] Add embedding and rebuild theme.json settings for fontFamily. --- .../global-styles/font-library-modal/context.js | 13 ++++++++++--- .../global-styles/font-library-modal/utils/index.js | 6 ++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 986a8ae12bc74c..6eba1e44dc1cbb 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -62,11 +62,18 @@ function FontLibraryProvider( { children } ) { records: libraryPosts = [], isResolving: isResolvingLibrary, hasResolved: hasResolvedLibrary, - } = useEntityRecords( 'postType', 'wp_font_family', { refreshKey } ); + } = useEntityRecords( 'postType', 'wp_font_family', { + refreshKey, + _embed: true, + } ); const libraryFonts = - ( libraryPosts || [] ).map( ( post ) => post.font_family_settings ) || - []; + ( libraryPosts || [] ).map( ( post ) => { + post.font_family_settings.fontFace = post._embedded.font_faces.map( + ( face ) => face.font_face_settings + ); + return post.font_family_settings; + } ) || []; // Global Styles (settings) font families const [ fontFamilies, setFontFamilies ] = useGlobalSetting( diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index 9c7af7d63b569d..fd9438d41e8fe7 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -201,15 +201,17 @@ export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { } else { // Handle HTTP error statuses results.errors.push( { - error: `HTTP error: ${ response.status }`, data: fontFacesData[ index ], + error: `HTTP error: ${ response.status }`, + message: response.message, } ); } } else { // Handle network errors or other fetch-related errors results.errors.push( { - error: `Fetch error: ${ result.reason }`, data: fontFacesData[ index ], + error: `Fetch error: ${ result.reason }`, + message: result.message, } ); } } ); From 73bd4d9ad873e08d42bea29a140713203a931438 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 15 Jan 2024 14:20:06 -0600 Subject: [PATCH 04/15] Handle responses directly, add to collection before activating. Remove unused test. --- .../font-library-modal/context.js | 10 +++- .../font-library-modal/utils/index.js | 9 +-- .../test/makeFormDataFromFontFamily.spec.js | 58 ------------------- 3 files changed, 12 insertions(+), 65 deletions(-) delete mode 100644 packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFormDataFromFontFamily.spec.js diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 6eba1e44dc1cbb..9aa9636bb18566 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -222,13 +222,21 @@ function FontLibraryProvider( { children } ) { fontFacesFormData ); - const fontsInstalled = response?.successes || []; + const fontFacesInstalled = response?.successes || []; + + // now we need to rebuild this in theme.json format: + const fontsInstalled = + fontFacesInstalled.map( ( face ) => { + return face.font_face_settings; + } ) || []; + // Get intersecting font faces between the fonts we tried to installed and the fonts that were installed // (to avoid activating a non installed font). const fontToBeActivated = getIntersectingFontFaces( fontsInstalled, [ font ] ); + // Activate the font families (add the font families to the global styles). activateCustomFontFamilies( fontToBeActivated ); // Save the global styles to the database. diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index fd9438d41e8fe7..13305b6854573c 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -196,14 +196,12 @@ export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { responses.forEach( ( result, index ) => { if ( result.status === 'fulfilled' ) { const response = result.value; - if ( response.ok ) { - results.successes.push( response.data ); + if ( response.id ) { + results.successes.push( response ); } else { - // Handle HTTP error statuses results.errors.push( { data: fontFacesData[ index ], - error: `HTTP error: ${ response.status }`, - message: response.message, + message: `Error: ${ response.message }`, } ); } } else { @@ -211,7 +209,6 @@ export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { results.errors.push( { data: fontFacesData[ index ], error: `Fetch error: ${ result.reason }`, - message: result.message, } ); } } ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFormDataFromFontFamily.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFormDataFromFontFamily.spec.js deleted file mode 100644 index 9f38903c89759b..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/makeFormDataFromFontFamily.spec.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Internal dependencies - */ -import { makeFormDataFromFontFamily } from '../index'; - -/* global File */ - -describe( 'makeFormDataFromFontFamily', () => { - it( 'should process fontFamilies and return FormData', () => { - const mockFontFamily = { - slug: 'bebas', - name: 'Bebas', - fontFamily: 'Bebas', - fontFace: [ - { - file: new File( [ 'content' ], 'test-font1.woff2' ), - fontWeight: '500', - fontStyle: 'normal', - }, - { - file: new File( [ 'content' ], 'test-font2.woff2' ), - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }; - - const formData = makeFormDataFromFontFamily( mockFontFamily ); - - expect( formData instanceof FormData ).toBeTruthy(); - - // Check if files are added correctly - expect( formData.get( 'file-0' ).name ).toBe( 'test-font1.woff2' ); - expect( formData.get( 'file-1' ).name ).toBe( 'test-font2.woff2' ); - - // Check if 'fontFamilies' key in FormData is correct - const expectedFontFamily = { - fontFace: [ - { - fontWeight: '500', - fontStyle: 'normal', - uploadedFile: 'file-0', - }, - { - fontWeight: '400', - fontStyle: 'normal', - uploadedFile: 'file-1', - }, - ], - slug: 'bebas', - name: 'Bebas', - fontFamily: 'Bebas', - }; - expect( JSON.parse( formData.get( 'font_family_settings' ) ) ).toEqual( - expectedFontFamily - ); - } ); -} ); From c251a31c52a12f0212471a105419f4014bca7882 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 15 Jan 2024 14:36:44 -0600 Subject: [PATCH 05/15] Remove getIntersectingFontFaces. --- .../global-styles/font-library-modal/context.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 9aa9636bb18566..6c338bb2b1cea3 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -31,7 +31,6 @@ import { batchInstallFontFaces, } from './utils'; import { toggleFont } from './utils/toggleFont'; -import getIntersectingFontFaces from './utils/get-intersecting-font-faces'; export const FontLibraryContext = createContext( {} ); @@ -224,21 +223,14 @@ function FontLibraryProvider( { children } ) { const fontFacesInstalled = response?.successes || []; - // now we need to rebuild this in theme.json format: - const fontsInstalled = + // Rebuild fontFace settings + font.fontFace = fontFacesInstalled.map( ( face ) => { return face.font_face_settings; } ) || []; - // Get intersecting font faces between the fonts we tried to installed and the fonts that were installed - // (to avoid activating a non installed font). - const fontToBeActivated = getIntersectingFontFaces( - fontsInstalled, - [ font ] - ); - - // Activate the font families (add the font families to the global styles). - activateCustomFontFamilies( fontToBeActivated ); + // Activate the font family (add the font family to the global styles). + activateCustomFontFamilies( [ font ] ); // Save the global styles to the database. saveSpecifiedEntityEdits( 'root', 'globalStyles', globalStylesId, [ 'settings.typography.fontFamilies', From 94b32c57fefc2c2438928c9e6433869b96f6cbde Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 15 Jan 2024 20:29:14 -0600 Subject: [PATCH 06/15] Check for existing font family before installing. --- .../font-library-modal/context.js | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 6c338bb2b1cea3..69351562c7a6e2 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -202,18 +202,26 @@ function FontLibraryProvider( { children } ) { async function installFont( font ) { setIsInstalling( true ); try { - // Prepare formData to install. - const fontFamilyFormData = makeFontFamilyFormData( font ); + // Get the ID of the font family post, if it is already installed. + let fontFamilyId = libraryPosts.filter( + ( post ) => post.font_family_settings.slug === font.slug + )[ 0 ]?.id; + + // Otherwise, install it. + if ( ! fontFamilyId ) { + const fontFamilyFormData = makeFontFamilyFormData( font ); + // Prepare font family form data to install. + fontFamilyId = await fetchInstallFontFamily( + fontFamilyFormData + ) + .then( ( response ) => response.id ) + .catch( ( e ) => { + throw Error( e.message ); + } ); + } + + // Prepare font faces form data to install. const fontFacesFormData = makeFontFacesFormData( font ); - const fontFamilyId = await fetchInstallFontFamily( - fontFamilyFormData - ) - .then( ( response ) => response.id ) - .catch( ( e ) => { - // eslint-disable-next-line no-console - console.error( e ); - throw Error( 'Unable to install font family.' ); - } ); // Install the fonts (upload the font files to the server and create the post in the database). const response = await batchInstallFontFaces( From ac9f29dc88d6b150fd0fde51ece8d8d6c20a84e1 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Mon, 15 Jan 2024 21:30:17 -0500 Subject: [PATCH 07/15] Reference src, not uploadedFile key. Co-authored-by: Matias Benedetto --- .../components/global-styles/font-library-modal/utils/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index 13305b6854573c..98b6375740e5b4 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -162,7 +162,7 @@ export function makeFontFacesFormData( font ) { const fileId = `file-${ faceIndex }`; // Add the files to the formData formData.append( fileId, face.file, face.file.name ); - // remove the file object from the face object the file is referenced by the uploadedFile key + // remove the file object from the face object the file is referenced in src const { file, ...faceWithoutFileProperty } = face; const fontFaceSettings = { ...faceWithoutFileProperty, From 6648afc527c67e1c2b386df8990998f9a28e632a Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Tue, 16 Jan 2024 10:22:38 -0600 Subject: [PATCH 08/15] Check for existing font family using GET /font-families?slug=. --- .../global-styles/font-library-modal/context.js | 11 ++++++++--- .../global-styles/font-library-modal/resolvers.js | 8 ++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 69351562c7a6e2..27910010751597 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -14,6 +14,7 @@ import { * Internal dependencies */ import { + fetchGetFontFamilyBySlug, fetchInstallFontFamily, fetchUninstallFonts, fetchFontCollections, @@ -203,9 +204,13 @@ function FontLibraryProvider( { children } ) { setIsInstalling( true ); try { // Get the ID of the font family post, if it is already installed. - let fontFamilyId = libraryPosts.filter( - ( post ) => post.font_family_settings.slug === font.slug - )[ 0 ]?.id; + let fontFamilyId = await fetchGetFontFamilyBySlug( font.slug ) + .then( ( response ) => response?.[ 0 ]?.id ) + .catch( ( e ) => { + // eslint-disable-next-line no-console + console.error( e ); + return null; + } ); // Otherwise, install it. if ( ! fontFamilyId ) { diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js index d03140a5a83335..a34c63233f7d71 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js @@ -25,6 +25,14 @@ export async function fetchInstallFontFace( fontFamilyId, data ) { return apiFetch( config ); } +export async function fetchGetFontFamilyBySlug( slug ) { + const config = { + path: `/wp/v2/font-families?slug=${ slug }`, + method: 'GET', + }; + return apiFetch( config ); +} + export async function fetchUninstallFonts( fonts ) { const data = { font_families: fonts, From 1c0f3358c043efc3a4e8706fcdf187c47f955c0f Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Wed, 17 Jan 2024 06:23:40 -0500 Subject: [PATCH 09/15] Filter already installed font faces (determined by matching fontWeight AND fontStyle) --- .../font-library-modal/context.js | 67 ++++++++++++++++--- .../font-library-modal/resolvers.js | 2 +- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 27910010751597..c6e37d45c689ec 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -69,9 +69,10 @@ function FontLibraryProvider( { children } ) { const libraryFonts = ( libraryPosts || [] ).map( ( post ) => { - post.font_family_settings.fontFace = post._embedded.font_faces.map( - ( face ) => face.font_face_settings - ); + post.font_family_settings.fontFace = + post?._embedded?.font_faces.map( + ( face ) => face.font_face_settings + ) || []; return post.font_family_settings; } ) || []; @@ -204,8 +205,23 @@ function FontLibraryProvider( { children } ) { setIsInstalling( true ); try { // Get the ID of the font family post, if it is already installed. - let fontFamilyId = await fetchGetFontFamilyBySlug( font.slug ) - .then( ( response ) => response?.[ 0 ]?.id ) + let installedFontFamily = await fetchGetFontFamilyBySlug( + font.slug + ) + .then( ( response ) => { + if ( ! response || response.length === 0 ) { + return null; + } + const fontFamilyPost = response[ 0 ]; + return { + id: fontFamilyPost.id, + ...fontFamilyPost.font_family_settings, + fontFace: + fontFamilyPost?._embedded?.font_faces.map( + ( face ) => face.font_face_settings + ) || [], + }; + } ) .catch( ( e ) => { // eslint-disable-next-line no-console console.error( e ); @@ -213,24 +229,57 @@ function FontLibraryProvider( { children } ) { } ); // Otherwise, install it. - if ( ! fontFamilyId ) { + if ( ! installedFontFamily ) { const fontFamilyFormData = makeFontFamilyFormData( font ); // Prepare font family form data to install. - fontFamilyId = await fetchInstallFontFamily( + installedFontFamily = await fetchInstallFontFamily( fontFamilyFormData ) - .then( ( response ) => response.id ) + .then( ( response ) => { + return { + id: response.id, + ...response.font_face_settings, + fontFace: [], + }; + } ) .catch( ( e ) => { throw Error( e.message ); } ); } + // Filter Font Faces that have already been installed + // We determine that by comparing the fontWeight and fontStyle + font.fontFace = font.fontFace.filter( ( fontFaceToInstall ) => { + return ( + -1 === + installedFontFamily.fontFace.findIndex( + ( installedFontFace ) => { + return ( + installedFontFace.fontWeight === + fontFaceToInstall.fontWeight && + installedFontFace.fontStyle === + fontFaceToInstall.fontStyle + ); + } + ) + ); + } ); + + if ( font.fontFace.length === 0 ) { + // Looks like we're only trying to install fonts that are already installed. + // Let's not do that. + // TODO: Exit with an error message? + return { + errors: [ 'All font faces are already installed' ], + }; + } + // Prepare font faces form data to install. const fontFacesFormData = makeFontFacesFormData( font ); // Install the fonts (upload the font files to the server and create the post in the database). const response = await batchInstallFontFaces( - fontFamilyId, + installedFontFamily.id, fontFacesFormData ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js index a34c63233f7d71..08e37dc7ee95fb 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js @@ -27,7 +27,7 @@ export async function fetchInstallFontFace( fontFamilyId, data ) { export async function fetchGetFontFamilyBySlug( slug ) { const config = { - path: `/wp/v2/font-families?slug=${ slug }`, + path: `/wp/v2/font-families?slug=${ slug }&_embed=true`, method: 'GET', }; return apiFetch( config ); From 1c9b7f33845d06cfb41c387bebf8c01b1bb01dd2 Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Wed, 17 Jan 2024 06:47:07 -0500 Subject: [PATCH 10/15] moved response processing into the resolver for fetchGetFontFamilyBySlug --- .../font-library-modal/context.js | 23 ++----------------- .../font-library-modal/resolvers.js | 15 +++++++++++- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index c6e37d45c689ec..eeea4c533d5867 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -204,29 +204,10 @@ function FontLibraryProvider( { children } ) { async function installFont( font ) { setIsInstalling( true ); try { - // Get the ID of the font family post, if it is already installed. + // Get the font family if it is already installed. let installedFontFamily = await fetchGetFontFamilyBySlug( font.slug - ) - .then( ( response ) => { - if ( ! response || response.length === 0 ) { - return null; - } - const fontFamilyPost = response[ 0 ]; - return { - id: fontFamilyPost.id, - ...fontFamilyPost.font_family_settings, - fontFace: - fontFamilyPost?._embedded?.font_faces.map( - ( face ) => face.font_face_settings - ) || [], - }; - } ) - .catch( ( e ) => { - // eslint-disable-next-line no-console - console.error( e ); - return null; - } ); + ); // Otherwise, install it. if ( ! installedFontFamily ) { diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js index 08e37dc7ee95fb..940a6dc811e8d4 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js @@ -30,7 +30,20 @@ export async function fetchGetFontFamilyBySlug( slug ) { path: `/wp/v2/font-families?slug=${ slug }&_embed=true`, method: 'GET', }; - return apiFetch( config ); + return apiFetch( config ).then( ( response ) => { + if ( ! response || response.length === 0 ) { + return null; + } + const fontFamilyPost = response[ 0 ]; + return { + id: fontFamilyPost.id, + ...fontFamilyPost.font_family_settings, + fontFace: + fontFamilyPost?._embedded?.font_faces.map( + ( face ) => face.font_face_settings + ) || [], + }; + } ); } export async function fetchUninstallFonts( fonts ) { From cf2b95c96330a0511a3bf3ccbfdc9fcd064ea5c9 Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Wed, 17 Jan 2024 07:12:39 -0500 Subject: [PATCH 11/15] Moved response processing for font family installation to the resolver --- .../font-library-modal/context.js | 68 ++++++++----------- .../font-library-modal/resolvers.js | 8 ++- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index eeea4c533d5867..a76e962de5b57d 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -201,52 +201,43 @@ function FontLibraryProvider( { children } ) { return getActivatedFontsOutline( source )[ slug ] || []; }; - async function installFont( font ) { + async function installFont( fontFamilyToInstall ) { setIsInstalling( true ); try { - // Get the font family if it is already installed. + // Get the font family if it already exists. let installedFontFamily = await fetchGetFontFamilyBySlug( - font.slug + fontFamilyToInstall.slug ); - // Otherwise, install it. + // Otherwise create it. if ( ! installedFontFamily ) { - const fontFamilyFormData = makeFontFamilyFormData( font ); // Prepare font family form data to install. installedFontFamily = await fetchInstallFontFamily( - fontFamilyFormData - ) - .then( ( response ) => { - return { - id: response.id, - ...response.font_face_settings, - fontFace: [], - }; - } ) - .catch( ( e ) => { - throw Error( e.message ); - } ); + makeFontFamilyFormData( fontFamilyToInstall ) + ); } // Filter Font Faces that have already been installed // We determine that by comparing the fontWeight and fontStyle - font.fontFace = font.fontFace.filter( ( fontFaceToInstall ) => { - return ( - -1 === - installedFontFamily.fontFace.findIndex( - ( installedFontFace ) => { - return ( - installedFontFace.fontWeight === - fontFaceToInstall.fontWeight && - installedFontFace.fontStyle === - fontFaceToInstall.fontStyle - ); - } - ) - ); - } ); + fontFamilyToInstall.fontFace = fontFamilyToInstall.fontFace.filter( + ( fontFaceToInstall ) => { + return ( + -1 === + installedFontFamily.fontFace.findIndex( + ( installedFontFace ) => { + return ( + installedFontFace.fontWeight === + fontFaceToInstall.fontWeight && + installedFontFace.fontStyle === + fontFaceToInstall.fontStyle + ); + } + ) + ); + } + ); - if ( font.fontFace.length === 0 ) { + if ( fontFamilyToInstall.fontFace.length === 0 ) { // Looks like we're only trying to install fonts that are already installed. // Let's not do that. // TODO: Exit with an error message? @@ -255,29 +246,28 @@ function FontLibraryProvider( { children } ) { }; } - // Prepare font faces form data to install. - const fontFacesFormData = makeFontFacesFormData( font ); - // Install the fonts (upload the font files to the server and create the post in the database). const response = await batchInstallFontFaces( installedFontFamily.id, - fontFacesFormData + makeFontFacesFormData( fontFamilyToInstall ) ); const fontFacesInstalled = response?.successes || []; // Rebuild fontFace settings - font.fontFace = + fontFamilyToInstall.fontFace = fontFacesInstalled.map( ( face ) => { return face.font_face_settings; } ) || []; // Activate the font family (add the font family to the global styles). - activateCustomFontFamilies( [ font ] ); + activateCustomFontFamilies( [ fontFamilyToInstall ] ); + // Save the global styles to the database. saveSpecifiedEntityEdits( 'root', 'globalStyles', globalStylesId, [ 'settings.typography.fontFamilies', ] ); + refreshLibrary(); return response; diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js index 940a6dc811e8d4..870c4385810d18 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js @@ -13,7 +13,13 @@ export async function fetchInstallFontFamily( data ) { method: 'POST', body: data, }; - return apiFetch( config ); + return apiFetch( config ).then( ( response ) => { + return { + id: response.id, + ...response.font_face_settings, + fontFace: [], + }; + } ); } export async function fetchInstallFontFace( fontFamilyId, data ) { From 5b82fc021b2f743450e4093cc2b4e02c0ad451e0 Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Wed, 17 Jan 2024 09:40:36 -0500 Subject: [PATCH 12/15] Refactored font face installation process to handle errors more cleanly --- .../font-library-modal/context.js | 85 +++--- .../font-library-modal/font-collection.js | 16 +- .../font-library-modal/local-fonts.js | 17 +- .../font-library-modal/resolvers.js | 7 +- .../utils/get-intersecting-font-faces.js | 58 ---- .../utils/get-notice-from-response.js | 62 ---- .../font-library-modal/utils/index.js | 20 ++ .../test/getIntersectingFontFaces.spec.js | 271 ------------------ 8 files changed, 95 insertions(+), 441 deletions(-) delete mode 100644 packages/edit-site/src/components/global-styles/font-library-modal/utils/get-intersecting-font-faces.js delete mode 100644 packages/edit-site/src/components/global-styles/font-library-modal/utils/get-notice-from-response.js delete mode 100644 packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getIntersectingFontFaces.spec.js diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index a76e962de5b57d..863ff0f2e00892 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -30,6 +30,7 @@ import { makeFontFacesFormData, makeFontFamilyFormData, batchInstallFontFaces, + checkFontFaceInstalled, } from './utils'; import { toggleFont } from './utils/toggleFont'; @@ -217,48 +218,50 @@ function FontLibraryProvider( { children } ) { ); } - // Filter Font Faces that have already been installed - // We determine that by comparing the fontWeight and fontStyle + // Collect font faces that have already been installed (to be activated later) + const alreadyInstalledFontFaces = + installedFontFamily.fontFace.filter( ( fontFaceToInstall ) => + checkFontFaceInstalled( + fontFaceToInstall, + fontFamilyToInstall.fontFace + ) + ); + + // Filter out Font Faces that have already been installed (so that they are not re-installed) fontFamilyToInstall.fontFace = fontFamilyToInstall.fontFace.filter( - ( fontFaceToInstall ) => { - return ( - -1 === - installedFontFamily.fontFace.findIndex( - ( installedFontFace ) => { - return ( - installedFontFace.fontWeight === - fontFaceToInstall.fontWeight && - installedFontFace.fontStyle === - fontFaceToInstall.fontStyle - ); - } - ) - ); - } + ( fontFaceToInstall ) => + ! checkFontFaceInstalled( + fontFaceToInstall, + installedFontFamily.fontFace + ) ); - if ( fontFamilyToInstall.fontFace.length === 0 ) { - // Looks like we're only trying to install fonts that are already installed. - // Let's not do that. - // TODO: Exit with an error message? - return { - errors: [ 'All font faces are already installed' ], - }; - } - // Install the fonts (upload the font files to the server and create the post in the database). - const response = await batchInstallFontFaces( - installedFontFamily.id, - makeFontFacesFormData( fontFamilyToInstall ) - ); + let sucessfullyInstalledFontFaces = []; + let unsucessfullyInstalledFontFaces = []; + if ( fontFamilyToInstall.fontFace.length > 0 ) { + const response = await batchInstallFontFaces( + installedFontFamily.id, + makeFontFacesFormData( fontFamilyToInstall ) + ); + sucessfullyInstalledFontFaces = response?.successes; + unsucessfullyInstalledFontFaces = response?.errors; + } - const fontFacesInstalled = response?.successes || []; + // If there were no successes and nothing already installed then we don't need to activate anything and can bounce now. + if ( + sucessfullyInstalledFontFaces.length === 0 && + alreadyInstalledFontFaces.length === 0 + ) { + throw new Error( 'No font faces were installed.' ); + } - // Rebuild fontFace settings - fontFamilyToInstall.fontFace = - fontFacesInstalled.map( ( face ) => { - return face.font_face_settings; - } ) || []; + // Use the sucessfully installed font faces + // As well as any font faces that were already installed (those will be activated) + fontFamilyToInstall.fontFace = [ + ...sucessfullyInstalledFontFaces, + ...alreadyInstalledFontFaces, + ]; // Activate the font family (add the font family to the global styles). activateCustomFontFamilies( [ fontFamilyToInstall ] ); @@ -270,11 +273,11 @@ function FontLibraryProvider( { children } ) { refreshLibrary(); - return response; - } catch ( error ) { - return { - errors: [ error ], - }; + if ( unsucessfullyInstalledFontFaces.length > 0 ) { + throw new Error( + 'Some font faces were installed. There were some errors.' + ); + } } finally { setIsInstalling( false ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js index f7f33032f1e3f5..d65e7ab7ac47f7 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js @@ -30,7 +30,6 @@ import CollectionFontDetails from './collection-font-details'; import { toggleFont } from './utils/toggleFont'; import { getFontsOutline } from './utils/fonts-outline'; import GoogleFontsConfirmDialog from './google-fonts-confirm-dialog'; -import { getNoticeFromInstallResponse } from './utils/get-notice-from-response'; import { downloadFontFaceAsset } from './utils'; const DEFAULT_CATEGORY = { @@ -182,9 +181,18 @@ function FontCollection( { id } ) { return; } - const response = await installFont( fontFamily ); - const installNotice = getNoticeFromInstallResponse( response ); - setNotice( installNotice ); + try { + await installFont( fontFamily ); + setNotice( { + type: 'success', + message: __( 'Fonts were installed successfully.' ), + } ); + } catch ( error ) { + setNotice( { + type: 'error', + message: error, + } ); + } resetFontsToInstall(); }; diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js index d4221b420cb613..a3aab609760f31 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js @@ -23,7 +23,6 @@ import { FontLibraryContext } from './context'; import { Font } from '../../../../lib/lib-font.browser'; import makeFamiliesFromFaces from './utils/make-families-from-faces'; import { loadFontFaceInBrowser } from './utils'; -import { getNoticeFromInstallResponse } from './utils/get-notice-from-response'; import { unlock } from '../../../lock-unlock'; const { ProgressBar } = unlock( componentsPrivateApis ); @@ -164,9 +163,19 @@ function LocalFonts() { return; } - const response = await installFont( fontFamilies[ 0 ] ); - const installNotice = getNoticeFromInstallResponse( response ); - setNotice( installNotice ); + try { + await installFont( fontFamilies[ 0 ] ); + setNotice( { + type: 'success', + message: __( 'Fonts were installed successfully.' ), + } ); + } catch ( error ) { + setNotice( { + type: 'error', + message: error, + } ); + } + setIsUploading( false ); }; diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js index 870c4385810d18..df10904b75026f 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/resolvers.js @@ -28,7 +28,12 @@ export async function fetchInstallFontFace( fontFamilyId, data ) { method: 'POST', body: data, }; - return apiFetch( config ); + return apiFetch( config ).then( ( response ) => { + return { + id: response.id, + ...response.font_face_settings, + }; + } ); } export async function fetchGetFontFamilyBySlug( slug ) { diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/get-intersecting-font-faces.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/get-intersecting-font-faces.js deleted file mode 100644 index e21e72c58ed533..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/get-intersecting-font-faces.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Retrieves intersecting font faces between two sets of fonts. - * - * For each font in the `incoming` list, the function checks for a corresponding match - * in the `existing` list based on the `slug` property. If a match is found and both - * have `fontFace` properties, it further narrows down to matching font faces based on - * the `fontWeight` and `fontStyle`. The result includes the properties of the matched - * existing font but only with intersecting font faces. - * - * @param {Array.<{ slug: string, fontFace?: Array.<{ fontWeight: string, fontStyle: string }> }>} incoming - The list of fonts to compare. - * @param {Array.<{ slug: string, fontFace?: Array.<{ fontWeight: string, fontStyle: string }> }>} existing - The reference list of fonts. - * - * @return {Array.<{ slug: string, fontFace?: Array.<{ fontWeight: string, fontStyle: string }> }>} An array of fonts from the `existing` list with intersecting font faces. - * - * @example - * const incomingFonts = [ - * { slug: 'arial', fontFace: [{ fontWeight: '400', fontStyle: 'normal' }] }, - * { slug: 'times-new', fontFace: [{ fontWeight: '700', fontStyle: 'italic' }] } - * ]; - * - * const existingFonts = [ - * { slug: 'arial', fontFace: [{ fontWeight: '400', fontStyle: 'normal' }, { fontWeight: '700', fontStyle: 'italic' }] }, - * { slug: 'helvetica', fontFace: [{ fontWeight: '400', fontStyle: 'normal' }] } - * ]; - * - * getIntersectingFontFaces(incomingFonts, existingFonts); - * // Returns: - * // [{ slug: 'arial', fontFace: [{ fontWeight: '400', fontStyle: 'normal' }] }] - */ -export default function getIntersectingFontFaces( incoming, existing ) { - const matches = []; - - for ( const incomingFont of incoming ) { - const existingFont = existing.find( - ( f ) => f.slug === incomingFont.slug - ); - - if ( existingFont ) { - if ( incomingFont?.fontFace ) { - const matchingFaces = incomingFont.fontFace.filter( - ( face ) => { - return ( existingFont?.fontFace || [] ).find( ( f ) => { - return ( - f.fontWeight === face.fontWeight && - f.fontStyle === face.fontStyle - ); - } ); - } - ); - matches.push( { ...incomingFont, fontFace: matchingFaces } ); - } else { - matches.push( incomingFont ); - } - } - } - - return matches; -} diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/get-notice-from-response.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/get-notice-from-response.js deleted file mode 100644 index b22bd0afe23248..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/get-notice-from-response.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; - -export function getNoticeFromInstallResponse( response ) { - const { errors = [], successes = [] } = response; - // Everything failed. - if ( errors.length && ! successes.length ) { - return { - type: 'error', - message: __( 'Error installing the fonts.' ), - }; - } - - // Eveerything succeeded. - if ( ! errors.length && successes.length ) { - return { - type: 'success', - message: __( 'Fonts were installed successfully.' ), - }; - } - - // Some succeeded, some failed. - if ( errors.length && successes.length ) { - return { - type: 'warning', - message: __( - 'Some fonts were installed successfully and some failed.' - ), - }; - } -} - -export function getNoticeFromUninstallResponse( response ) { - const { errors = [], successes = [] } = response; - // Everything failed. - if ( errors.length && ! successes.length ) { - return { - type: 'error', - message: __( 'Error uninstalling the fonts.' ), - }; - } - - // Everything succeeded. - if ( ! errors.length && successes.length ) { - return { - type: 'success', - message: __( 'Fonts were uninstalled successfully.' ), - }; - } - - // Some succeeded, some failed. - if ( errors.length && successes.length ) { - return { - type: 'warning', - message: __( - 'Some fonts were uninstalled successfully and some failed.' - ), - }; - } -} diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index 98b6375740e5b4..09b9e733794645 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -245,3 +245,23 @@ export async function downloadFontFaceAsset( url ) { throw error; } ); } + +/* + * Determine if a given Font Face is present in a given collection. + * We determine that a font face has been installed by comparing the fontWeight and fontStyle + * + * @param {Object} fontFace The Font Face to seek + * @param {Array} collection The Collection to seek in + * @returns True if the font face is found in the collection. Otherwise False. + */ +export function checkFontFaceInstalled( fontFace, collection ) { + return ( + -1 !== + collection.findIndex( ( collectionFontFace ) => { + return ( + collectionFontFace.fontWeight === fontFace.fontWeight && + collectionFontFace.fontStyle === fontFace.fontStyle + ); + } ) + ); +} diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getIntersectingFontFaces.spec.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getIntersectingFontFaces.spec.js deleted file mode 100644 index 9899005ad65b89..00000000000000 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/test/getIntersectingFontFaces.spec.js +++ /dev/null @@ -1,271 +0,0 @@ -/** - * Internal dependencies - */ -import getIntersectingFontFaces from '../get-intersecting-font-faces'; - -describe( 'getIntersectingFontFaces', () => { - it( 'returns matching font faces for matching font family', () => { - const incomingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const existingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - - expect( result ).toEqual( incomingFontFamilies ); - } ); - - it( 'returns empty array when there is no match', () => { - const incomingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const existingFontFamilies = [ - { - slug: 'montserrat', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - - expect( result ).toEqual( [] ); - } ); - - it( 'returns matching font faces', () => { - const incomingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - { - fontWeight: '700', - fontStyle: 'italic', - }, - ], - }, - { - slug: 'times', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const existingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - { - fontWeight: '800', - fontStyle: 'italic', - }, - { - fontWeight: '900', - fontStyle: 'italic', - }, - ], - }, - ]; - - const expectedOutput = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - - expect( result ).toEqual( expectedOutput ); - } ); - - it( 'returns empty array when the first list is empty', () => { - const incomingFontFamilies = []; - - const existingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - - expect( result ).toEqual( [] ); - } ); - - it( 'returns empty array when the second list is empty', () => { - const incomingFontFamilies = [ - { - slug: 'lobster', - fontFace: [ - { - fontWeight: '400', - fontStyle: 'normal', - }, - ], - }, - ]; - - const existingFontFamilies = []; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - - expect( result ).toEqual( [] ); - } ); - - it( 'returns intersecting font family when there are no fonfaces', () => { - const incomingFontFamilies = [ - { - slug: 'piazzolla', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - }, - { - slug: 'lobster', - }, - ]; - - const existingFontFamilies = [ - { - slug: 'lobster', - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - - expect( result ).toEqual( existingFontFamilies ); - } ); - - it( 'returns intersecting if there is an intended font face and is not present in the returning it should not be returned', () => { - const incomingFontFamilies = [ - { - slug: 'piazzolla', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - }, - { - slug: 'lobster', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - }, - ]; - - const existingFontFamilies = [ - { - slug: 'lobster', - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - const expected = [ - { - slug: 'lobster', - fontFace: [], - }, - ]; - expect( result ).toEqual( expected ); - } ); - - it( 'updates font family definition using the incoming data', () => { - const incomingFontFamilies = [ - { - slug: 'gothic-a1', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - fontFamily: "'Gothic A1', serif", - }, - ]; - - const existingFontFamilies = [ - { - slug: 'gothic-a1', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - fontFamily: 'Gothic A1, serif', - }, - ]; - - const result = getIntersectingFontFaces( - incomingFontFamilies, - existingFontFamilies - ); - const expected = [ - { - slug: 'gothic-a1', - fontFace: [ { fontStyle: 'normal', fontWeight: '400' } ], - fontFamily: "'Gothic A1', serif", - }, - ]; - expect( result ).toEqual( expected ); - } ); -} ); From 9fe6ec147e5fbd5970bd62764a5b4295855c8da7 Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Wed, 17 Jan 2024 11:52:08 -0500 Subject: [PATCH 13/15] Cleanup error handling for font library view --- .../global-styles/font-library-modal/context.js | 14 ++++++++++++-- .../font-library-modal/font-collection.js | 2 +- .../font-library-modal/installed-fonts.js | 5 ++--- .../font-library-modal/local-fonts.js | 1 + .../font-library-modal/utils/index.js | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 863ff0f2e00892..2c175ace586bb2 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -248,12 +248,21 @@ function FontLibraryProvider( { children } ) { unsucessfullyInstalledFontFaces = response?.errors; } + const detailedErrorMessage = unsucessfullyInstalledFontFaces.reduce( + ( errorMessageCollection, error ) => { + return `${ errorMessageCollection } ${ error.message }`; + }, + '' + ); + // If there were no successes and nothing already installed then we don't need to activate anything and can bounce now. if ( sucessfullyInstalledFontFaces.length === 0 && alreadyInstalledFontFaces.length === 0 ) { - throw new Error( 'No font faces were installed.' ); + throw new Error( + 'No font faces were installed. ' + detailedErrorMessage + ); } // Use the sucessfully installed font faces @@ -275,7 +284,8 @@ function FontLibraryProvider( { children } ) { if ( unsucessfullyInstalledFontFaces.length > 0 ) { throw new Error( - 'Some font faces were installed. There were some errors.' + 'Some font faces were installed. There were some errors. ' + + detailedErrorMessage ); } } finally { diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js index d65e7ab7ac47f7..5b6eeb2481e7a4 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js @@ -190,7 +190,7 @@ function FontCollection( { id } ) { } catch ( error ) { setNotice( { type: 'error', - message: error, + message: error.message, } ); } resetFontsToInstall(); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js index d493a2a297b18b..48a53e54b7bc21 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js @@ -22,7 +22,6 @@ import FontsGrid from './fonts-grid'; import LibraryFontDetails from './library-font-details'; import LibraryFontCard from './library-font-card'; import ConfirmDeleteDialog from './confirm-delete-dialog'; -import { getNoticeFromUninstallResponse } from './utils/get-notice-from-response'; import { unlock } from '../../../lock-unlock'; const { ProgressBar } = unlock( componentsPrivateApis ); @@ -50,8 +49,8 @@ function InstalledFonts() { const handleConfirmUninstall = async () => { const response = await uninstallFont( libraryFontSelected ); - const uninstallNotice = getNoticeFromUninstallResponse( response ); - setNotice( uninstallNotice ); + // const uninstallNotice = getNoticeFromUninstallResponse( response ); + // setNotice( uninstallNotice ); // If the font was succesfully uninstalled it is unselected if ( ! response?.errors?.length ) { handleUnselectFont(); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js index a3aab609760f31..a77b524dddbed0 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/local-fonts.js @@ -160,6 +160,7 @@ function LocalFonts() { 'Variants from only one font family can be uploaded at a time.' ), } ); + setIsUploading( false ); return; } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js index 09b9e733794645..1adc8847f15171 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/utils/index.js @@ -208,7 +208,7 @@ export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) { // Handle network errors or other fetch-related errors results.errors.push( { data: fontFacesData[ index ], - error: `Fetch error: ${ result.reason }`, + message: `Fetch error: ${ result.reason.message }`, } ); } } ); From 406fb29714890b12a795bcaf6f0748bc8d90722d Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Wed, 17 Jan 2024 17:15:51 +0000 Subject: [PATCH 14/15] Add i18n function to error messages --- .../global-styles/font-library-modal/context.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 2c175ace586bb2..078d11e235c043 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -9,6 +9,7 @@ import { useEntityRecords, store as coreStore, } from '@wordpress/core-data'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -261,7 +262,8 @@ function FontLibraryProvider( { children } ) { alreadyInstalledFontFaces.length === 0 ) { throw new Error( - 'No font faces were installed. ' + detailedErrorMessage + __( 'No font faces were installed. ' ) + + detailedErrorMessage ); } @@ -284,8 +286,9 @@ function FontLibraryProvider( { children } ) { if ( unsucessfullyInstalledFontFaces.length > 0 ) { throw new Error( - 'Some font faces were installed. There were some errors. ' + - detailedErrorMessage + __( + 'Some font faces were installed. There were some errors. ' + ) + detailedErrorMessage ); } } finally { @@ -308,7 +311,7 @@ function FontLibraryProvider( { children } ) { [ 'settings.typography.fontFamilies' ] ); } - // Refresh the library (the the library font families from database). + // Refresh the library (the library font families from database). refreshLibrary(); return response; } catch ( error ) { From c960acbc41150995757c3708078550220ced06e6 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Wed, 17 Jan 2024 17:19:11 +0000 Subject: [PATCH 15/15] Add TODO comment for uninstall notice --- .../global-styles/font-library-modal/installed-fonts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js index 48a53e54b7bc21..0c481f6e4d8ca8 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js @@ -49,6 +49,7 @@ function InstalledFonts() { const handleConfirmUninstall = async () => { const response = await uninstallFont( libraryFontSelected ); + // TODO: Refactor uninstall notices // const uninstallNotice = getNoticeFromUninstallResponse( response ); // setNotice( uninstallNotice ); // If the font was succesfully uninstalled it is unselected