A Freshworks Platform 3.0 React Meta sample app that lets agents pin colored sticky notes to tickets using Entity Storage, with a full-page Agent Huddle board for viewing and managing notes across tickets.
Agents often need lightweight, ticket-scoped reminders — shift handoffs, VIP flags, or follow-up context that is not a formal private note. Sticky Notes provides a post-it style sidebar on each ticket and a consolidated full-page board so the team can see pinned context at a glance.
- Pin a note on a ticket — pick a color, preview the card live, and save one sticky note per ticket in Entity Storage.
- Revisit and update — reopening the ticket sidebar loads the saved note for that ticket automatically.
- Browse the huddle board — the full-page app lists all pinned notes plus sample cards for demo; edit or delete with icon actions.
| Surface | Placement | Behavior |
|---|---|---|
app/ticketSidebar.html |
support_ticket.ticket_sidebar |
Color picker, live preview card, textarea, Pin it! / Update note |
app/index.html |
common.full_page_app |
Agent Huddle grid of pinned notes with edit/delete icons |
- Loads the sticky note saved for the current ticket (
client.data.get('ticket')). - Five color swatches: yellow, pink, green, blue, orange.
- Live preview card with pin and drop shadow.
- Creates a new note on first pin; subsequent saves update the same record.
- Toast feedback via
showNotify; iframe height adjusted withclient.instance.resize().
- Fetches all notes from Entity Storage with pagination support.
- Always shows six sample sticky notes (tagged Sample) for demo; saved notes appear first.
- Each card has edit and delete icon buttons (bottom-right).
- Edit opens a modal with color picker and textarea; delete confirms before removal.
- Sample notes can be edited or hidden in-session (changes reset on refresh).
Notes are stored in the ticket_notes entity with filterable fields for efficient per-ticket queries.
| Operation | Method | Where used |
|---|---|---|
| Create | entity.create() |
Sidebar — first pin |
| Read | entity.getAll({ query }) |
Sidebar — load by ticket_id; board — fetch all |
| Update | entity.update(display_id, data) |
Sidebar — update note; board — edit modal |
| Delete | entity.delete(display_id) |
Board — delete modal |
Entity schema (config/entities.json):
{
"ticket_notes": {
"fields": [
{ "name": "ticket_id", "type": "text", "filterable": true, "required": true },
{ "name": "note_content", "type": "paragraph" },
{ "name": "note_color", "type": "text", "filterable": true }
]
}
}Query by ticket:
const entity = client.db.entity({ version: 'v1' });
const ticketNotes = entity.get('ticket_notes');
const result = await ticketNotes.getAll({
query: { ticket_id: String(ticketId) }
});const ticketData = await client.data.get('ticket');
const ticketId = String(ticketData.ticket.id);await client.interface.trigger('showNotify', {
type: 'success',
title: 'Sticky note',
message: 'Sticky note pinned to this ticket!'
});client.instance.resize({ height: '520px' });Built with metaConfig.framework: "react". UI uses Crayons React components:
| Component | Usage |
|---|---|
<FwTextarea> |
Note input in sidebar and edit modal |
<FwButton> |
Pin, update, refresh, modal actions |
<FwModal> |
Edit and delete confirmation on full-page board |
<FwSpinner> |
Loading states |
<FwIcon> |
Edit and delete icons on board cards |
├── app/
│ ├── index.html # Full-page Agent Huddle board
│ ├── ticketSidebar.html # Ticket sidebar surface
│ ├── public/icon.svg # React Meta app icon (required path)
│ ├── components/
│ │ ├── index.jsx # Full-page React entry
│ │ ├── FullPageApp.jsx # Notes grid, modals, sample merge
│ │ ├── bootstrap/crayonsInit.js
│ │ ├── lib/
│ │ │ ├── noteColors.js # Five color tokens
│ │ │ ├── notesService.js # Entity Storage CRUD helpers
│ │ │ └── sampleNotes.js # Demo cards for full-page board
│ │ ├── ui/
│ │ │ ├── StickyNoteCard.jsx # Pinned post-it card + pin
│ │ │ └── ColorPicker.jsx # Sidebar color swatches
│ │ └── placeholders/
│ │ ├── ticketSidebar.jsx # Sidebar React entry
│ │ ├── TicketSidebarApp.jsx
│ │ └── PlaceholderWrapper.jsx
│ └── styles/style.css
├── config/
│ └── entities.json # Entity Storage schema
├── tests/
│ └── app.test.js # Vitest — colors, notes service, samples
├── manifest.json # React Meta + full_page_app + ticket_sidebar
├── package.json
└── vitest.config.js
- Freshworks CLI (FDK) v10.1.2 or later
- Node.js v24.x
- A Freshdesk trial account
-
Clone the repository:
git clone <repo-url> cd sticky-notes
-
Install dependencies and validate:
npm install fdk validate
-
Run the app locally:
fdk run
-
Open Freshdesk with
?dev=true:https://your-domain.freshdesk.com/a/tickets/1?dev=true -
Test both surfaces:
- Ticket sidebar — open a ticket, pin a colored note.
- Full-page app — Admin → Agent Huddle (or your configured full-page location).
npm testFDK simulates Entity Storage locally in .fdk/store.sqlite. Reset after schema changes or a clean slate:
rm .fdk/store.sqlite
fdk run- Entity Storage vs key-value — filterable
ticket_idenables efficient per-ticket queries without scanning all records. - React Meta icons — place
icon.svgunderapp/public/; FDK resolves manifest"icon": "icon.svg"from there. - One note per ticket in sidebar — load with
getAll({ query: { ticket_id } })and update viadisplay_idon save. - Full-page sample data — demo cards live in
sampleNotes.jsand merge with saved records for a populated board on first run.
