Smart View Overrides¶
Overview¶
Smart View overrides allow you to customize several aspects of the Smart View without having to rely on the Smart View SDK and without the need to deploy new artifacts on Content Server servers. This low-coding approach enables rapid customization of Smart View features.

General Concepts¶
Like many other features in Module Suite, Smart View overrides follow a convention-based configuration approach. For applying a customization to the Smart View UI using one of the supported overrides, it is sufficient, in most cases, to create the appropriate script under the appropriate Content Script Volume folder.
Folder Structure¶
Smart View overrides are organized as follows:
Content Script Volume
└── CSSmartView
├── Actions # Used to define lazy loaded actions to be displayed in nodes' related actionbars
├── Commands # Used to define new commands to be displayed in nodes' related actionbars
├── Columns # Used to define custom dynamic columns to be displayed in Content Server spaces
├── MetaPanels # Used to define custom dynamic Metadata Panels that can be added alongside an object's standard metadata panels, enabling enhanced or context-specific metadata display
└── Overrides # Overrides configuration. Its content determines when and where a particular override is used

Override Map (OM) and Actual Override Map (AOM)¶
Having a possible serious impact on the end user experience, it is important that the system is effective in calculating how, where and when overrides should be applied.
For this reason, Module Suite uses an elaborate algorithm to determine the Actual Override Map (AOM) to use when overrides should be applied.
Override Map Structure¶
The content of the Overrides folder is used to compute an Override Map (OM), specific to your repository, having the following structure:
OM = [
"globals": [ // (1) Scripts to be always executed
540588
],
"type": [ // (2) Scripts for specific subtypes
"144": [ // (3) Scripts for Documents (subtype 144)
548066
]
],
"tenants": [ // (4) Tenant-specific overrides
"497147": [ // (5) Tenant DataID
"globals": [ // (6) Tenant global overrides
548169
],
"type": [ // (7) Tenant subtype overrides
"144": [ // (8) Documents in this tenant
496932
]
],
"ids": [ // (9) Specific node overrides
"496931": [ // (10) Specific node DataID
545972
]
]
]
]
]
Override Evaluation Order¶
The configuration options are processed in the following order:
- Global Overrides (scripts found directly under the Override folder) are executed first.
- Subtype Overrides (scripts found within a Subtype folder - e.g. "S144" for Documents) will be evaluated second, and might overwrite the global overrides.
- Tenant Global Overrides (any object in the tenant) will be evaluated next (3rd globally).
- Tenant Subtype Overrides will go next (4th globally) to process objects of a specific subtype within the selected tenant.
- Tenant DataID Overrides go last (5th globally). These are overrides targeting a specific object, and thus have the highest priority.
flowchart TD
Start([Override Evaluation Starts]) --> Global[1. Global Overrides<br/>Override folder root]
Global --> Subtype[2. Subtype Overrides<br/>S144, S0, etc.]
Subtype --> TenantGlobal[3. Tenant Global Overrides<br/>D+TenantID/root]
TenantGlobal --> TenantSubtype[4. Tenant Subtype Overrides<br/>D+TenantID/S+Subtype]
TenantSubtype --> TenantDataID[5. Tenant DataID Overrides<br/>D+TenantID/D+NodeID]
TenantDataID --> End([Final Override Map<br/>Highest Priority])
style Global fill:#e1f5ff
style Subtype fill:#fff4e1
style TenantGlobal fill:#e8f5e9
style TenantSubtype fill:#f3e5f5
style TenantDataID fill:#ffebee
style Start fill:#f5f5f5
style End fill:#f5f5f5
How OM is Created¶
In order to determine the OM, the content of the Overrides folder is evaluated following this logic:
- globals: Contains the list of scripts stored directly under "Overrides"
- type: For each direct subfolder of "Overrides" that has a name starting with "S", an entry is created. The key is the target subtype (from the folder name), and the value is the list of scripts in that folder.
- tenants: For each direct subfolder of "Overrides" that has a name starting with "D", an entry is created. The key is the tenant's DataID, and the value is the tenant OM configuration.
- ids: Within tenant folders, subfolders starting with "D" are used to create entries in the "ids" map for specific node overrides.
Example Folder Structure¶
Overrides (ID: 00001)
├── GlobalScript (ID: 00002) - Content Script
├── S144 (ID: 00003) - AnsTemplateFolder
│ └── Document Script (ID: 00004) - Content Script
└── D1234 (ID: 00005) - AnsTemplateFolder (Tenant)
├── S0 (ID: 00006) - AnsTemplateFolder
│ └── Folder Script (ID: 00007) - Content Script
└── D5678 (ID: 00008) - AnsTemplateFolder
└── Node Script (ID: 00009) - Content Script
This structure results in:
{
"globals": [00002],
"type": {
"144": [00004]
},
"tenants": {
"1234": {
"globals": [],
"type": {
"0": [00007]
},
"ids": {
"5678": [00009]
}
}
}
}
Actual Override Map (AOM)¶
When a user changes the current space, the OM is evaluated by the framework against the users' permissions and the actual override map (AOM) associated to the space is determined.
AOM is determined by executing the relevant scripts in OM in the order described above. The AOM has the following form:
AOM = [
"S144": [ // (1) Commands/columns for subtype 144
commands: ["comm_one", "comm_two", ...], // (2) List of command keys
columns: [ // (3) Optional columns
col_name: "col value", // value can be HTML
...
]
],
"D1234": [ // (4) Commands/columns for specific node
commands: ["comm_one", "comm_two", ...],
columns: [
col_name: "col value",
...
]
]
]
Where: - (1) represents commands and columns to be associated to all nodes having the identified subtype - (3) can be omitted if no custom columns are needed - (4) represents commands and columns to be associated to a specific node (identified by its id) - (4) takes precedence over (1)
Override Map Creation Timeline¶
Initial System Startup¶
- First User Access: When any user first accesses a SmartUI application, the system begins the override definition loading process
- Definition Loading: All Column, Command/Action, and Panel definitions are loaded from the Content Script volume
- User-Specific Caching: If
amcs.amsui.volumeCacheis enabled, definitions are cached in memcached per user
Per-Space Navigation¶
- Lazy Initialization: When users navigate to different OTCS folders/spaces, the Actual Override Map is built on-demand
- Permission Evaluation: The system evaluates user permissions against Content Script volume objects
- Dynamic Computation: AOM is computed based on current space context and user rights
- Script Execution: Override scripts execute in the documented order hierarchy
Volume Cache Configuration¶
Parameter: amcs.amsui.volumeCache¶
- Type: Boolean
- Default: false
- Scope: Global system setting
- Performance Impact:
- Enabled: Significant performance improvement for override-heavy environments
- Disabled: Real-time computation on every space navigation (slower but always current)
Cache Storage Architecture¶
The system uses a sophisticated two-tier caching strategy:
- Memcached Layer: Stores user-specific override definitions based on Content Script volume permissions
- Java Memory Layer: Stores the Override Map (OM) structure
- Dynamic Computation: Actual Override Map (AOM) generation on-demand during space navigation
Cache Management¶
- Programmatic Clearing: Use
amsui.clearCache()API - Automatic Invalidation: Cache invalidates on Content Script volume changes
- User Isolation: Each user maintains separate cached definitions
Direct Access Restrictions
Override Maps (OM) and Actual Override Maps (AOM) are internal system components and should not be accessed directly through custom code. Use the supported approaches: Custom Override Scripts, Override Configuration, Cache Management, and System Monitoring.
Smart View Custom Menus¶
Setting up a customization to the Smart View menu requires at least two components:
- A menu command definition script (in
CSSmartView/Commands) - An override configuration script (in
CSSmartView/Overrides)
Menu Command Definition¶
Commands are defined in Content Scripts stored in the CSSmartView/Commands folder. These scripts return command definitions that specify how the command should appear and behave.
Basic Command Definition¶
return [
[
am: [
exec: [
mode: "script",
script: 2644067, // Content Script ID to execute
params: [],
refresh_on_success: true,
on_success_action: "",
newtab: false,
url: ""
]
],
baricon: null,
icon: null,
name: "My Custom Command",
command_key: "my_custom_command",
signature: "my_custom_command",
scope: "multiple" // single, multiple, or container
]
]
Command with Confirmation¶
return [
[
am: [
confirmation: [
required: true,
title: "Confirm Action",
message: "Are you sure you want to proceed?"
],
exec: [
mode: "script",
script: 2644067,
params: []
]
],
name: "Delete Item",
command_key: "delete_item",
signature: "delete_item",
scope: "single"
]
]
Command with Panel¶
return [
[
am: [
panel: [
width: 40,
cssClass: "my-panel-class",
slides: [
[
title: "My Panel",
script: 2644068 // Content Script for panel content
]
]
],
exec: [
mode: "panel"
]
],
name: "Open Panel",
command_key: "open_panel",
signature: "open_panel",
scope: "single"
]
]
Grouped Commands¶
Commands can be grouped together in a flyout menu:
return [
[
// Parent command (flyout)
am: [
exec: [
mode: "group"
]
],
scope: "multiple",
group: "info",
flyout: "am_group",
name: "Module Suite Actions",
command_key: "am_group",
signature: "am_group"
],
[
// Child command
am: [
exec: [
mode: "script",
script: 2644067,
params: []
]
],
name: "Content Script Action",
command_key: "am_content_script",
signature: "am_content_script",
scope: "multiple",
flyout: "am_group" // References parent command
]
]
Override Configuration¶
Override configuration scripts determine when and where commands should be displayed. These scripts are stored in the CSSmartView/Overrides folder structure.
Override Map Format¶
For more control, return a map structure:
// Script in CSSmartView/Overrides
return [
"D12345": [
commands: ["x_selectDocument"]
],
"D67890": [
commands: ["x_selectDocument"]
]
]
This approach allows multiple override behaviors to be defined in one script.
Dynamic Override Script¶
Override scripts receive a list of nodes in the execution context:
// Script receives 'nodes' variable in context
overrides = [:]
nodes.findAll { it.subtype == 144 }.each { node ->
overrides["D${node.dataid}"] = [
commands: ["training_override"]
]
}
return overrides

Smart View Custom MetaPanels¶
Setting up a customization to add custom metadata panels requires creating a metadata panel definition script in the CSSmartView/MetaPanels folder. These panels can be displayed alongside an object's standard metadata panels, enabling enhanced or context-specific metadata display.
MetaPanel Definition Script¶
MetaPanel definition scripts return command definitions that specify how the metadata panel should appear and behave. The scripts can return a list of command definitions.
Basic MetaPanel Definition¶
// In CSSmartView/MetaPanels
// Commands scripts can return a list
return [
[
am: [
exec: [
mode: "group" // (1) This command will act as our flyout
]
],
scope: "multiple",
group: "info",
flyout: "am_group", // (2) This command will act as our flyout
baricon: null,
icon: null,
name: "Try Module Suite",
command_key: "am_group",
signature: "am_group"
],
[
am: [
confirmation: [
required: false,
title: "",
message: ""
],
panel: [
width: 40,
cssClass: "",
slides: [
[
title: "",
script: null
]
]
],
key: [
code: 83,
message: "",
nogui: false
],
exec: [
mode: "script",
script: 2644067,
params: [],
refresh_on_success: true,
on_success_action: "",
newtab: false,
url: ""
]
],
baricon: null,
icon: null,
name: "Content Script",
command_key: "am_content_script",
signature: "am_content_script",
scope: "multiple",
flyout: "am_group",
selfBlockOnly: false
]
]

Smart View Custom Columns¶
Setting up a customization to add custom columns requires at least two components:
- A menu column definition script (in
CSSmartView/Columns) - An override configuration script (in
CSSmartView/Overrides)
Column Definition Script¶
The column definition Content Script is responsible for filtering the list of columns available in a certain browse view, potentially removing available columns or injecting new ones.
The script is expected to return an object available within the context ("nodesColumns"), after processing it.
Basic Column Definition¶
// In CSSmartView/Columns
// Execution context includes:
// - nodesColumns: map associating node ids with their column definitions
// - nodes: list of node records
// - req: the original REST request record
// - envelope: the current REST API call envelope
def sampleColumn = [
type: 43200, // Should be 43200 for custom columns
data_type: 43200, // Should be 43200 for custom columns
name: "Status",
sort_key: "type",
key: "sample_column" // Unique identifier, must match override script
]
nodesColumns[3156087]?.add(sampleColumn)
// Must return the revised nodeColumns
return nodesColumns
Column Definition Properties¶
| Variable | Description |
|---|---|
| type | Should be 43200 for custom columns |
| data_type | Should be 43200 for custom columns |
| name | The plaintext value for the column header |
| sort_key | The identifier of the node value to be used for sorting this column |
| key | The unique identifier for this column. Must match the key provided in the override script |
Column Override Definition¶
The override definition is shared with the custom menu overrides. In this case, we use the "columns" section:
// In CSSmartView/Overrides
retval = nodes.collect {
[
("D${it.dataid}" as String): [
commands: [],
columns: [
// Columns of type 43200 can be used to inject HTML
sample_column: drawStatusBar(it),
sample_icon_column: drawIcon(it)
]
]
]
}
return retval
// Helper function to generate column HTML
def drawStatusBar = { node ->
def statusList = ['Draft', 'Under Revision', 'Approved', 'Published']
def numSteps = statusList.size()
def currStep = new Random().nextInt(statusList.size())
def currStepName = statusList[currStep]
def stepStyle = "height:100%; width:calc(100% / ${numSteps}); float:left; background-color:#F0AD4E; box-sizing:border-box;"
def stepsHtml = ""
(currStep + 1).times {
stepsHtml += """<span style="${stepStyle}"></span>"""
}
return """
<div style="text-align:center; font-size:.75em">${currStepName}</div>
<div style="margin:3px 0; padding:0; height:5px; background-color:#eee;">${stepsHtml}</div>
"""
}

Smart View Custom Actions¶
Setting up a customization to add custom actions requires at least two components:
- A menu command definition script (same as for menus, in
CSSmartView/Commands) - An action configuration script (in
CSSmartView/Actions)
Registering a Smart View Action¶
Registering an action differs from the registration of a standard menu entry as the customization is processed in a different, separate phase.
In this case, we use the CSSmartView > Actions folder. Here we create a Content Script that acts as a filter, whose aim is to process and manipulate an existing object called "actions" which is automatically injected in the context.
Actions Object Structure¶
The actions object is a mapping containing all the actions registered so far, for each object associated to the request, indexed by the object's DataID.
Example structure:
actions = [
"656609": [
data: [
"Classify": [
content_type: "application/x-www-form-urlencoded",
method: "POST",
name: "Add RM Classification",
href: "/api/v2/nodes/2891606/rmclassifications",
body: "{\"displayPrompt\":false,\"enabled\":false}",
form_href: ""
],
"zipanddownload": [
content_type: "",
method: "POST",
name: "Zip and Download",
href: "/api/v2/zipanddownload",
body: "",
form_href: ""
]
],
map: [
default_action: "open"
],
order: [
"Classify",
"zipanddownload"
]
]
]
Action Registration Script¶
// In CSSmartView/Actions
// Execution context includes:
// - actions: map associating node ids with available actions
// - req: the current HTTP request
// - envelope: the REST API request's envelope
actions.each { action ->
node = docman.getNodeFast(action.key as long)
if (node.subtype == 144 && node.parentID == 973895) {
// Add custom action based on business rule
action.value.data["training_action"] = [
body: "training_action"
]
action.value.order.add("training_action")
}
}

Command Execution and Return Values¶
Content Script scripts executed as commands can return execution information to the caller.
Success Message¶
// After script execution completes successfully
json([
message: [
type: 'success',
text: "Operation completed successfully",
details: "The document has been processed and saved to the repository."
]
])
Error Message¶
// After script execution encounters an error
json([
message: [
type: 'error',
text: "Operation failed",
details: "Unable to process the document. Please try again."
]
])

Best Practices¶
Override Scripts¶
- Keep scripts focused: Each script should handle a specific override type
- Use meaningful names: Name scripts descriptively
- Document business logic: Add comments explaining override conditions
- Test thoroughly: Test overrides in different contexts and with different user permissions
Performance¶
- Enable caching: Use
amcs.amsui.volumeCachein production - Optimize queries: Minimize database queries in override scripts
- Cache expensive operations: Cache results of expensive computations
- Limit scope: Only apply overrides where necessary
Security¶
- Validate permissions: Always check user permissions before applying overrides
- Sanitize output: Escape HTML in column values
- Validate input: Validate any parameters passed to commands
- Audit actions: Log important actions for audit purposes
Next Steps¶
- Learn about Tile Communication for inter-tile interactions
- Explore WebForms Integration for embedding forms
- Review Smart Pages Object for creating custom pages