Initial commit
This commit is contained in:
397
references/integration-and-migration.md
Normal file
397
references/integration-and-migration.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# SAP SAC Custom Widget Integration and Migration
|
||||
|
||||
Coverage of script integration, content transport, story compatibility, and planning features.
|
||||
|
||||
**Sources**:
|
||||
- [SAP Community - Content Transport](https://community.sap.com/t5/technology-blog-posts-by-members/sac-content-transport-migration-using-ctms/ba-p/13742318)
|
||||
- [Optimized Story Experience](https://community.sap.com/t5/technology-blog-posts-by-sap/the-new-optimized-story-experience-the-unification-of-story-and-analytic/ba-p/13558887)
|
||||
- [Analytics Designer API Reference](https://help.sap.com/doc/958d4c11261f42e992e8d01a4c0dde25/release/en-US/index.html)
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Script Integration](#script-integration)
|
||||
2. [Content Transport and Migration](#content-transport-and-migration)
|
||||
3. [Story Compatibility](#story-compatibility)
|
||||
4. [Planning Integration](#planning-integration)
|
||||
5. [API Methods Reference](#api-methods-reference)
|
||||
|
||||
---
|
||||
|
||||
## Script Integration
|
||||
|
||||
### Global Script Objects
|
||||
|
||||
Custom widgets can interact with SAC's global script objects.
|
||||
|
||||
**Script Object Structure**:
|
||||
- Script objects act as containers for reusable functions
|
||||
- Functions not tied to events, invoked directly
|
||||
- Accessible from all scripts in the story
|
||||
|
||||
**Invoking Script Functions**:
|
||||
```javascript
|
||||
// In SAC script
|
||||
ScriptObjectName.ScriptFunctionName();
|
||||
|
||||
// Example
|
||||
Utils.formatCurrency(1000, "USD"); // Returns "$1,000.00"
|
||||
```
|
||||
|
||||
### Script Variables
|
||||
|
||||
**Global Variables**:
|
||||
- Defined at story level
|
||||
- Accessible from all script blocks
|
||||
- Can receive values from URL parameters
|
||||
|
||||
**Using with Custom Widgets**:
|
||||
```javascript
|
||||
// In SAC script
|
||||
var myValue = GlobalVariable_1;
|
||||
CustomWidget_1.setValue(myValue);
|
||||
|
||||
// Widget method receives value
|
||||
class MyWidget extends HTMLElement {
|
||||
setValue(val) {
|
||||
this._props.value = val;
|
||||
this._render();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Script Object Integration Pattern
|
||||
|
||||
```javascript
|
||||
// Custom widget firing events for script handling
|
||||
class MyWidget extends HTMLElement {
|
||||
_handleUserAction(data) {
|
||||
// Fire event that SAC script can handle
|
||||
this.dispatchEvent(new CustomEvent("onUserAction", {
|
||||
detail: { actionData: data }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// In SAC script (event handler)
|
||||
CustomWidget_1.onUserAction = function() {
|
||||
var eventData = CustomWidget_1.getEventInfo();
|
||||
// Process event, call other script objects
|
||||
DataProcessor.handleAction(eventData.actionData);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Content Transport and Migration
|
||||
|
||||
### Transport Methods
|
||||
|
||||
**1. Content Network (Same Region)**
|
||||
- Source and destination on same region
|
||||
- Same or +1 quarterly version
|
||||
- Access: Main Menu > Transport > Export/Import > Content Network Storage
|
||||
|
||||
**2. Import/Export (Any Region)**
|
||||
- No region restriction
|
||||
- Version constraints apply
|
||||
- More flexible but manual
|
||||
|
||||
### Custom Widget Transport
|
||||
|
||||
**Supported Scenarios**:
|
||||
- Cloud Foundry to Cloud Foundry tenants
|
||||
- Same hosting configuration required
|
||||
|
||||
**Not Supported**:
|
||||
- Cloud Foundry to Neo platform
|
||||
- Different hosting configurations may cause issues
|
||||
|
||||
### Common Transport Issue
|
||||
|
||||
**Error**: "The system couldn't load the custom widget"
|
||||
|
||||
**Causes**:
|
||||
- Widget JSON transported but resource files not accessible
|
||||
- Different hosting URLs between source/target
|
||||
- Integrity hash mismatch after transport
|
||||
|
||||
**Solution**:
|
||||
```json
|
||||
// Ensure resource URLs are accessible from target tenant
|
||||
{
|
||||
"webcomponents": [
|
||||
{
|
||||
"kind": "main",
|
||||
"tag": "my-widget",
|
||||
"url": "[https://globally-accessible-host.com/widget.js",](https://globally-accessible-host.com/widget.js",)
|
||||
"integrity": "sha256-...",
|
||||
"ignoreIntegrity": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Transport Best Practices
|
||||
|
||||
1. **Use globally accessible hosting** (GitHub Pages, CDN, SAC-hosted)
|
||||
2. **Verify URLs before transport** - Ensure target can reach resource files
|
||||
3. **Re-upload JSON** if hosting changes - Update URLs post-transport
|
||||
4. **Test in target** before production use
|
||||
|
||||
### CTMS Integration
|
||||
|
||||
Cloud Transport Management Service (CTMS) provides automated transport:
|
||||
|
||||
1. Integrate CTMS with SAC
|
||||
2. Define transport routes
|
||||
3. Upload packages via SAC interface
|
||||
4. CTMS handles deployment to destination
|
||||
|
||||
**Limitation**: CTMS is basic - no destination location selection like native Content Network.
|
||||
|
||||
---
|
||||
|
||||
## Story Compatibility
|
||||
|
||||
### Story Types
|
||||
|
||||
| Type | Custom Widgets | Scripting | CSS/Themes |
|
||||
|------|----------------|-----------|------------|
|
||||
| Classic Story | Limited | No | Limited |
|
||||
| Optimized Story (Classic Responsive) | Yes | Limited | Limited |
|
||||
| Optimized Story (Advanced Responsive) | Full | Full | Full |
|
||||
|
||||
### Optimized Story Experience (QRC Q2 2023+)
|
||||
|
||||
**Advanced Responsive Layout** features:
|
||||
- Full custom widget support
|
||||
- Complete scripting capabilities
|
||||
- CSS and theme customization
|
||||
- Device preview
|
||||
- Data binding
|
||||
|
||||
### Classic Story Conversion
|
||||
|
||||
**Conversion Status Types**:
|
||||
|
||||
1. **Ready to convert** - No issues, direct conversion
|
||||
2. **Feature limitation** - Some features not supported in optimized
|
||||
3. **Blocked** - Issues must be resolved first
|
||||
|
||||
**Conversion Notes**:
|
||||
- Conversion is permanent
|
||||
- Save as copy recommended
|
||||
- Converted stories use Classic Responsive Layout initially
|
||||
|
||||
### Custom Widget Compatibility
|
||||
|
||||
**In Optimized Stories**:
|
||||
```json
|
||||
{
|
||||
"id": "com.company.widget",
|
||||
"dataBindings": {
|
||||
"myData": {
|
||||
"feeds": [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
- Full data binding support
|
||||
- Script integration
|
||||
- Builder/Styling panels
|
||||
|
||||
**In Classic Stories**:
|
||||
- Limited support
|
||||
- No data binding
|
||||
- Basic property configuration only
|
||||
|
||||
---
|
||||
|
||||
## Planning Integration
|
||||
|
||||
### ⚠️ Important Limitations
|
||||
|
||||
Before implementing planning widgets, review these constraints:
|
||||
|
||||
1. **Builder Panel + Data Binding Conflict**: Cannot combine custom Builder Panel with data binding in the same widget
|
||||
2. **Hierarchies Not Supported**: Data binding works with flat data only; select "flat" representation in SAC
|
||||
|
||||
See details in [Data Binding Limitations](#data-binding-limitations) below.
|
||||
|
||||
### Custom Widgets for Planning
|
||||
|
||||
Custom widgets can support SAP Analytics Cloud Planning scenarios:
|
||||
|
||||
**Use Cases**:
|
||||
- Custom input controls
|
||||
- Specialized data entry forms
|
||||
- Planning workflow visualization
|
||||
- Custom approval interfaces
|
||||
|
||||
### Data Binding Limitations
|
||||
|
||||
**Known Limitations**:
|
||||
|
||||
1. **Builder Panel + Data Binding Conflict**:
|
||||
- Cannot combine custom Builder Panel with data binding
|
||||
- Builder Panel overrides data binding functionality
|
||||
- Choose one approach per widget
|
||||
|
||||
2. **Hierarchies Not Supported**:
|
||||
- Data binding works with flat data only
|
||||
- Select "flat" representation in SAC properties
|
||||
- Hierarchical dimensions require alternative approach
|
||||
|
||||
### Planning API Integration
|
||||
|
||||
**Available through Script**:
|
||||
```javascript
|
||||
// In SAC script
|
||||
var ds = Table_1.getDataSource();
|
||||
|
||||
// Planning operations (via DataSource)
|
||||
ds.setUserInput(selection, value); // Write data
|
||||
ds.submitData(); // Commit changes
|
||||
ds.revertData(); // Rollback
|
||||
```
|
||||
|
||||
**Custom Widget Access**:
|
||||
```javascript
|
||||
// Widget receives DataSource via method
|
||||
class PlanningWidget extends HTMLElement {
|
||||
async setDataSource(dataSource) {
|
||||
this._ds = dataSource;
|
||||
// Can now call dataSource methods
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Input Control Pattern
|
||||
|
||||
```javascript
|
||||
class CustomInputWidget extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this._setupInputHandlers();
|
||||
}
|
||||
|
||||
_setupInputHandlers() {
|
||||
this._shadowRoot.getElementById("input").addEventListener("change", (e) => {
|
||||
// Fire event with new value
|
||||
this.dispatchEvent(new CustomEvent("onValueChange", {
|
||||
detail: { newValue: e.target.value }
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// SAC script handles the planning write-back
|
||||
CustomInputWidget_1.onValueChange = function() {
|
||||
var info = CustomInputWidget_1.getEventInfo();
|
||||
var selection = { "Account": "Forecast", "Time": "2024.Q1" };
|
||||
Table_1.getDataSource().setUserInput(selection, info.newValue);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Methods Reference
|
||||
|
||||
### DataSource Methods (via Script)
|
||||
|
||||
| Method | Description | Parameters |
|
||||
|--------|-------------|------------|
|
||||
| `getData(selection)` | Get data cell value | Selection object |
|
||||
| `getResultSet()` | Get current result set | None |
|
||||
| `getMembers(dimension)` | Get dimension members | Dimension name |
|
||||
| `getResultMember(dim, selection)` | Get member info | Dimension, Selection |
|
||||
| `getDimensionFilters(dimension)` | Get filter values | Dimension name |
|
||||
| `setDimensionFilter(dim, member)` | Set filter | Dimension, MemberInfo |
|
||||
| `removeDimensionFilter(dimension)` | Clear filter | Dimension name |
|
||||
|
||||
### Variable Methods
|
||||
|
||||
| Method | Description | Parameters |
|
||||
|--------|-------------|------------|
|
||||
| `setVariableValue(name, value)` | Set variable | Variable name, value |
|
||||
| `getVariableValues()` | Get all variables | None |
|
||||
|
||||
**Performance Tip**: Group `setVariableValue()` calls together for automatic request merging.
|
||||
|
||||
### Custom Widget Data Binding Methods
|
||||
|
||||
```javascript
|
||||
// Access data binding
|
||||
const binding = this.dataBindings.getDataBinding("myBinding");
|
||||
|
||||
// Get result set (async)
|
||||
const resultSet = await binding.getResultSet();
|
||||
|
||||
// Direct property access
|
||||
const data = this.myBinding.data;
|
||||
const metadata = this.myBinding.metadata;
|
||||
```
|
||||
|
||||
### Event Info Pattern
|
||||
|
||||
```javascript
|
||||
// In custom widget
|
||||
this.dispatchEvent(new CustomEvent("onSelect", {
|
||||
detail: {
|
||||
selectedId: "item-123",
|
||||
selectedValue: 100
|
||||
}
|
||||
}));
|
||||
|
||||
// In SAC script
|
||||
Widget_1.onSelect = function() {
|
||||
var info = Widget_1.getEventInfo();
|
||||
// info.selectedId = "item-123"
|
||||
// info.selectedValue = 100
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
### Before Transport
|
||||
|
||||
- [ ] Verify resource file hosting is globally accessible
|
||||
- [ ] Update URLs if changing hosting strategy
|
||||
- [ ] Regenerate integrity hashes if files changed
|
||||
- [ ] Test widget in source tenant
|
||||
- [ ] Document any script dependencies
|
||||
|
||||
### After Transport
|
||||
|
||||
- [ ] Verify widget loads in target tenant
|
||||
- [ ] Test all functionality
|
||||
- [ ] Check script object references still work
|
||||
- [ ] Verify data binding if applicable
|
||||
- [ ] Test in view mode (not just edit mode)
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
| Symptom | Likely Cause | Solution |
|
||||
|---------|--------------|----------|
|
||||
| Widget won't load | URL not accessible | Verify hosting, CORS |
|
||||
| Integrity warning | Hash mismatch | Regenerate hash |
|
||||
| Script errors | Missing script objects | Recreate in target |
|
||||
| No data | Data binding lost | Reconfigure binding |
|
||||
| Styling broken | CSS not loaded | Check styling panel config |
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Analytics Designer API Reference](https://help.sap.com/doc/958d4c11261f42e992e8d01a4c0dde25/release/en-US/index.html)
|
||||
- [Custom Widget Developer Guide](https://help.sap.com/doc/c813a28922b54e50bd2a307b099787dc/release/en-US/CustomWidgetDevGuide_en.pdf)
|
||||
- [SAC Content Transport](https://community.sap.com/t5/technology-blog-posts-by-members/sac-content-transport-migration-using-ctms/ba-p/13742318)
|
||||
- [Optimized Story Experience](https://community.sap.com/t5/technology-blog-posts-by-sap/the-new-optimized-story-experience-the-unification-of-story-and-analytic/ba-p/13558887)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-22
|
||||
Reference in New Issue
Block a user