AEM Cloud Service - AEM Experience UI Content Fragments App Extension Show Page References


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

1) Create a maven project for Server Side Code to get  Page References...
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) Org Administrator can now Review the app and Approve by accessing https://exchange.adobe.com/Manage Experience Cloud Applications...



21) The extension is now available for all AEM Cloud Instances in the org...



22) Publishing the app to Extension Registry will make the extension available to all AEM instances in the Org, to make it available for specific instances, use Extension Manager https://developer.adobe.com/uix/docs/extension-manager/


No comments:

Post a Comment