Skip to content
PDF

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.

Smart View Overrides Overview

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 Folder Structure

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:

  1. Global Overrides (scripts found directly under the Override folder) are executed first.
  2. Subtype Overrides (scripts found within a Subtype folder - e.g. "S144" for Documents) will be evaluated second, and might overwrite the global overrides.
  3. Tenant Global Overrides (any object in the tenant) will be evaluated next (3rd globally).
  4. Tenant Subtype Overrides will go next (4th globally) to process objects of a specific subtype within the selected tenant.
  5. 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

  1. First User Access: When any user first accesses a SmartUI application, the system begins the override definition loading process
  2. Definition Loading: All Column, Command/Action, and Panel definitions are loaded from the Content Script volume
  3. User-Specific Caching: If amcs.amsui.volumeCache is enabled, definitions are cached in memcached per user

Per-Space Navigation

  1. Lazy Initialization: When users navigate to different OTCS folders/spaces, the Actual Override Map is built on-demand
  2. Permission Evaluation: The system evaluates user permissions against Content Script volume objects
  3. Dynamic Computation: AOM is computed based on current space context and user rights
  4. 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:

  1. Memcached Layer: Stores user-specific override definitions based on Content Script volume permissions
  2. Java Memory Layer: Stores the Override Map (OM) structure
  3. 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:

  1. A menu command definition script (in CSSmartView/Commands)
  2. An override configuration script (in CSSmartView/Overrides)

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

Command Example

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
    ]
]

MetaPanel Example

Smart View Custom Columns

Setting up a customization to add custom columns requires at least two components:

  1. A menu column definition script (in CSSmartView/Columns)
  2. 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>
    """
}

Custom Columns Example

Smart View Custom Actions

Setting up a customization to add custom actions requires at least two components:

  1. A menu command definition script (same as for menus, in CSSmartView/Commands)
  2. 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")
    }
}

Custom Actions Example

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."
    ]
])

Command Execution Result

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.volumeCache in 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