In AEM Content Fragments Experience UI (https://experience.adobe.com/) add an Extension App to show Page References of the selected Content Fragment...
Demo | Package Install | Github
AEM Module
set JAVA_HOME=C:/Progra~1/Java/jdk-11.0.6
mvn -B org.apache.maven.plugins:maven-archetype-plugin:3.2.1:generate -D archetypeGroupId=com.adobe.aem
-D archetypeArtifactId=aem-project-archetype -D archetypeVersion=48 -D aemVersion="cloud"
-D appTitle="Experience AIO CF Page References" -D appId="eaem-cf-page-references"
-D groupId="apps.experienceaem.sites" -D frontendModule=none -D includeExamples=n -D includeDispatcherConfig=n
2) Add the Data Source code in eaem-cf-page-references\ui.apps\src\main\content\jcr_root\apps\eaem-cf-page-references\components\cf-page-references\cf-page-references.jsp to get the page references
<%@include file="/libs/granite/ui/global.jsp"%>
<%@page session="false"
import="java.util.Iterator,
org.apache.sling.commons.json.JSONObject,
com.adobe.granite.ui.components.Tag"%>
<%@ page import="com.adobe.granite.ui.components.ds.DataSource" %>
<%@ page import="org.apache.sling.api.SlingHttpServletRequest" %>
<%@ page import="org.apache.sling.api.resource.Resource" %>
<%@ page import="org.apache.sling.api.resource.ValueMap" %>
<%@ page import="com.adobe.granite.ui.components.ds.SimpleDataSource" %>
<%@ page import="org.apache.sling.api.resource.ResourceMetadata" %>
<%
response.setContentType("application/json");
Resource datasource = resource.getChild("datasource");
DataSource refsDS = cmp.asDataSource(datasource);
JSONObject cfReferences = new JSONObject();
ValueMap refResVM = null;
if(refsDS == null){
cfReferences.write(response.getWriter());
return;
}
ResourceMetadata refResourceMeta = null;
for (Iterator<Resource> items = refsDS.iterator(); items.hasNext();) {
refResourceMeta = items.next().getResourceMetadata();
cfReferences.put(String.valueOf(refResourceMeta.get("path")), refResourceMeta.get("title"));
}
cfReferences.write(response.getWriter());
%>
3) Add the Data Source Config in eaem-cf-page-references\ui.apps\src\main\content\jcr_root\apps\eaem-cf-page-references\components\cf-page-references\references\.content.xml
<?xml version="1.0"encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"xmlns:jcr="http://www.jcp.org/jcr/1.0"xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
sling:resourceType="/apps/eaem-cf-page-references/components/cf-page-references">
<datasource
jcr:primaryType="nt:unstructured"
path="${empty requestPathInfo.suffix ? param.item : requestPathInfo.suffix}"
sling:resourceType="dam/gui/coral/components/datasource/assetreferencesdatasource"/>
</jcr:root>
4) We can now get the references of a CF with the following url...
https://author-p10961-e880305.adobeaemcloud.com/apps/eaem-cf-page-references/components/cf-page-references/references.html/content/dam/eaem-cf-page-references/home-1
5) For the App to make CORS Requests to get references, add the following code in eaem-cf-page-references\ui.config\src\main\content\jcr_root\apps\eaem-cf-page-references\osgiconfig\config.author\com.adobe.granite.cors.impl.CORSPolicyImpl~eaem-cf-page-references.cfg.json
{
"alloworigin": [""],
"allowedpaths": ["/apps/eaem-cf-page-references.*"],
"supportedheaders": [
"Authorization",
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
],
"supportedmethods": ["GET","HEAD"],
"alloworiginregexp": [ ".*"]
}
6) "alloworiginregexp": [ ".*" ] in the above config lets browser execute CORS requests from https://experience.adobe.com/ to https://author-p10961-e880305.adobeaemcloud.com/
7) AEM part of the extension is now implemented, next steps are for creating the UI Extension....
UI App Extension Module
8) Sign-In to https://developer.adobe.com/console/home and create a project using App Builder Template (check product documentation - https://developer.adobe.com/uix/docs/services/aem-cf-console-admin/extension-development/ )
9) Browse local file system of maven project created, create app parent folder aio-app eg. eaem-cf-page-references\aio-app
> mkdir aio-app
> cd aio-app
10) Make sure you have the latest node, npm, aio-cli versions...
> node -v
> npm -v
> npm install -g @adobe/aio-cli
11) Sign in to Experience Cloud from the cli ( because of multiple orgs associated with this test account, sign-in process here involves getting the url and opening it in a new incognito window)
> aio login -l -f --no-open
12) Make sure you are in the app folder eg. eaem-cf-page-references\aio-app, and Init the App (check product documentation - https://developer.adobe.com/uix/docs/services/aem-cf-console-admin/code-generation/#launch-code-generation-during-project-initialization )
> aio app init eaem-cf-page-references --template=@adobe/aem-cf-admin-ui-ext-tpl
13) For showing the selected content fragment page references in modal, add the following code in eaem-cf-page-references\aio-app\eaem-cf-page-references\src\aem-cf-console-admin-1\web-src\src\components\CFPageReferencesModal.js
import React, {useState, useEffect} from 'react'
import {attach} from "@adobe/uix-guest"
import {
defaultTheme,
Flex,
Provider,
Content,
Text,
ButtonGroup,
Button, Dialog, Divider
} from '@adobe/react-spectrum'
import {useParams} from "react-router-dom"
import {extensionId} from "./Constants"
export default function CFPageReferencesModal() {
const GET_REFERENCES_URL = "/apps/eaem-cf-page-references/components/cf-page-references/references.html";
const [guestConnection, setGuestConnection] = useState()
const [references, setReferences] = useState({});
const {fragmentId} = useParams()
if (!fragmentId) {
console.error("fragmentId parameter is missing")
return
}
useEffect(() => {
(async () => {
const guestConnection = await attach({id: extensionId})
setGuestConnection(guestConnection)
const sharedContext = guestConnection.sharedContext,
auth = sharedContext.get('auth');
const baseUrl = `https://${sharedContext.get('aemHost')}${GET_REFERENCES_URL}${fragmentId}`;
const requestOptions = {
method: 'GET',
headers: new Headers({
'Authorization': `Bearer ${auth['imsToken']}`,
})
};
const res = await fetch(baseUrl, requestOptions);
if (res.ok) {
setReferences(await res.json());
}
})()
})
const onCloseHandler = () => {
guestConnection.host.modal.close()
}
return (
<Provider theme={defaultTheme}>
<Content>
<Flex direction="column"gap="size-125">
{
Object.entries(references).map(([path, title]) => {
return <Text>
<div>{title}</div>
<div>
<a target="_blank"
href={`https://${guestConnection.sharedContext.get('aemHost')}/bin/wcmcommand?cmd=open&path=${path}`}>
{path}
</a>
</div>
</Text>
})
}
</Flex>
<Flex width="100%"justifyContent="end"alignItems="center"height="70px">
<ButtonGroup align="end">
<Button variant="primary"onClick={onCloseHandler}>Close</Button>
</ButtonGroup>
</Flex>
</Content>
</Provider>
)
}
14) Make sure you are in the app folder eg. eaem-cf-page-references\aio-app\eaem-cf-page-references and Run the App. Running first time, open app extension in a browser tab (eg. https://localhost:9080) and accept the unsafe message (its because we are using self signed certificates for local testing)
> aio app run
15) You should now be able to see the extension running locally by adding devMode=true&ext=https://localhost:9080 in the url...
https://experience.adobe.com/?devMode=true&ext=https://localhost:9080&repo=author-p10961-e880305.adobeaemcloud.com#/@2FBC7B975CFE21C40A495FBB@AdobeOrg/aem/cf/admin/
16) After some quick testing, we are now ready to deploy the extension to Stage Workgroup. Execute the following commands to make sure you are in the right project before deploying....
> aio where
> aio app deploy
17) To test it on stage, get the extension url from output above, eg. https://258616-eaemcfpagereferences-stage.adobeio-static.net/index.html and add it in the app url eg. devMode=true&ext=https://258616-eaemcfpagereferences-stage.adobeio-static.net/index.html
https://experience.adobe.com/?devMode=true&ext=https://258616-eaemcfpagereferences-stage.adobeio-static.net/index.html&repo=author-p10961-e880305.adobeaemcloud.com#/@2FBC7B975CFE21C40A495FBB@AdobeOrg/aem/cf/admin/
18) After some stage testing, deploy the app to Production Workgroup...
> aio app use -w Production
> aio app deploy
19) Access https://developer.adobe.com/, navigate to the project and submit app for Review and Approval
20) App in production...