Skip to content

Override Pages

In some cases, the default pages do not offer all the functionality or modification possibilities needed. It is possible to override the pages, though this should be the last resort as it increases resources needed for maintainability.

We will look into how to override some essential pages of invenio-app-rdm with our existing module invenio-theme-tugraz.

! IMPORTANT: This is valid for invenio-app-rdm==v6.0.2 !

The component to be overridden is search so the path for this looks like invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/search/. Place the components in invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/search/components.js.

The original file can be found here: components.js

Creating Search App

Now that all components have been created or imported, create the following file invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/search/index.js. In here, all the previously defined components will be imported and the search app will be defined.

import { createSearchAppInit } from "@js/invenio_search_ui";
import {
  RDMBucketAggregationElement,
  RDMRecordFacets,
  RDMRecordFacetsValues,
  RDMRecordResultsGridItem,
  RDMRecordResultsListItem,
  RDMRecordSearchBarContainer,
  RDMRecordSearchBarElement,
  RDMToggleComponent,
  RDMCountComponent,
} from "./components";

const initSearchApp = createSearchAppInit({
  "BucketAggregation.element": RDMBucketAggregationElement,
  "BucketAggregationValues.element": RDMRecordFacetsValues,
  "ResultsGrid.item": RDMRecordResultsGridItem,
  "ResultsList.item": RDMRecordResultsListItem,
  "SearchApp.facets": RDMRecordFacets,
  "SearchApp.searchbarContainer": RDMRecordSearchBarContainer,
  "SearchBar.element": RDMRecordSearchBarElement,
  "SearchFilters.ToggleComponent": RDMToggleComponent,
  "Count.element": RDMCountComponent,
});

Update webpack

Now that the functionality is done, it is important to add it to webpack. This makes it accessible to templates. Adding the following line in the invenio_theme_tugraz/webpack.py file, under the semantic-ui entries will do the trick. It will look something like this:

"semantic-ui": dict(
            entry={
                "invenio-theme-tugraz-theme": "./less/invenio_theme_tugraz/theme.less",
                "invenio-theme-tugraz-js": "./js/invenio_theme_tugraz/theme.js",
                # add search component
                'invenio-theme-tugraz-rdm-search': './js/invenio_theme_tugraz/search/index.js',
            }, ...

Adding Search Template

To make use of the new search, a search template will be added. It will import our search app as previously defined in webpack. To achieve this, we will simply copy the current search page from invenio-rdm and replace the standard search app import with ours. Create the following file invenio_theme_tugraz/templates/invenio_theme_tugraz/search.html with the content of the base search template from invenio-app-rdm .

In that file, all that has to be done is to replace the import:

{%- block javascript %}
  {{ super() }}
- {{ webpack['invenio-app-rdm-search.js'] }}
+ {{ webpack['invenio-theme-tugraz-rdm-search.js'] }}
{%- endblock %}

Override Config Variable

Finally, invenio-rdm must know that it should use our new template for the search. This can be achieved by overriding the config variable SEARCH_UI_SEARCH_TEMPLATE. In invenio_theme_tugraz/config.py add or override the following line:

SEARCH_UI_SEARCH_TEMPLATE = "invenio_theme_tugraz/search.html"

Now invenio-rdm will use the new search template, which will use the new search app.

The component to be overridden is user_records_search so the path for this looks like invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/user_records_search/. Place the components in invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/user_records_search/components.js.

The original file can be found here: components.js

Creating Search App

Now that all components have been created or imported, create the following file invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/user_records_search/index.js. In here, all the previously defined components will be imported and the search app will be defined.

import { createSearchAppInit } from "@js/invenio_search_ui";
import {
  RDMRecordResultsListItem,
  RDMRecordResultsGridItem,
  RDMDepositResults,
  RDMEmptyResults,
  RDMUserRecordsSearchLayout,
} from "./components";
import {
  RDMBucketAggregationElement,
  RDMCountComponent,
  RDMRecordFacets,
  RDMRecordFacetsValues,
  RDMRecordSearchBarElement,
  RDMToggleComponent,
} from "../search/components";

const initSearchApp = createSearchAppInit({
  "BucketAggregation.element": RDMBucketAggregationElement,
  "BucketAggregationValues.element": RDMRecordFacetsValues,
  "Count.element": RDMCountComponent,
  "EmptyResults.element": RDMEmptyResults,
  "ResultsList.item": RDMRecordResultsListItem,
  "ResultsGrid.item": RDMRecordResultsGridItem,
  "SearchApp.facets": RDMRecordFacets,
  "SearchApp.layout": RDMUserRecordsSearchLayout,
  "SearchApp.results": RDMDepositResults,
  "SearchBar.element": RDMRecordSearchBarElement,
  "BucketAggregation.element": RDMBucketAggregationElement,
  "BucketAggregationValues.element": RDMRecordFacetsValues,
  "SearchFilters.ToggleComponent": RDMToggleComponent,
});

Update webpack

Now that the functionality is done, it is important to add it to webpack. This makes it accessible to templates. Adding the following line in the invenio_theme_tugraz/webpack.py file, under the semantic-ui entries will do the trick. It will look something like this:

"semantic-ui": dict(
            entry={
                "invenio-theme-tugraz-theme": "./less/invenio_theme_tugraz/theme.less",
                "invenio-theme-tugraz-js": "./js/invenio_theme_tugraz/theme.js",
                # add user record search component
                'invenio-theme-tugraz-rdm-user-records-search': './js/invenio_theme_tugraz/user_records_search/index.js',
            }, ...

Adding Search Template

To make use of the new search, a search template will be added. It will import our search app as previously defined in webpack. To achieve this, we will simply copy the current search page from invenio-rdm and replace the standard search app import with ours. Create the following file invenio_theme_tugraz/templates/invenio_theme_tugraz/records/search_deposit.html with the content of the base user records search template from invenio-app-rdm .

In that file, all that has to be done is to replace the import:

{%- block javascript %}
  {{ super() }}
- {{ webpack['invenio-app-rdm-user-records-search.js'] }}
+ {{ webpack['invenio-theme-tugraz-rdm-user-records-search.js'] }}
{%- endblock javascript %}

Adding Render Function

Next, in invenio_theme_tugraz/deposits.py we define a function which will render the previously created template and pass the searchbar_config as argument.

from flask import render_template
from flask_login import login_required
from invenio_app_rdm.records_ui.views.deposits import get_search_url


@login_required
def deposit_search():
    """List of user deposits page."""
    return render_template(
        "invenio_theme_tugraz/records/search_deposit.html",
        searchbar_config=dict(searchUrl=get_search_url()),
    )

Adding URL Route

All that is left is to add a URL rule, so that the new function is called instead of the one from the base implementation. In invenio_theme_tugraz/ext.py import the previously defined function

from invenio_theme_tugraz.deposits import deposit_search

and inside the init_app function add:

app.add_url_rule("/uploads", "deposit_search", deposit_search)

Now invenio-rdm will use the new user record search template, which will use the new search app.

Record Landing Page

Since we do not need to add additional functionality to the record landing page, there is no need for new components or updating the webpack file. We will simply add and modify the html file and add the URL route. If there is need for additional functionality, follow the steps from the search page guide.

Adding Detail Template

Create the following file invenio_theme_tugraz/templates/invenio_theme_tugraz/records/detail.html with the content of the base record detail template from invenio-app-rdm .

Modify the template file as you see fit.

Adding Render Function

Next, in invenio_theme_tugraz/deposits.py we define a function which will render the previously created template and pass arguments needed by the template.

from flask import render_template
from invenio_app_rdm.records_ui.views.decorators import (
    pass_is_preview,
    pass_record_files,
    pass_record_or_draft,
)
from invenio_rdm_records.resources.serializers import UIJSONSerializer


@pass_is_preview
@pass_record_files
@pass_record_or_draft
def record_detail(record=None, files=None, pid_value=None, is_preview=False):
    """Record detail page (aka landing page)."""
    files_dict = None if files is None else files.to_dict()

    return render_template(
        "invenio_theme_tugraz/records/detail.html",
        record=UIJSONSerializer().serialize_object_to_dict(record.to_dict()),
        pid=pid_value,
        files=files_dict,
        permissions=record.has_permissions_to(['edit', 'new_version', 'manage',
                                               'update_draft', 'read_files']),
        is_preview=is_preview,
    )

Adding URL Route

All that is left is to add a URL rule, so that the new function is called instead of the one from the base implementation. In invenio_theme_tugraz/ext.py import the previously defined function

from invenio_theme_tugraz.deposits import record_detail

and inside the init_app function add:

app.add_url_rule("/records/<pid_value>", "record_detail", record_detail)

Now invenio-rdm will use the new record detail template when displaying a record.

Deposit Page

The component to be overridden is deposit so the path for this looks like invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/deposit/. Place the components in invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/deposit/RDMDepositForm.js.

The original file can be found here: RDMDepositForm.js

Rendering Deposit Form

Now that all components have been created or imported, create the following file invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/deposit/index.js. In here, all the previously defined components will be imported and the deposit form will be rendered.

import React from "react";
import ReactDOM from "react-dom";
import "semantic-ui-css/semantic.min.css";

import { getInputFromDOM } from "react-invenio-deposit";
import { RDMDepositForm } from "./RDMDepositForm";

ReactDOM.render(
  <RDMDepositForm
    record={getInputFromDOM("deposits-record")}
    files={getInputFromDOM("deposits-record-files")}
    config={getInputFromDOM("deposits-config")}
    permissions={getInputFromDOM("deposits-record-permissions")}
  />,
  document.getElementById("deposit-form")
);

Update webpack

Now that the functionality is done, it is important to add it to webpack. This makes it accessible to templates. Adding the following line in the invenio_theme_tugraz/webpack.py file, under the semantic-ui entries will do the trick. It will look something like this:

"semantic-ui": dict(
            entry={
                "invenio-theme-tugraz-theme": "./less/invenio_theme_tugraz/theme.less",
                "invenio-theme-tugraz-js": "./js/invenio_theme_tugraz/theme.js",
                # add deposit component
                'invenio-theme-tugraz-rdm-deposit': './js/invenio_theme_tugraz/deposit/index.js',
            }, ...

Adding Deposit Template

To make use of the new deposit form, a template will be added. It will import the deposit form as previously defined in webpack. To achieve this, we will simply copy the current deposit page from invenio-rdm and replace the standard deposit form import with ours. Create the following file invenio_theme_tugraz/templates/invenio_theme_tugraz/records/deposit.html with the content of the base deposit form template from invenio-app-rdm .

In that file, all that has to be done is to replace the import:

{%- block javascript %}
  {{ super() }}
- {{ webpack['invenio-app-rdm-deposit.js'] }}
+ {{ webpack['invenio-theme-tugraz-rdm-deposit.js'] }}
{%- endblock %}

Adding Render Function

Next, in invenio_theme_tugraz/deposits.py we define two functions which will render the previously created template and pass arguments needed by the template.

First the create function, which is called when the user wants to create a new record:

from flask import render_template
from flask_login import login_required
from invenio_app_rdm.records_ui.views.decorators import (
    pass_draft,
    pass_draft_files,
)
from invenio_app_rdm.records_ui.views.deposits import (
    get_form_config,
    get_search_url,
    new_record,
)
from invenio_rdm_records.resources.serializers import UIJSONSerializer


@login_required
def deposit_create():
    """Create a new deposit."""
    return render_template(
        "invenio_theme_tugraz/records/deposit.html",
        forms_config=get_form_config(createUrl=("/api/records")),
        searchbar_config=dict(searchUrl=get_search_url()),
        record=new_record(),
        files=dict(
            default_preview=None, entries=[], links={}
        ),
    )

Second the edit function, which is called when the user wants to edit an existing record:

@login_required
@pass_draft
@pass_draft_files
def deposit_edit(draft=None, draft_files=None, pid_value=None):
    """Edit an existing deposit."""
    record = UIJSONSerializer().serialize_object_to_dict(draft.to_dict())

    return render_template(
        "invenio_theme_tugraz/records/deposit.html",
        forms_config=get_form_config(apiUrl=f"/api/records/{pid_value}/draft"),
        record=record,
        files=draft_files.to_dict(),
        searchbar_config=dict(searchUrl=get_search_url()),
        permissions=draft.has_permissions_to(['new_version'])
    )

Adding URL Route

All that is left is to add URL rules, so that the new functions are called instead of the ones from the base implementation. In invenio_theme_tugraz/ext.py import the previously defined functions

from invenio_theme_tugraz.deposits import deposit_create, deposit_edit

and inside the init_app function add:

  • For new records:
app.add_url_rule("/uploads/new", "deposit_create", deposit_create)
  • For editing existing records:
app.add_url_rule("/uploads/<pid_value>", "deposit_edit", deposit_edit)`

Now invenio-rdm will use the new deposit form, when creating a new record or updating an existing record.

Troubleshoot

ManifestKeyNotFoundError

  • check if the spelling of the webpack names matches with the import in the template.
  • reinstall invenio-theme-tugraz
    • In order to pick up all the new files and to rebuild webpack, it is necessary to install invenio-theme-tugraz again. If no such changes happened, this step can be skipped.
    • invenio-cli packages install /path/to/invenio-theme-tugraz