diff --git a/README.md b/README.md index d2c4c15..f0afc8e 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Community examples, open to everyone. This is the section external contributions | --- | --- | --- | | [`expense-policy-agent-skill`](examples/expense-policy-agent-skill) | A markdown skill that teaches an agent to answer expense policy questions and escalate anything it cannot verify. | Agent Skill | | [`employee-data-orchestration`](examples/employee-data-orchestration) | An orchestration that reads worker data from one tenant and creates matching records through the Workday REST API. | Orchestration | +| [`peer-kudos-home-card`](examples/peer-kudos-home-card) | An Extend app with a Home page card, custom business object, and orchestration that lets employees celebrate peer contributions and notifies managers. | Extend App | | [`pto-policy-agent-skill`](examples/pto-policy-agent-skill) | A markdown skill that teaches an agent to answer employee questions about PTO, leave accrual, rollover, and sick leave policy with clear escalation rules. | Agent Skill | | [`stock-notifications`](examples/stock-notifications) | An Extend app that fetches Workday's current stock price from an external API and displays it on a home page card. | Extend App | | [`wql-anniversary-celebrations`](examples/wql-anniversary-celebrations) | An orchestration that queries Workday via WQL for active workers celebrating milestone work anniversaries and formats an announcement digest payload for collaboration channels. | Orchestration | diff --git a/examples/peer-kudos-home-card/README.md b/examples/peer-kudos-home-card/README.md new file mode 100644 index 0000000..31d2d54 --- /dev/null +++ b/examples/peer-kudos-home-card/README.md @@ -0,0 +1,36 @@ +# Peer Kudos & Recognition Card + +## What it is + +An Extend application that brings employee recognition directly to the Workday homepage. The solution features an interactive Home Page Card (`kudosSpotlight`) displaying recent team shoutouts, a Presentation Page (`sendKudos.pmd`) where employees can submit kudos tied to core company values, a custom Business Object (`PeerKudos`) to store submissions, and an Orchestration flow (`KudosNotification`) to prepare notification summaries for managers. + +## What's inside + +- `appManifest.json`: Application configuration defining the app metadata, reference ID, and version. +- `cards/kudosSpotlight.carddefinition`: The Home page card definition providing quick visibility and direct launch actions into the recognition flow. +- `presentation/peerKudos.amd`: Application Metadata Definition registering the home and send kudos tasks and navigation routes. +- `presentation/peerKudos.smd`: Site Metadata Definition configuring site authentication and supported languages. +- `presentation/home.pmd`: Team recognition landing page displaying recent shoutouts. +- `presentation/sendKudos.pmd`: Interactive form for selecting a peer, choosing a value badge, writing an appreciation note, and submitting. +- `model/PeerKudos.businessobject`: Custom business object schema storing recipient, sender, badge type, message, and timestamp. +- `model/KudosSecurityDomain.securitydomain`: Security domain definition controlling access permissions for pages and orchestrations. +- `orchestration/KudosNotification.orchestration`: Orchestrate workflow triggered on submission that queries recent kudos entries and formats manager notifications with full error-handling scaffolding. +- `sample-data/sample-kudos-entry.json`: Fictional JSON response illustrating stored peer kudos records. +- `example.json`: Metadata file used by the Workday Developer Program gallery. + +## How to use it + +1. Deploy the app source to your Workday Cloud Platform (WCP) development tenant using App Builder, the Workday CLI (WDCLI), or Local Disk Sync. +2. Configure or map the `KudosSecurityDomain` to your target security groups (e.g., All Employees) so users can view the card and submit kudos. +3. Import `orchestration/KudosNotification.orchestration` into Workday Orchestration Builder and deploy it to your tenant. +4. Add the `kudosSpotlight` card to your default Home page configuration in Workday Home Settings. +5. Open Workday; the card appears on the desktop and mobile homepage ready for team members to share recognition. + +## Before you deploy + +Before deploying this example to your target tenant, verify the following configuration points: + +- **App reference id**: `peerKudos` in `appManifest.json`, `presentation/peerKudos.amd`, and `presentation/peerKudos.smd` is the sample app reference ID. When deploying to your tenant, replace it with the app reference ID generated for your application, or reference it dynamically using `site.applicationId` in scripts and PMD expressions. +- **Security domains**: Map `KudosSecurityDomain` in `model/KudosSecurityDomain.securitydomain` to your organization's security groups (e.g., Employee Self-Service / All Workers) to grant create and view permissions. +- **Base URLs**: Endpoints in `sendKudos.pmd` use `baseUrlType: "workday-apps"` to resolve your tenant's API host automatically without hardcoding tenant URLs. +- **Manager Notifications**: In `orchestration/KudosNotification.orchestration`, update the notification recipient mapping to route to your organization's communication channel (such as Slack, Microsoft Teams, or Workday Notifications) as needed. diff --git a/examples/peer-kudos-home-card/appManifest.json b/examples/peer-kudos-home-card/appManifest.json new file mode 100644 index 0000000..c02a462 --- /dev/null +++ b/examples/peer-kudos-home-card/appManifest.json @@ -0,0 +1,8 @@ +{ + "id": "7b5037e444f4f3f37ac1d53d4a63b389", + "referenceId": "peerKudos", + "name": "PeerKudos", + "description": "Peer Kudos and Recognition Home Card and Micro-App", + "latestVersion": "fbb00627e15388b48397b7c8974414f5", + "organizationId": "9ff68ed1-68e4-4225-9f3d-68dbf554c38b" +} diff --git a/examples/peer-kudos-home-card/cards/kudosSpotlight.carddefinition b/examples/peer-kudos-home-card/cards/kudosSpotlight.carddefinition new file mode 100644 index 0000000..1039a5f --- /dev/null +++ b/examples/peer-kudos-home-card/cards/kudosSpotlight.carddefinition @@ -0,0 +1,16 @@ +{ + "id": "kudosSpotlight", + "presentation": { + "type": "inlineCard", + "header": { + "type": "cardHeader", + "title": "Team Kudos Spotlight", + "subtitle": "Recognize your peers", + "icon": "wd-accent-star" + }, + "body": { + "type": "simpleCard", + "value": "Celebrate your colleagues' achievements and send instant appreciation across your team." + } + } +} diff --git a/examples/peer-kudos-home-card/example.json b/examples/peer-kudos-home-card/example.json new file mode 100644 index 0000000..6cb7168 --- /dev/null +++ b/examples/peer-kudos-home-card/example.json @@ -0,0 +1,21 @@ +{ + "title": "Peer Kudos & Recognition Card", + "description": "An Extend app with a Home page card, custom business object, and orchestration that lets employees celebrate peer contributions and notifies managers.", + "type": "Extend App", + "components": [ + "Presentation", + "Card", + "Model", + "Orchestration" + ], + "products": [ + "Workday Extend", + "Workday Orchestrate", + "Workday HCM" + ], + "authors": [ + "srivilliamsai" + ], + "tutorial": "", + "source": "community" +} diff --git a/examples/peer-kudos-home-card/model/KudosSecurityDomain.securitydomain b/examples/peer-kudos-home-card/model/KudosSecurityDomain.securitydomain new file mode 100644 index 0000000..c1afbdf --- /dev/null +++ b/examples/peer-kudos-home-card/model/KudosSecurityDomain.securitydomain @@ -0,0 +1,6 @@ +{ + "id": 1, + "name": "KudosSecurityDomain", + "enabledForPageSecurity": true, + "enabledForOrchestrationSecurity": true +} diff --git a/examples/peer-kudos-home-card/model/PeerKudos.businessobject b/examples/peer-kudos-home-card/model/PeerKudos.businessobject new file mode 100644 index 0000000..1a49a37 --- /dev/null +++ b/examples/peer-kudos-home-card/model/PeerKudos.businessobject @@ -0,0 +1,64 @@ +{ + "id": 1, + "name": "PeerKudos", + "label": "Peer Kudos", + "defaultSecurityDomains": [ + "KudosSecurityDomain" + ], + "defaultCollection": { + "name": "peerKudoses", + "label": "Peer Kudoses" + }, + "fields": [ + { + "id": 1, + "name": "recipientWorker", + "type": "TEXT", + "isReferenceId": false, + "useForDisplay": true, + "isPurgeable": false, + "enableIndex": false, + "enableSearch": false + }, + { + "id": 2, + "name": "senderWorker", + "type": "TEXT", + "isReferenceId": false, + "useForDisplay": false, + "isPurgeable": false, + "enableIndex": false, + "enableSearch": false + }, + { + "id": 3, + "name": "badgeType", + "type": "TEXT", + "isReferenceId": false, + "useForDisplay": false, + "isPurgeable": false, + "enableIndex": false, + "enableSearch": false + }, + { + "id": 4, + "name": "kudosMessage", + "type": "TEXT", + "isReferenceId": false, + "useForDisplay": false, + "isPurgeable": false, + "enableIndex": false, + "enableSearch": false + }, + { + "id": 5, + "name": "createdMoment", + "type": "TEXT", + "isReferenceId": false, + "useForDisplay": false, + "isPurgeable": false, + "enableIndex": false, + "enableSearch": false + } + ] +} diff --git a/examples/peer-kudos-home-card/orchestration/KudosNotification.orchestration b/examples/peer-kudos-home-card/orchestration/KudosNotification.orchestration new file mode 100644 index 0000000..daa4893 --- /dev/null +++ b/examples/peer-kudos-home-card/orchestration/KudosNotification.orchestration @@ -0,0 +1 @@ +{"flowVersion":"3.2.0","_type":"Flow","_value":{"id":{"_type":"String","_value":"8c61a4917a2f46bf82b3288c65759e2b"},"name":{"_type":"Identifier","_value":"KudosNotification"},"type":{"_type":"FlowType","_value":".maya.FlowSync"},"start":{"_type":"StartBasic","_value":{"structuredRequest":{"_type":["Opt","RequestStructure"],"_value":null},"hasMultipartData":{"_type":"Boolean","_value":false},"mcpToolConfig":{"_type":["Opt","MCPToolInputConfig"],"_value":null},"notes":{"_type":["List","Note"],"_value":[]}}},"end":{"_type":"EndSync","_value":{"headers":{"_type":["List","Header"],"_value":[]},"body":{"_type":["Opt","DataRefBody"],"_value":{"_type":"DataRefBody","_value":{"dataRef":{"_type":["Expr","Data"],"_value":{"type":{"_type":"Type","_value":"Data"},"source":{"_type":"String","_value":"data(\"FormatResponse\", \"message\")"},"isAuto":{"_type":"Boolean","_value":false}}},"contentType":{"_type":["Opt","String"],"_value":{"_type":"String","_value":"application/json"}}}}},"mcpToolConfig":{"_type":["Opt","MCPToolOutputConfig"],"_value":null},"notes":{"_type":["List","Note"],"_value":[{"_type":"Note","_value":{"key":{"_type":"String","_value":"description"},"value":{"_type":"String","_value":"Sync kudos notification status"}}}]}}},"nodes":{"_type":["List","Node"],"_value":[{"_type":"CreateValues","_value":{"name":{"_type":"Identifier","_value":"ParseKudosPayload"},"isDisabled":{"_type":"Boolean","_value":false},"errorHandler":{"_type":["Opt","ErrorHandler"],"_value":null},"values":{"_type":["List","Assignment"],"_value":[{"_type":"Assignment","_value":{"param":{"_type":"Parameter","_value":{"name":{"_type":"Identifier","_value":"recipientName"},"type":{"_type":"Type","_value":"String"},"default":{"_type":["Opt","Any"],"_value":null}}},"expr":{"_type":["Expr","String"],"_value":{"type":{"_type":"Type","_value":"String"},"source":{"_type":"String","_value":"data(\"start\", \"request\").asJSON().stringAtJsonPathWithDefault(\"$.recipientWorker\", \"Teammate\")"},"isAuto":{"_type":"Boolean","_value":false}}}}},{"_type":"Assignment","_value":{"param":{"_type":"Parameter","_value":{"name":{"_type":"Identifier","_value":"badgeType"},"type":{"_type":"Type","_value":"String"},"default":{"_type":["Opt","Any"],"_value":null}}},"expr":{"_type":["Expr","String"],"_value":{"type":{"_type":"Type","_value":"String"},"source":{"_type":"String","_value":"data(\"start\", \"request\").asJSON().stringAtJsonPathWithDefault(\"$.badgeType\", \"Master Collaborator\")"},"isAuto":{"_type":"Boolean","_value":false}}}}}]},"notes":{"_type":["List","Note"],"_value":[{"_type":"Note","_value":{"key":{"_type":"String","_value":"description"},"value":{"_type":"String","_value":"Extract recipient and badge attributes"}}}]}}},{"_type":"SendWorkdayApiRequest","_value":{"name":{"_type":"Identifier","_value":"GetKudosEntries"},"isDisabled":{"_type":"Boolean","_value":false},"errorHandler":{"_type":["Opt","ErrorHandler"],"_value":{"_type":"ErrorHandler","_value":{"name":{"_type":"Identifier","_value":"_localErrorHandler_GetKudosEntries"},"isDisabled":{"_type":"Boolean","_value":false},"strategy":{"_type":"ErrorHandlerStrategy","_value":"PropagateError"},"nodes":{"_type":["List","Node"],"_value":[{"_type":"Log","_value":{"name":{"_type":"Identifier","_value":"LogApiError"},"isDisabled":{"_type":"Boolean","_value":false},"errorHandler":{"_type":["Opt","ErrorHandler"],"_value":null},"message":{"_type":["Expr","String"],"_value":{"type":{"_type":"Type","_value":"String"},"source":{"_type":"String","_value":"s\"\"\"${\"Failed to query Kudos entries: \"}${data(\"GetKudosEntries\", \"processingError\").message()}\"\"\""},"isAuto":{"_type":"Boolean","_value":false}}},"condition":{"_type":["Expr","Boolean"],"_value":{"type":{"_type":"Type","_value":"Boolean"},"source":{"_type":"String","_value":"true"},"isAuto":{"_type":"Boolean","_value":false}}},"notes":{"_type":["List","Note"],"_value":[]}}}]},"notes":{"_type":["List","Note"],"_value":[]}}}},"body":{"_type":["Opt","HttpBody"],"_value":null},"path":{"_type":["Expr","String"],"_value":{"type":{"_type":"Type","_value":"String"},"source":{"_type":"String","_value":"\"apps/peerkudos_app/v1/peerKudoses?limit=10\""},"isAuto":{"_type":"Boolean","_value":false}}},"queryParams":{"_type":["List","QueryParam"],"_value":[]},"method":{"_type":"HttpMethod","_value":"GET"},"headers":{"_type":["List","Header"],"_value":[]},"auth":{"_type":"WorkdayCredentialRef","_value":{"resourceName":{"_type":"String","_value":"_DEFAULT_WORKDAY_CREDENTIAL"}}},"isChunked":{"_type":"Boolean","_value":false},"connectTimeoutMs":{"_type":"Long","_value":10000},"responseTimeoutMs":{"_type":"Long","_value":20000},"overallTimeoutMs":{"_type":"Long","_value":300000},"retryConfigRef":{"_type":"RetryConfigRef","_value":"_DEFAULT_WORKDAY_RETRY_CONFIG"},"tlsConfig":{"_type":["Opt","TlsConfig"],"_value":null},"proxyConfig":{"_type":["Opt","ProxyConfig"],"_value":null},"responseType":{"_type":"HttpResponseType","_value":"Json"},"longRunningRequest":{"_type":"Boolean","_value":false},"notes":{"_type":["List","Note"],"_value":[{"_type":"Note","_value":{"key":{"_type":"String","_value":"description"},"value":{"_type":"String","_value":"Fetch recent kudos entries from custom business object"}}}]}}},{"_type":"CreateTextTemplate","_value":{"name":{"_type":"Identifier","_value":"FormatResponse"},"isDisabled":{"_type":"Boolean","_value":false},"errorHandler":{"_type":["Opt","ErrorHandler"],"_value":null},"message":{"_type":"TextTemplate","_value":"{\n \"status\": \"success\",\n \"notificationSent\": true,\n \"recipient\": \"{{data(\"ParseKudosPayload\", \"recipientName\")}}\",\n \"badge\": \"{{data(\"ParseKudosPayload\", \"badgeType\")}}\",\n \"message\": \"Kudos recorded and manager notification digest prepared.\"\n}"},"contentType":{"_type":"String","_value":"application/json"},"formatRef":{"_type":["Opt","TextFormatRef"],"_value":null},"notes":{"_type":["List","Note"],"_value":[{"_type":"Note","_value":{"key":{"_type":"String","_value":"description"},"value":{"_type":"String","_value":"Format outbound JSON notification response"}}}]}}}]},"notes":{"_type":["List","Note"],"_value":[]},"resources":{"_type":"ResourceProvider","_value":{"fileLikeResources":{"_type":["Map","Resource"],"_value":{}},"credentials":{"_type":["Map","Credential"],"_value":{}},"xmlNamespaces":{"_type":["Map","String"],"_value":{}},"retryConfigs":{"_type":["Map",["WithNotes","RetryConfig"]],"_value":{}},"csvFormats":{"_type":["Map","CsvFormat"],"_value":{}},"pollingConfigs":{"_type":["Map","PollingConfig"],"_value":{}}}},"defaultWorkdayCredentialRef":{"_type":["Opt","AccessTokenFromInitiatingUser"],"_value":{"_type":"AccessTokenFromInitiatingUser","_value":"AccessTokenFromInitiatingUser"}},"mayaVersion":{"_type":"String","_value":"1.4072.0"},"errorHandler":{"_type":["Opt","ErrorHandler"],"_value":{"_type":"ErrorHandler","_value":{"name":{"_type":"Identifier","_value":"_globalErrorHandler_Kudos"},"strategy":{"_type":"ErrorHandlerStrategy","_value":"GlobalErrorHandler"},"nodes":{"_type":["List","Node"],"_value":[{"_type":"Log","_value":{"name":{"_type":"Identifier","_value":"LogGlobalKudosError"},"errorHandler":{"_type":["Opt","ErrorHandler"],"_value":null},"message":{"_type":["Expr","String"],"_value":{"type":{"_type":"Type","_value":"String"},"source":{"_type":"String","_value":"s\"\"\"${\"Uncaught error in KudosNotification orchestration: \"}${data(\"_orchestration\",\"processingError\").message()}\"\"\""}}},"notes":{"_type":["List","Note"],"_value":[{"_type":"Note","_value":{"key":{"_type":"String","_value":"description"},"value":{"_type":"String","_value":"Log uncaught exceptions"}}}]}}}]},"notes":{"_type":["List","Note"],"_value":[]}}}},"cancelBarrier":{"_type":["Opt","Identifier"],"_value":null},"defaultLocale":{"_type":"Locale","_value":{"value":{"_type":["Expr","String"],"_value":{"type":{"_type":"Type","_value":"String"},"source":{"_type":"String","_value":"\"en_US\""},"isAuto":{"_type":"Boolean","_value":false}}}}},"securityDomains":{"_type":["Opt",["List","String"]],"_value":["KudosSecurityDomain"]}}} diff --git a/examples/peer-kudos-home-card/presentation/home.pmd b/examples/peer-kudos-home-card/presentation/home.pmd new file mode 100644 index 0000000..eefe747 --- /dev/null +++ b/examples/peer-kudos-home-card/presentation/home.pmd @@ -0,0 +1,35 @@ +{ + "id": "home", + "securityDomains": [ + "KudosSecurityDomain" + ], + "presentation": { + "headerSize": "VPS_DEFAULT", + "title": { + "type": "title", + "id": "pageTitle", + "label": "Team Kudos & Recognition" + }, + "body": { + "type": "section", + "id": "mainSection", + "children": [ + { + "type": "text", + "id": "introText", + "value": "Welcome to Peer Kudos! Celebrate your teammates' daily wins and company value alignment." + }, + { + "type": "button", + "id": "giveKudosButton", + "action": "PRIMARY", + "label": "Give Kudos", + "taskReference": { + "type": "taskReference", + "taskId": "sendKudos" + } + } + ] + } + } +} diff --git a/examples/peer-kudos-home-card/presentation/peerKudos.amd b/examples/peer-kudos-home-card/presentation/peerKudos.amd new file mode 100644 index 0000000..ef1a2c4 --- /dev/null +++ b/examples/peer-kudos-home-card/presentation/peerKudos.amd @@ -0,0 +1,20 @@ +{ + "appProperties": [], + "tasks": [ + { + "id": "home", + "routingPattern": "/", + "page": { + "id": "home" + } + }, + { + "id": "sendKudos", + "routingPattern": "/sendKudos", + "page": { + "id": "sendKudos" + } + } + ], + "applicationId": "peerKudos" +} diff --git a/examples/peer-kudos-home-card/presentation/peerKudos.smd b/examples/peer-kudos-home-card/presentation/peerKudos.smd new file mode 100644 index 0000000..c198a69 --- /dev/null +++ b/examples/peer-kudos-home-card/presentation/peerKudos.smd @@ -0,0 +1,19 @@ +{ + "id": "peerKudos", + "applicationId": "peerKudos", + "siteId": "peerKudos", + "languages": [ + { + "code": "en-US", + "description": "English" + } + ], + "siteAuth": { + "authTypes": [ + { + "scheme": "SSO", + "id": "sso" + } + ] + } +} diff --git a/examples/peer-kudos-home-card/presentation/sendKudos.pmd b/examples/peer-kudos-home-card/presentation/sendKudos.pmd new file mode 100644 index 0000000..a8076ba --- /dev/null +++ b/examples/peer-kudos-home-card/presentation/sendKudos.pmd @@ -0,0 +1,95 @@ +{ + "id": "sendKudos", + "securityDomains": [ + "KudosSecurityDomain" + ], + "outboundData": { + "outboundEndPoints": [ + { + "name": "kudosOutbound", + "baseUrlType": "workday-apps", + "url": "<% `/apps/{{site.applicationId}}/v1/peerKudoses` %>", + "httpMethod": "POST", + "authType": "sso", + "failOnStatusCodes": [ + { + "code": 400 + }, + { + "code": 403 + } + ] + } + ] + }, + "presentation": { + "headerSize": "VPS_DEFAULT", + "title": { + "type": "title", + "id": "sendKudosTitle", + "label": "Send Peer Kudos" + }, + "body": { + "type": "section", + "id": "formSection", + "children": [ + { + "type": "text", + "id": "formIntro", + "value": "Recognize a colleague for living our core team values." + }, + { + "type": "textInput", + "id": "recipientInput", + "label": "Recipient Colleague Name", + "valueOutBinding": "kudosOutbound.recipientWorker", + "required": true + }, + { + "type": "dropdown", + "id": "badgeDropdown", + "label": "Kudos Badge", + "valueOutBinding": "kudosOutbound.badgeType", + "required": true, + "values": [ + { + "id": "val1", + "value": "Customer Hero" + }, + { + "id": "val2", + "value": "Velocity Champion" + }, + { + "id": "val3", + "value": "Master Collaborator" + }, + { + "id": "val4", + "value": "Innovation Driver" + } + ] + }, + { + "type": "textArea", + "id": "messageInput", + "label": "Appreciation Note", + "valueOutBinding": "kudosOutbound.kudosMessage", + "required": true + } + ] + }, + "footer": { + "type": "footer", + "id": "pageFooter", + "children": [ + { + "type": "button", + "id": "submitButton", + "action": "PRIMARY", + "label": "Submit Kudos" + } + ] + } + } +} diff --git a/examples/peer-kudos-home-card/sample-data/sample-kudos-entry.json b/examples/peer-kudos-home-card/sample-data/sample-kudos-entry.json new file mode 100644 index 0000000..e709420 --- /dev/null +++ b/examples/peer-kudos-home-card/sample-data/sample-kudos-entry.json @@ -0,0 +1,29 @@ +{ + "total": 3, + "data": [ + { + "id": "1", + "recipientWorker": "Alex Morgan", + "senderWorker": "Jordan Lee", + "badgeType": "Customer Hero", + "kudosMessage": "Huge thank you for stepping in to resolve the tenant configuration issue for our European launch!", + "createdMoment": "2026-09-18T10:15:00Z" + }, + { + "id": "2", + "recipientWorker": "Samira Patel", + "senderWorker": "Taylor Chen", + "badgeType": "Velocity Champion", + "kudosMessage": "Incredible velocity delivering the new design system components ahead of schedule.", + "createdMoment": "2026-09-19T14:30:00Z" + }, + { + "id": "3", + "recipientWorker": "Devon Reed", + "senderWorker": "Alex Morgan", + "badgeType": "Master Collaborator", + "kudosMessage": "Thank you for facilitating the cross-functional alignment workshop with our product managers.", + "createdMoment": "2026-09-20T09:00:00Z" + } + ] +}