Files
gh-secondsky-sap-skills-ski…/references/api-calendar-bookmarks.md
2025-11-30 08:55:33 +08:00

604 lines
14 KiB
Markdown

# Calendar, Bookmarks & Advanced Integration API Reference
Complete reference for Calendar integration, Bookmarks, Linked Analysis, and Timer APIs in SAP Analytics Cloud.
**Source**: [Analytics Designer API Reference 2025.14](https://help.sap.com/doc/958d4c11261f42e992e8d01a4c0dde25/release/en-US/index.html)
---
## Table of Contents
1. [Calendar Integration API](#calendar-integration-api)
2. [Bookmarks API](#bookmarks-api)
3. [Linked Analysis API](#linked-analysis-api)
4. [Timer API](#timer-api)
5. [Notification Badges](#notification-badges)
---
## Calendar Integration API
SAC Calendar allows integration with planning workflows, tasks, and processes.
### Getting Calendar Events
#### getCalendarEventById(eventId)
Retrieves an existing calendar event by ID.
```javascript
var event = Calendar.getCalendarEventById("EVENT_ID_STRING");
```
**Note**: The ID is a unique string (like a story/model ID), not the display name.
#### getCurrentEvent()
Returns the event from which the application was started.
```javascript
var currentEvent = Calendar.getCurrentEvent();
if (currentEvent) {
console.log("Started from event:", currentEvent.getName());
}
```
### Calendar Event Methods
Once you have an event reference, these methods are available:
| Method | Description |
|--------|-------------|
| `getId()` | Returns event unique ID |
| `getName()` | Returns event display name |
| `getDescription()` | Returns event description |
| `getStartDate()` | Returns start date |
| `getDueDate()` | Returns due date |
| `getStatus()` | Returns current status |
| `getType()` | Returns event type |
| `getProgress()` | Returns completion percentage |
| `hasUserRole(role)` | Checks if user has specific role |
| `activate()` | Activates the event |
### Calendar Composite Task
For composite tasks (multi-step workflows):
#### CalendarCompositeTask Methods
```javascript
// Approval workflow
task.approve(); // Approve task (requires Reviewer role)
task.reject(); // Reject task
task.submit(); // Submit for review
task.decline(); // Decline task
// Check permissions
task.canUserApprove();
task.canUserReject();
task.canUserSubmit();
task.canUserDecline();
// Reviewer management
task.addReviewer(userId);
task.removeReviewer(userId);
```
### Creating Calendar Events
#### Create Process
```javascript
var processProperties = {
name: "Q4 Planning",
startDate: new Date(2024, 9, 1), // October 1, 2024
endDate: new Date(2024, 11, 31), // December 31, 2024
description: "Q4 Budget Planning Process",
owners: ["user1@company.com"],
assignees: ["user2@company.com", "user3@company.com"]
};
var newProcess = Calendar.createProcess(processProperties);
```
#### Create Task
```javascript
var taskProperties = {
name: "Review Budget",
startDate: new Date(2024, 10, 1),
dueDate: new Date(2024, 10, 15),
description: "Review Q4 budget allocations",
assignees: ["reviewer@company.com"],
parentId: parentProcessId,
reminders: [
{ daysBeforeDue: 3 },
{ daysBeforeDue: 1 }
]
};
var newTask = Calendar.createTask(taskProperties);
```
### CalendarCompositeTaskCreateProperties
Full list of properties when creating tasks:
| Property | Type | Description |
|----------|------|-------------|
| name | string | Task name (required) |
| startDate | Date | Start date (required) |
| endDate | Date | End date (required) |
| dueDate | Date | Due date |
| description | string | Task description |
| owners | string[] | Owner user IDs |
| assignees | string[] | Assignee user IDs |
| reviewers | string[] | Reviewer user IDs |
| parentId | string | Parent process ID |
| dependencies | string[] | Dependent task IDs |
| contextFilters | object | Context filter settings |
| reminders | object[] | Reminder configurations |
| workFiles | string[] | Attached work file IDs |
### Calendar Event Status
```javascript
CalendarTaskStatus.Open // Not started
CalendarTaskStatus.InProgress // In progress
CalendarTaskStatus.Successful // Completed successfully
CalendarTaskStatus.Failed // Failed
CalendarTaskStatus.Canceled // Canceled
```
### Reminder Configuration
```javascript
// Add reminder to event
event.addReminder({
daysBeforeDue: 5,
notificationType: "Email"
});
```
### Bulk Operations Example
```javascript
// Bulk modify context filters on calendar events
function updateEventFilters(eventIds, newFilter) {
eventIds.forEach(function(eventId) {
var event = Calendar.getCalendarEventById(eventId);
if (event) {
event.setContextFilter("Year", newFilter);
}
});
}
```
---
## Bookmarks API
Bookmarks save application state for later restoration.
### What Bookmarks Save
- Dimension and measure selections in Tables/Charts
- Filter states
- Hierarchical levels
- Dropdown/Radio button/Checkbox selections
- Script Variables (primitive types: string, boolean, integer, number)
- Widget visibility states
- Sorting configurations
**Not Saved**: Non-primitive type script variables (complex objects)
### BookmarkSet Technical Object
Add a BookmarkSet technical object to enable bookmark functionality.
#### saveBookmark(options)
Saves current application state as a bookmark.
```javascript
BookmarkSet_1.saveBookmark({
name: "Q4 Analysis View",
isGlobal: true // false for personal bookmark
});
```
#### getAll()
Returns all available bookmarks.
```javascript
var bookmarks = BookmarkSet_1.getAll();
bookmarks.forEach(function(bookmark) {
console.log(bookmark.id + ": " + bookmark.name);
});
```
#### apply(bookmarkId)
Applies a saved bookmark.
```javascript
// Apply by ID
Bookmarks.apply("22305278-9717-4296-8809-298841349359");
// Or from bookmark info
var selectedBookmark = Dropdown_Bookmarks.getSelectedKey();
BookmarkSet_1.apply(selectedBookmark);
```
#### getAppliedBookmark()
Returns currently applied bookmark info.
```javascript
var currentBookmark = BookmarkSet_1.getAppliedBookmark();
if (currentBookmark) {
console.log("Current bookmark:", currentBookmark.name);
}
```
#### deleteBookmark(bookmarkInfo)
Deletes a bookmark.
```javascript
var bookmarkToDelete = BookmarkSet_1.getAppliedBookmark();
BookmarkSet_1.deleteBookmark(bookmarkToDelete);
```
### URL Parameters for Bookmarks
Bookmarks can be loaded via URL:
```
# Load specific bookmark
?bookmarkId=XXXXXXXXXXX
# Load default bookmark
?bookmarkId=DEFAULT
```
### Bookmark Dropdown Pattern
```javascript
// Populate dropdown with bookmarks
function populateBookmarkDropdown() {
var bookmarks = BookmarkSet_1.getAll();
var items = bookmarks.map(function(b) {
return { key: b.id, text: b.name };
});
Dropdown_Bookmarks.setItems(items);
}
// Apply selected bookmark
Dropdown_Bookmarks.onSelect = function() {
var bookmarkId = Dropdown_Bookmarks.getSelectedKey();
if (bookmarkId) {
BookmarkSet_1.apply(bookmarkId);
}
};
```
### Global vs Personal Bookmarks
| Type | Visibility | Use Case |
|------|-----------|----------|
| Personal | Only creator | Individual analysis views |
| Global | All viewers | Shared scenarios, published views |
---
## Linked Analysis API
Linked Analysis enables cross-widget filtering based on selections.
### In Analytics Applications
Linked Analysis must be implemented via scripting in Analytic Applications (unlike Stories where it's automatic).
### setFilters(selections)
Applies selection filters to linked widgets.
```javascript
// In Chart_1 onSelect event
var selections = Chart_1.getSelections();
if (selections.length > 0) {
// Set filters on linked widgets
LinkedAnalysis.setFilters(selections);
}
```
### removeFilters()
Removes linked analysis filters.
```javascript
LinkedAnalysis.removeFilters();
```
### Custom Linked Analysis Pattern
```javascript
// Create reusable linked analysis function
function applyLinkedAnalysis(sourceWidget, targetWidgets) {
var selections = sourceWidget.getSelections();
if (selections.length === 0) {
// Clear filters on all targets
targetWidgets.forEach(function(widget) {
widget.getDataSource().clearAllFilters();
});
return;
}
// Apply selection to all targets
var selection = selections[0];
targetWidgets.forEach(function(widget) {
var ds = widget.getDataSource();
Object.keys(selection).forEach(function(dimId) {
ds.setDimensionFilter(dimId, selection[dimId]);
});
});
}
// Usage in Chart_1.onSelect
applyLinkedAnalysis(Chart_1, [Table_1, Chart_2, Chart_3]);
```
### With Custom Widgets
Starting from QRC Q3 2023, Custom Widgets support Linked Analysis:
```javascript
// In custom widget code
this.dataBindings
.getDataBinding()
.getLinkedAnalysis()
.setFilters(selection);
// Remove filters
this.dataBindings
.getDataBinding()
.getLinkedAnalysis()
.removeFilters();
```
---
## Timer API
Timer enables scheduled script execution and animations.
### Timer Technical Object
Add a Timer from the Outline panel under Technical Objects.
### Timer Methods
```javascript
// Start timer (interval in milliseconds)
Timer_1.start(1000); // Every 1 second
// Stop timer
Timer_1.stop();
// Check if running
var isRunning = Timer_1.isRunning();
// Get interval
var interval = Timer_1.getInterval();
// Set interval
Timer_1.setInterval(2000); // Change to 2 seconds
```
### Timer Events
```javascript
// onTimeout - fires at each interval
Timer_1.onTimeout = function() {
// Update data or animations
refreshDashboard();
};
```
### Auto-Refresh Pattern
```javascript
// Auto-refresh dashboard every 30 seconds
Timer_Refresh.start(30000);
Timer_Refresh.onTimeout = function() {
Application.showBusyIndicator();
Chart_1.getDataSource().refreshData();
Table_1.getDataSource().refreshData();
Application.hideBusyIndicator();
// Update timestamp
Text_LastRefresh.setText(
"Last updated: " + new Date().toLocaleTimeString()
);
};
// Stop on user interaction
Button_Pause.onClick = function() {
if (Timer_Refresh.isRunning()) {
Timer_Refresh.stop();
Button_Pause.setText("Resume Auto-Refresh");
} else {
Timer_Refresh.start(30000);
Button_Pause.setText("Pause Auto-Refresh");
}
};
```
### Countdown Timer Pattern
```javascript
var countdown = 60; // 60 seconds
Timer_Countdown.start(1000); // 1 second intervals
Timer_Countdown.onTimeout = function() {
countdown--;
Text_Countdown.setText("Time remaining: " + countdown + "s");
if (countdown <= 0) {
Timer_Countdown.stop();
performAction();
}
};
```
### Animation Pattern
```javascript
var currentIndex = 0;
var dataPoints = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"];
Timer_Animation.start(2000); // 2 second intervals
Timer_Animation.onTimeout = function() {
// Highlight next data point
Chart_1.getDataSource().setDimensionFilter("Month", dataPoints[currentIndex]);
currentIndex++;
if (currentIndex >= dataPoints.length) {
currentIndex = 0; // Loop back
}
};
```
---
## Notification Badges
### Application Messages
```javascript
// Display notifications
Application.showMessage(ApplicationMessageType.Info, "Information message");
Application.showMessage(ApplicationMessageType.Success, "Success message");
Application.showMessage(ApplicationMessageType.Warning, "Warning message");
Application.showMessage(ApplicationMessageType.Error, "Error message");
```
### Custom Notification Pattern
```javascript
// Check for alerts and show notification
function checkAlerts() {
var data = Chart_1.getDataSource().getData({
"@MeasureDimension": "[Account].[parentId].&[Revenue]"
});
if (data.rawValue < 10000) {
Application.showMessage(
ApplicationMessageType.Warning,
"Revenue below threshold: " + data.formattedValue
);
// Open alert popup
Popup_Alert.open();
}
}
// Call on data change
Chart_1.onResultChanged = function() {
checkAlerts();
};
```
### Tooltip Patterns
Tooltips appear automatically on chart data points. For custom tooltips:
```javascript
// Use popup as custom tooltip
Chart_1.onSelect = function() {
var selections = Chart_1.getSelections();
if (selections.length > 0) {
// Get detailed data
var details = getDetailedInfo(selections[0]);
// Update tooltip content
Text_TooltipContent.setText(details);
// Position and show popup
Popup_Tooltip.open();
}
};
```
---
## Complete Example: Planning Workflow with Calendar
```javascript
// Initialize from calendar event
Application.onInitialization = function() {
var event = Calendar.getCurrentEvent();
if (event) {
// Set context from calendar event
var year = event.getContextFilter("Year");
var version = event.getContextFilter("Version");
if (year) {
Table_1.getDataSource().setDimensionFilter("Year", year);
}
if (version) {
Table_1.getDataSource().setDimensionFilter("Version", version);
}
// Update title
Text_Title.setText("Planning: " + event.getName());
// Show task info
Text_DueDate.setText("Due: " + event.getDueDate().toLocaleDateString());
}
};
// Submit task
Button_Submit.onClick = function() {
var event = Calendar.getCurrentEvent();
if (event && event.canUserSubmit()) {
// Save data first
Table_1.getPlanning().submitData();
// Submit for review
event.submit();
Application.showMessage(
ApplicationMessageType.Success,
"Task submitted for review"
);
} else {
Application.showMessage(
ApplicationMessageType.Warning,
"Cannot submit task"
);
}
};
```
---
## Related Documentation
- [DataSource API](api-datasource.md)
- [Widgets API](api-widgets.md)
- [Planning API](api-planning.md)
- [Application API](api-application.md)
**Official Reference**: [https://help.sap.com/doc/958d4c11261f42e992e8d01a4c0dde25/release/en-US/index.html](https://help.sap.com/doc/958d4c11261f42e992e8d01a4c0dde25/release/en-US/index.html)