Skip to content

Commit 3518cc2

Browse files
committed
feature: added warning if site is not reachable
1 parent e3ec439 commit 3518cc2

File tree

3 files changed

+92
-15
lines changed

3 files changed

+92
-15
lines changed

assets/src/admin/templates/components/SiteSelection.js

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ import { getInitials } from '../../../js/utils';
1515
/**
1616
* SiteSelection component.
1717
*
18-
* @param {Object} props - Component props.
19-
* @param {Array} props.siteInfo - Array of connected site information.
20-
* @param {boolean} props.isApplying - Boolean indicating if templates are being applied.
21-
* @param {Function} props.setIsApplying - Function to set the isApplying state.
22-
* @param {Function} props.onApply - Function to handle applying templates to selected sites.
23-
* @param {Function} props.setIsApplyModalOpen - Function to control the visibility of the apply modal.
24-
* @param {Function} props.setSelectedSites - Function to set the selected site IDs.
25-
* @param {Array} props.selectedSites - Array of selected site IDs.
26-
* @param {Object} props.notice - Notice object containing type and message.
27-
* @param {Array} props.brandSiteTemplates - Array of templates available for brand sites.
28-
* @param {Array} props.selectedTemplates - Array of selected template IDs.
18+
* @param {Object} props - Component props.
19+
* @param {Array} props.siteInfo - Array of connected site information.
20+
* @param {boolean} props.isApplying - Boolean indicating if templates are being applied.
21+
* @param {Function} props.setIsApplying - Function to set the isApplying state.
22+
* @param {Function} props.onApply - Function to handle applying templates to selected sites.
23+
* @param {Function} props.setIsApplyModalOpen - Function to control the visibility of the apply modal.
24+
* @param {Function} props.setSelectedSites - Function to set the selected site IDs.
25+
* @param {Array} props.selectedSites - Array of selected site IDs.
26+
* @param {Object} props.notice - Notice object containing type and message.
27+
* @param {Array} props.brandSiteTemplates - Array of templates available for brand sites.
28+
* @param {Array} props.selectedTemplates - Array of selected template IDs.
29+
* @param {Object} props.sitesHealthCheckResult - Object containing health check results for sites.
2930
* @return {JSX.Element} The rendered component.
3031
*/
3132
const SiteSelection = ( {
@@ -39,6 +40,7 @@ const SiteSelection = ( {
3940
notice,
4041
brandSiteTemplates,
4142
selectedTemplates,
43+
sitesHealthCheckResult,
4244
} ) => {
4345
const handleSiteSelection = ( siteId ) => {
4446
setSelectedSites( ( prevSelected ) => {
@@ -145,7 +147,7 @@ const SiteSelection = ( {
145147
onClick={ selectAllSites }
146148
disabled={
147149
selectedSelectableSiteCount === selectableSiteCount ||
148-
selectableSiteCount === 0
150+
selectableSiteCount === 0
149151
}
150152
className="od-bulk-action"
151153
>
@@ -185,7 +187,7 @@ const SiteSelection = ( {
185187
<div className="od-sites-list od-sites-grid">
186188
{ siteInfo.map( ( { id, name, url, logo } ) => {
187189
const isSelected = selectedSites.includes( id );
188-
const isDisabled = areAllTemplatesPresent( id ) && ! isSelected;
190+
const isDisabled = ( ( areAllTemplatesPresent( id ) && ! isSelected ) || ( sitesHealthCheckResult[ id ] && ! sitesHealthCheckResult[ id ].success ) );
189191

190192
return (
191193
<div
@@ -205,7 +207,9 @@ const SiteSelection = ( {
205207
<div className="od-site-inner">
206208
{ isSelected && (
207209
<div className="od-site-selected-indicator">
208-
<span className="dashicons dashicons-yes-alt"></span>
210+
{
211+
renderIcon( { sitesHealthCheckResult, id } )
212+
}
209213
</div>
210214
) }
211215
{ isDisabled && ! isSelected && (
@@ -216,7 +220,7 @@ const SiteSelection = ( {
216220
'onedesign',
217221
) }
218222
>
219-
<span className="dashicons dashicons-yes"></span>
223+
{ renderIcon( { sitesHealthCheckResult, id } ) }
220224
</div>
221225
) }
222226
<div className="od-site-logo">
@@ -314,4 +318,22 @@ const SiteSelection = ( {
314318
);
315319
};
316320

321+
/**
322+
* Render the appropriate dashicon based on health check result.
323+
*
324+
* @param {Object} props - Component props.
325+
* @param {Object} props.sitesHealthCheckResult - Object containing health check results for sites.
326+
* @param {number} props.id - Site ID.
327+
* @return {JSX.Element} The rendered dashicon element.
328+
*/
329+
const renderIcon = ( { sitesHealthCheckResult, id } ) => {
330+
return (
331+
sitesHealthCheckResult[ id ] && ! sitesHealthCheckResult[ id ].success ? (
332+
<span className="dashicons dashicons-warning"></span>
333+
) : (
334+
<span className="dashicons dashicons-yes-alt"></span>
335+
)
336+
);
337+
};
338+
317339
export default SiteSelection;

assets/src/admin/templates/components/TemplateModal.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const TemplateModal = () => {
4343
const [ connectedSitesTemplates, setConnectedSitesTemplates ] = useState( {} );
4444
const [ notice, setNotice ] = useState( null );
4545
const [ isReSyncing, setIsReSyncing ] = useState( false );
46+
const [ sitesHealthCheckResult, setSitesHealthCheckResult ] = useState( {} );
4647
const [ tabs, setTabs ] = useState( [
4748
{
4849
name: 'baseTemplate',
@@ -54,6 +55,50 @@ const TemplateModal = () => {
5455
const [ isApplyModalOpen, setIsApplyModalOpen ] = useState( false );
5556
const [ isApplying, setIsApplying ] = useState( false );
5657

58+
const PerformHealthCheckOnSites = useCallback( async () => {
59+
setIsLoading( true );
60+
try {
61+
for ( const siteId of Object.keys( siteInfo ) ) {
62+
const siteUrl = siteInfo[ siteId ]?.url;
63+
const siteApiKey = siteInfo[ siteId ]?.api_key;
64+
if ( siteUrl ) {
65+
try {
66+
const response = await fetch(
67+
`${ siteUrl }/wp-json/onedesign/v1/health-check?timestamp=${ Date.now() }`,
68+
{
69+
method: 'GET',
70+
headers: {
71+
'Content-Type': 'application/json',
72+
'X-OneDesign-Token': siteApiKey,
73+
},
74+
},
75+
);
76+
const data = await response.json();
77+
if ( ! data.success ) {
78+
setSitesHealthCheckResult( ( prevResults ) => ( {
79+
...prevResults,
80+
[ siteInfo[ siteId ]?.id ]: { success: false, message: data.message || __( 'Health check failed.', 'onedesign' ) },
81+
} ) );
82+
continue;
83+
}
84+
setSitesHealthCheckResult( ( prevResults ) => ( {
85+
...prevResults,
86+
[ siteInfo[ siteId ]?.id ]: data,
87+
} ) );
88+
} catch ( error ) {
89+
setSitesHealthCheckResult( ( prevResults ) => ( {
90+
...prevResults,
91+
[ siteInfo[ siteId ]?.id ]: { success: false, message: 'Failed to reach the site.' },
92+
} ) );
93+
}
94+
}
95+
}
96+
} catch ( error ) {
97+
} finally {
98+
setIsLoading( false );
99+
}
100+
}, [ siteInfo ] );
101+
57102
const fetchConnectedSitesTemplates = useCallback( async () => {
58103
try {
59104
const response = await fetch(
@@ -220,6 +265,11 @@ const TemplateModal = () => {
220265
// eslint-disable-next-line react-hooks/exhaustive-deps
221266
}, [] );
222267

268+
// to check if the connected sites are reachable or not
269+
useEffect( () => {
270+
PerformHealthCheckOnSites();
271+
}, [ PerformHealthCheckOnSites ] );
272+
223273
// clear notice on tab change
224274
useEffect( () => {
225275
setNotice( null );
@@ -432,6 +482,7 @@ const TemplateModal = () => {
432482
notice={ notice }
433483
brandSiteTemplates={ connectedSitesTemplates }
434484
selectedTemplates={ selectedTemplates }
485+
sitesHealthCheckResult={ sitesHealthCheckResult }
435486
/>
436487
</Modal>
437488
) }

assets/src/css/editor.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,10 @@
786786
width: 16px;
787787
height: 16px;
788788
}
789+
790+
&:has(.dashicons.dashicons-warning) {
791+
background: #d63638;
792+
}
789793
}
790794

791795
.od-site-label {

0 commit comments

Comments
 (0)