Tabs configuration are part of the Tabs Framework, which creates tabs based on a tab template, this tabs templates are not constrain to any specific format for the configuration, except for a required few fields. This page will review the must used tab, the Search Tab, to give an idea of whats possible to configure in a tab.

Required Fields 

As mention before there are a few required fields for every tab configuration:

  • type - Name of the type of tab this configuration will apply to
  • display - Display Name of the tab in the user interface
  • path - Path of the tab in the url
  • roles - Roles allow to see this tab
  • groups - Security groups allow to see this tab


Both roles and groups are string arrays, if both are not configure or empty, the tab will be public, if both have values, the user must have at least 1 value of each (role and group)

General Configuration Section Example
module.exports = {
    /***********************************************************************************************************
     * Tab Configuration Required Fields
     ***********************************************************************************************************/

    type: 'search',
    display: 'Movies', // Tab Name
    path: 'movies', // /search -> Uses Search Component

    // Access to tab
    roles: [], // ['anonymous', 'admin'],
    groups: [], // ['PUBLIC:ALL']
    .
    .
    .
}

Search Tab Configuration

The search tab is must common tab used in Enterprise Search, thus the reason why it will be use to explain the major sections of the tab configuration, which are:

  • required fields (general for all tabs) - Explained in the above section
  • type specific (applies only to the current type) - Constrained only to the current type, can greatly change from one type to another, we will explain the search type in this section
  • endpoint overrides (general for all tabs) - Explained in the section below


The configuration below is a example of the search tab configuration, it may be a little different from the ones the current code has, this is due the difference between each tab requirements, and the addition of new features.

  • index - a string with the name of the index or a string array with the names of the indexes

    For multiple indexesit would look like this

    • index: ['prospectis', 'crawl_covid_19']
  • left_column_width - (optional) Inline style applied to the width of the left column, it only accepts <number-value><unit> (e.g 100px or 8em or 10vm ...)

  • filters - Specific filter to apply 

  • advancedQuery - Options for the advanced search form
    • enable - boolean flag indicating the use of the advanced search form

  • rank_results - (optional) boolean flag which displays the raking feature in every individual result
  • result - Options regarding the display of the results
    • for - (Use when multiple indexes) Indicates the index which this configuration will apply, if multiple indexes are used in the same search and each one has a different display
    • title - Field of the result that will be display as the title
    • url - (optional) Field of the result which will be use for display and as a link
    • thumbnail - (optional) Image located at the left of the title and url
      • field - Field of source media
      • type - (img or mimeType) Indicates the type of source to use
        • img - Assumes the field values is the path to an image either internal or external
        • mimeType - The value of the field will be mapped to a mimeType

          The mimeType configuration can be located in config/ui/configs/mimeTypes.js

      • style - custom style to be applied to the thumbnail
    • other_fields -  Additional fields to retrieve with each document

      The search by default retrieves the fields from body, if you want to retrieve a field but not display it, use other_fields

    • body - Matrix of Dynamic Fields, where every array inside holding the Dynamic fields represents a row in the result display

    • metadata -
      • fields - Array of Dynamic Fields
      • sort - String indication the sort orientation of  the fields based on their display label
        • asc - Ascendant (A to Z)
        • desc - Descendant (Z to A)
        • none - As added in the configuration


  • facets - List of Dynamic Facets

  • sort
    • default - default sort value compoused of the field name and the orientation
      • Formatted like this <field-name>:<orientation>
    • options - List of sorting options
      • sort - Field name to which sort
      • displayName - Name to be displayed in the user interface
      • order - Default orientation of the options

        Using Elasticsearch sort option may gave an issue, check your field is of type keyword or you are using the nested keyword value

  • highlight
    • pre_tag - Tag before highlighted text
    • post_Tag - Tag after highlighted text
    • fields - Fields configuration for highlight
      • <field name>
        • fragment_size - maximum size of the block to be highlighted
        • number_of_fragments - maximum blocks highlighted
module.exports = {
    /***********************************************************************************************************
     * Tab Configuration Required Fields
     ***********************************************************************************************************/
    .
    .
    .
    /***********************************************************************************************************
     * Search Type Specific
     ***********************************************************************************************************/

    index: 'tmdb',
    left_column_width: '25vw',
    // filters: {
    //     sourceName: 'the_movie_db_movies'
    // },

    // Advanced Search
    advancedQuery: {
        enable: true
    },

    rank_results: true,
    result: {
        title: 'title', // Required
        url: 'url',
        thumbnail: {
            field: 'poster_path_w185',
            type: 'img', // img | mimeType
            style: 'width: 3.1em; height: 8.8ex;'
        }, // Image in the left of the result

        other_fields: [], // Add extra fields to fetch but not to display, no need to repeat other fields values
        body: [
            [
                { field: 'release_date', type: 'date', format: 'shortDate', label: 'Release Date' },
                { field: 'status', label: 'Status', transform: 'upperCase' }
            ],
            [{ field: 'overview', class: 'content' }],
            [
                {
                    field: 'metadata.cast.profile_path_w185',
                    type: 'thumbnails',
                    detail: 'metadata.cast.name',
                    fullSize: 'metadata.cast.profile_path',
                    class: 'cast-thumbnails', // add custom style in ui/src/styles.scss
                    missing_icon: 'person'
                }
            ],
            [{ field: 'video', label: 'Has Video' }, { field: 'metadata.budget', label: 'Budget', type: 'number', prefix: '$' }]
        ],

        metadata: {
            fields: [
                {
                    field: 'poster_path_w185',
                    label: 'Poster',
                    type: 'img'
                    // transform: 'replace',
                    // style: 'width: 5em;',
                    // transformArg: ['https://image.tmdb.org/t/p/original/', 'https://www.dvdplanetstore.pk/wp-content/uploads/2017/12/']
                },
                { field: 'metadata.homepage', label: 'Homepage', type: 'url', default: '-' },
                { field: 'url', label: 'Url', type: 'url' },
                { field: 'metadata.directors.name', label: 'Directors', join: ', ' },
                { field: 'metadata.cast.name', label: 'Cast', join: ', ' },
                { field: 'metadata.original_language', label: 'Original Language', transform: 'upperCase' },
                { field: 'metadata.imdb_id', label: 'Imdb Id' },
                { field: 'runtime', label: 'RunTime', suffix: ' min' },
                { field: 'metadata.revenue', label: 'Revenue', type: 'number', prefix: '$ ' },
                { field: 'metadata.vote_average', label: 'Vote Average' },
                { field: 'metadata.production_countries.name', label: 'Production Countries' },
                { field: 'metadata.tagline', label: 'Tag Line', default: '-' },
                { field: 'metadata.vote_count', label: 'Votes' },
                { field: 'metadata.budget', label: 'Budget', type: 'number', suffix: ' USD' },
                { field: 'status', label: 'Status' }
            ],
            sort: 'none' // 'asc' Ascendant | 'desc' Descendant | 'none' As added in configuration
        }
    },

    facets: [
        {
            id: 'gender',
            type: 'string',
            field: 'metadata.genres.name',
            displayName: 'Gender',
            maxValues: 100,
            maxDisplay: 5,
            mimeIcon: true,
            expanded: true,
            order: 'countDesc',
            postFilter: true, // By default doesn't show the counts
            hideCount: true // force to show the count
        },
        {
            id: 'status',
            type: 'string',
            field: 'status',
            displayName: 'Status',
            maxValues: 100,
            maxDisplay: 5,
            mimeIcon: true,
            expanded: true,
            order: 'countDesc'
        },
        {
            id: 'language',
            type: 'string',
            field: 'metadata.spoken_languages.name',
            displayName: 'Spoken Language',
            maxValues: 100,
            maxDisplay: 5,
            mimeIcon: true,
            expanded: true,
            order: 'countDesc'
        },
        {
            id: 'adult',
            type: 'boolean',
            field: 'adult',
            displayName: 'Adult',
            order: 'countDesc',
            showIfOne: true, // show facet if just one option
            true: 'yes',
            false: 'no',
            expanded: true
        },
        {
            id: 'release_date_h',
            type: 'date_histogram',
            field: 'release_date',
            displayName: 'Release Date',
            // fixed_interval: ['3650d', '365d', '30d', '1d'], // milliseconds (ms) | seconds (s) | minutes (m) | hours (h) | days (d)
            calendar_interval: ['1y', '1q', '1M', '1d'],
            format: ['yyyy', '\'Q\'q', 'MMMM', 'E dd'],
            time_zone: '-06:00',
            min_doc_count: [100, 1]
        },
        {
            id: 'budget',
            type: 'histogram',
            field: 'metadata.budget',
            displayName: 'Budget',
            interval: [10000000, 1000000, 1000000],
            min_doc_count: [100, 10, 1]
            /* extended_bounds: {
                min: 0,
                max: 130000000
            } */
        },
        {
            id: 'release_date_dr',
            type: 'date_range',
            field: 'release_date',
            displayName: 'Release Range',
            format: 'MM-yyyy',
            // Based on https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math
            ranges: [
                { from: 'now-10y', key: 'minus_10' },
                { from: '01-1960', to: '01-1970' },
                { to: 'now-10M/M' }
            ]
        },
        {
            id: 'budget_r',
            type: 'range',
            field: 'metadata.budget',
            displayName: 'Budget Range',
            ranges: [
                { to: 10000000, key: '< 10,000,000' },
                { from: 10000000, key: '> 10,000,000' },
                { from: 50000000, to: 100000000, key: '50 to 100 millions' }
            ]
        }
    ],

    sort: {
        default: '_score:desc',
        options: [
            {
                sort: '_score',
                displayName: 'Relevancy',
                order: 'desc'
            },
            {
                sort: 'release_date',
                displayName: 'Release Date',
                order: 'desc'
            },
            {
                sort: 'metadata.budget',
                displayName: 'Budget',
                order: 'desc'
            }
        ]
    },

    highlight: {
        pre_tags: [
            '<strong>'
        ],
        post_tags: [
            '</strong>'
        ],
        fields: {
            title: {
                fragment_size: 100,
                number_of_fragments: 1
            },
            overview: {
                fragment_size: 200,
                number_of_fragments: 5
            },
            url: {
                fragment_size: 100,
                number_of_fragments: 1
            }
        }
    },

    /***********************************************************************************************************
     * Endpoints Overrides
     ***********************************************************************************************************/
    .
    .
    .
}

Endpoint Overrides 

Endpoint Overrides are an option to customize the endpoint configuration for each tab, for an endpoint override to work many changes must be done in the user interface, as well for the endpoint to support this. This process will be explain the Tabs Framework page, but below are a few examples of already working overrides for the endpoints of Saga, Search and Type-ahead.

The overrides are pieces of endpoint configuration specified in the tab configuration. either updating or adding values. This configuration will be use to update the endpoint using its configuration as the base for the new one.

module.exports = {
    .
    .
    .
    /***********************************************************************************************************
     * Endpoints Overrides
     ***********************************************************************************************************/

    // Override of the config for the search endpoint in 'server/endpoints/saga/endpoint.json'
    saga: {
        enable: false,
        splitRegex: '[\r|\n]+',
        metadata: false,
        addComponents: false,
        compFields: null,
        timeout: 10000,
        tags: ['admin-actions']
    },

    // Override of the index config for the search endpoint in 'server/endpoints/search/endpoint.json'
    search: {
        compositeSearchFields: {
            title: 2.0,
            overview: 1.0,
            url: 1.0
        },
        suggest: {
            field: 'title',
            candidates: 3,
            gram_size: 3,
            mode: 'always'
        },

        dateField: 'release_date' // Advanced search
    },

    // Override of the index config for the search endpoint in 'server/endpoints/typeAhead/endpoint.json'
    typeahead: {
        enable: true,
        fields: {
            search: { // The fields to search
                titleStartNgrams: 2.0,
                titleMiddleNgrams: 1.0 // 1.0 Its the boosting value
            },
            fetch: 'title' // The fields to return.
        },
        count: 5, // Results to return
        dedupMultiplier: 3.5 // Multiplier of count (above) so we can de-dup
    }
}

  • No labels