Skip to main content

OARepo UI

User interface components and templating system for Invenio framework.

Overview

This package extends Invenio with comprehensive UI capabilities:

  • JinjaX-based static template rendering system
  • React JS integration for dynamic search interfaces
  • Pluggable UI resource components
  • Content negotiation and export decorators
  • Configurable permission-based UI actions
  • Built-in components for common UI patterns
  • Template override system for customization

Installation

pip install oarepo-ui

Requirements

  • Python 3.14+
  • Invenio 14.x
  • oarepo-runtime >= 2.0.0
  • jinjax >= 0.60

Key Features

1. JinjaX Template System

Source: oarepo_ui/templating/catalog.py, oarepo_ui/ext.py

OARepo builds its static UI pages on top of the JinjaX library, providing a component-based templating system with reusable UI elements.

Component Specification

Define templates in your configuration:

templates = {"detail": "DetailPage", "search": "SearchPage"}

Components accept metadata, ui, and layout parameters by default. Define parameters using JinjaX syntax:

{#def metadata, ui, layout #}
{% extends "oarepo_ui/detail.html" %}

{%- block head_links %}
{{ super() }}
{{ webpack['docs_app_components.js']}}
{{ webpack['docs_app_components.css']}}
{%- endblock %}

{% block record_main_content %}
    <Main metadata={{metadata}}></Main>
{% endblock %}

{% block record_sidebar %}
    <Sidebar metadata={{metadata}}></Sidebar>
{% endblock %}

Nested Components

Create reusable component hierarchies:

{#def metadata, ui, layout #}
<h1 style="margin-bottom: 1em">{{ metadata.title }}</h1>
<dl class="ui very basic table">
<Field label="accessibility">{{metadata.accessibility}}</Field>

Component Namespacing

Use dot notation to organize components in subdirectories:

templates = {"detail": "myrepo.DetailPage", "search": "myrepo.SearchPage"}

Components are loaded from templates/myrepo/DetailPage.jinja.

Built-in Components:

The library provides pre-built components in the templates/ folder:

  • ClipboardCopyButton.jinja - Copy-to-clipboard functionality
  • IdentifierBadge.jinja - Display identifier badges (DOI, etc.)
  • IdentifiersAndLinks.jinja - Render multiple identifiers
  • Multilingual.jinja - Multilingual field display
  • RecordExport.jinja - Export functionality
  • RecordSharing.jinja - Social sharing buttons
  • RecordVersions.jinja - Version navigation
  • SearchLink.jinja - Search result links

2. UI Resource System

Source: oarepo_ui/resources/base.py, oarepo_ui/resources/records/

Pluggable resource system for building UI endpoints with component-based architecture.

from oarepo_ui.resources.base import UIResourceConfig, UIComponentsResource


class MyUIResourceConfig(UIResourceConfig):
    blueprint_name = "my_records"
    url_prefix = "/records"
    template_folder = "templates"

    components = (
        PermissionsComponent,
        BabelComponent,
        FilesComponent,
    )


class MyUIResource(UIComponentsResource):
    def __init__(self, config):
        super().__init__(config)

Key capabilities:

  • Blueprint-based routing
  • Component lifecycle management
  • Template folder resolution
  • Content negotiation support
  • Error handler registration

3. UI Resource Components

Source: oarepo_ui/resources/components/

Reusable components for common UI functionality:

Base Component

from oarepo_ui.resources.components import UIResourceComponent


class MyComponent(UIResourceComponent):
    def before_ui_detail(self, *, id, identity, record, extra_context, **kwargs):
        # Add data to template context
        extra_context["custom_data"] = self.compute_data(record)

Built-in Components

PermissionsComponent (permissions.py)

  • Computes UI permission flags for record actions
  • Maps API permissions to UI visibility controls

BabelComponent (babel.py)

  • Provides locale information to templates
  • Integrates with Flask-Babel

FilesComponent (files.py)

  • Adds file metadata to record context
  • Handles file listing and access

CustomFieldsComponent (custom_fields.py)

  • Exposes custom field vocabularies to UI
  • Provides vocabulary term resolution

AllowedHtmlTagsComponent (bleach.py)

  • Configures HTML sanitization rules
  • Provides safe HTML rendering configuration

MultilingualFieldLanguagesComponent (multilingual_field_languages.py)

  • Adds available language options for multilingual fields

RecordRestrictionComponent (record_restriction.py)

  • Computes record access restriction status

FilesLockedComponent (files_locked.py)

  • Determines if record files are locked for editing

FilesQuotaAndTransferComponent (files_quota.py)

  • Provides file quota and transfer information

EmptyRecordAccessComponent (access_empty_record.py)

  • Ensures empty record structures have proper access data

4. Resource Decorators

Source: oarepo_ui/resources/decorators/

Content Negotiation

from oarepo_ui.resources.decorators import content_negotiation


@content_negotiation(default="text/html", supported=["text/html", "application/json"])
def detail_view(self, id, identity, **kwargs):
    # Automatically handles Accept header routing
    pass

Signposting

FAIR Signposting implementation for machine-readable links:

from oarepo_ui.resources.decorators import signposting


@signposting
def landing_page(self, id, identity, record, **kwargs):
    # Adds Link headers and linkset endpoints
    pass

Supported relation types:

  • author - Author identifiers
  • cite-as - Persistent identifier (DOI)
  • describedby - Metadata formats
  • item - File contents
  • license - License URIs
  • type - Resource type (schema.org)

Record/Draft Passthrough

from oarepo_ui.resources.decorators import pass_record, pass_draft


@pass_record
def detail_view(self, id, identity, record, **kwargs):
    # `record` parameter automatically populated
    pass


@pass_draft
def edit_view(self, id, identity, draft, **kwargs):
    # `draft` parameter automatically populated
    pass

5. React Search UI Integration

Source: oarepo_ui/resources/records/config.py, oarepo_ui/resources/records/resource.py, webpack assets

Integration with Invenio-Search-UI for dynamic search interfaces. The system provides embedded React apps within Jinja-rendered pages rather than full single-page applications.

Template Setup

{%- extends config.BASE_TEMPLATE %}

{%- block javascript %}
    {{ super() }}
    {# imports oarepo-ui JS libraries #}
    {{ webpack['oarepo_ui.js'] }}
    {# boots Invenio-Search-UI search app #}
    {{ webpack['oarepo_ui_search.js'] }}
{%- endblock %}

<div class="ui container">
  {# DOM root element for Search UI #}
  <div data-invenio-search-config='{{ search_app_oarepo_config(app_id="oarepo-search") | tojson }}'></div>
</div>

Blueprint Configuration

from functools import partial
from flask import Blueprint, render_template, current_app, g
from oarepo_runtime import current_runtime


def create_blueprint(app):
    """Blueprint for search routes."""
    blueprint = Blueprint(
        "your-app",
        __name__,
        template_folder="templates",
        static_folder="static",
    )

    blueprint.add_url_rule("/", view_func=search)
    blueprint.app_context_processor(search_app_context)
    return blueprint


def search():
    """Search template."""
    return render_template("your-app/search.html")


def search_app_context():
    """Search app context processor."""
    # Get the model's service configuration
    model = current_runtime.models.get("your_model_name")
    api_config = model.service_config

    return {
        "search_app_oarepo_config": partial(
            # Use the config's search_app_config method from RecordsUIResourceConfig
            your_ui_resource_config.search_app_config,
            identity=g.identity,
            api_config=api_config,
            overrides={
                "layoutOptions": {
                    "listView": True,
                    "gridView": False,
                    "ResultsList": {
                        "item": {
                            "component": "segment",
                            "children": [{"component": "header", "dataField": "metadata.title"}],
                        }
                    },
                }
            },
        )
    }

Search Configuration

In your invenio.cfg:

from flask_babel import lazy_gettext as _

OAREPO_SEARCH = {
    "facets": [],
    "sort": ["bestmatch", "newest", "oldest", "version"],
}

OAREPO_SORT_OPTIONS = {
    "bestmatch": dict(
        title=_("Best match"),
        fields=["_score"],  # search defaults to desc on `_score` field
    ),
    "newest": dict(
        title=_("Newest"),
        fields=["-created"],
    ),
    "oldest": dict(
        title=_("Oldest"),
        fields=["created"],
    ),
    "version": dict(
        title=_("Version"),
        fields=["-versions.index"],
    ),
    "updated-desc": dict(
        title=_("Recently updated"),
        fields=["-updated"],
    ),
    "updated-asc": dict(
        title=_("Least recently updated"),
        fields=["updated"],
    ),
}

6. UI Component Override System

Source: oarepo_ui/overrides/components.py, oarepo_ui/config.py

Dynamic override system for JavaScript React components:

from oarepo_ui.overrides import UIComponent, UIComponentOverride

# Register custom result list item component
component = UIComponent(name="MyResultItem", module="my_app.components", import_mode="lazy")

override = UIComponentOverride(endpoint="search", component=component)

# Add to configuration
OAREPO_UI_OVERRIDES = {override}

Result List Item Registration:

from oarepo_ui.proxies import current_oarepo_ui

current_oarepo_ui.register_result_list_item(
    schema="https://example.com/schemas/record-1.0.0.json", component=my_component
)

7. Permission-Based UI Actions

Source: oarepo_ui/config.py

Configure which actions are available in the UI:

# Record actions (published records)
OAREPO_UI_RECORD_ACTIONS = {
    "search",
    "create",
    "read",
    "update",
    "delete",
    "read_files",
    "update_files",
    "read_deleted_files",
    "edit",
    "new_version",
    "manage",
    "review",
    "view",
    "manage_files",
    "manage_record_access",
}

# Draft action mapping
OAREPO_UI_DRAFT_ACTIONS = {
    "read_draft": "read",
    "update_draft": "update",
    "delete_draft": "delete",
    "draft_read_files": "read_files",
    "draft_update_files": "update_files",
    "draft_read_deleted_files": "read_deleted_files",
    "manage": "manage",
    "manage_files": "manage_files",
    "manage_record_access": "manage_record_access",
}

8. Multilingual Field Support

Source: oarepo_ui/config.py

Configure supported languages for multilingual fields:

from flask_babel import lazy_gettext as _

OAREPO_UI_MULTILINGUAL_FIELD_LANGUAGES = [
    {"text": _("English"), "value": "en"},
    {"text": _("Czech"), "value": "cs"},
]

9. Template Filters and Globals

Source: oarepo_ui/templating/filters.py, oarepo_ui/config.py

Custom Jinja filters and global functions:

OAREPO_UI_JINJAX_FILTERS = {
    "compact_number": "invenio_app_rdm.records_ui.views.filters:compact_number",
    "localize_number": "invenio_app_rdm.records_ui.views.filters:localize_number",
    "truncate_number": "invenio_app_rdm.records_ui.views.filters:truncate_number",
    "as_dict": "oarepo_ui.templating.filters:as_dict",
    "ui_value": "oarepo_ui.templating.filters:ui_value",
}

OAREPO_UI_JINJAX_GLOBALS = {
    "ui_value": "oarepo_ui.templating.filters:ui_value",
    "as_array": "oarepo_ui.templating.filters:as_array",
    "value": "oarepo_ui.templating.filters:value",
    "as_dict": "oarepo_ui.templating.filters:as_dict",
}

Development

Setup

# Clone repository
git clone https://github.com/oarepo/oarepo-ui.git
cd oarepo-ui

./run.sh venv

Running Tests

./run.sh test

Entry Points

The package registers several Invenio entry points:

[project.entry-points."invenio_base.apps"]
oarepo_ui = "oarepo_ui.ext:OARepoUIExtension"

[project.entry-points."oarepo_ui.extensions"]
default = "oarepo_ui._components:DefaultUIExtensionConfig"

[project.entry-points."invenio_i18n.translations"]
oarepo_ui_messages = "oarepo_ui"

[project.entry-points."invenio_assets.webpack"]
oarepo_ui_theme = "oarepo_ui.theme.webpack:theme"

[project.entry-points."invenio_base.blueprints"]
oarepo_ui = "oarepo_ui.views:create_blueprint"

[project.entry-points."invenio_base.finalize_app"]
oarepo_ui = "oarepo_ui.views:finalize_app"

License

Copyright (c) 2022-2025 CESNET z.s.p.o.

OARepo UI is free software; you can redistribute it and/or modify it under the terms of the MIT License. See LICENSE file for more details.

Links

Acknowledgments

This project builds upon Invenio Framework and is developed as part of the OARepo ecosystem.

Metadata

Release files for oarepo-ui 13.5.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for oarepo-ui 13.5.3
File Size Uploaded
oarepo_ui-13.5.3.tar.gz 216.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for oarepo-ui 13.5.3
File Interpreter ABI Platform
oarepo_ui-13.5.3-py3-none-any.whl Python 3 none any Details

Total release size: 565.8 kB

Release files / oarepo_ui-13.5.3.tar.gz

Download URL oarepo_ui-13.5.3.tar.gz
Size 216.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f63e254cf62e14fce94cc194ef5f4e14cfa706d670d94cf713559596da8aac6f
BLAKE2b-256 checksum
How to use checksums
e9c81ef932b07f64c7701dd28a7ed412378cdff4f43d09ae987cda6f334c7761
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / oarepo_ui-13.5.3-py3-none-any.whl

Download URL oarepo_ui-13.5.3-py3-none-any.whl
Size 348.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c6e34bef8fece3470709698a96aa84795f8f54ac91408cab31499bdd18fa981c
BLAKE2b-256 checksum
How to use checksums
2f1267e71b1eb6295d37003c9ed8c48144507eb0422a96d5aa9ffc598fa0bc3f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

13.5.3 This release

2 release files

13.5.2

2 release files

13.5.1

2 release files

13.4.0

2 release files

13.3.0

2 release files

13.2.3

2 release files

13.2.2

2 release files

13.2.1

2 release files

13.2.0

2 release files

13.1.0

2 release files

13.0.0

2 release files

12.1.0

2 release files

12.0.2

2 release files

11.0.0

2 release files

10.2.0

2 release files

10.1.0

2 release files

10.0.0

2 release files

9.2.0

2 release files

9.1.5

2 release files

9.1.4

2 release files

9.1.3

2 release files

9.1.2

2 release files

9.1.1

2 release files

9.1.0

2 release files

9.0.0

2 release files

8.0.2

2 release files

8.0.1

2 release files

8.0.0

2 release files

6.0.0

2 release files

5.2.87

2 release files

5.2.86

2 release files

5.2.85

2 release files

5.2.84

2 release files

5.2.83

2 release files

5.2.81

2 release files

5.2.79

2 release files

5.2.78

2 release files

5.2.77

2 release files

5.2.76

2 release files

5.2.75

2 release files

5.2.74

2 release files

5.2.71

2 release files

5.2.70

2 release files

5.2.69

2 release files

5.2.68

2 release files

5.2.67

2 release files

5.2.66

2 release files

5.2.65

2 release files

5.2.64

2 release files

5.2.63

2 release files

5.2.56

2 release files

5.2.54

2 release files

5.2.53

2 release files

5.2.52

2 release files

5.2.51

2 release files

5.2.48

2 release files

5.2.47

2 release files

5.2.46

2 release files

5.2.45

2 release files

5.2.43

2 release files

5.2.42

2 release files

5.2.40

2 release files

5.2.39

2 release files

5.2.38

2 release files

5.2.37

2 release files

5.2.34

2 release files

5.2.33

2 release files

5.2.32

2 release files

5.2.29

2 release files

5.2.28

2 release files

5.2.27

2 release files

5.2.26

2 release files

5.2.25

2 release files

5.2.24

2 release files

5.2.22

2 release files

5.2.21

2 release files

5.2.20

2 release files

5.2.19

2 release files

5.2.18

2 release files

5.2.17

2 release files

5.2.16

2 release files

5.2.15

2 release files

5.2.12

2 release files

5.2.11

2 release files

5.2.10

2 release files

5.2.9

2 release files

5.2.8

2 release files

5.2.7

2 release files

5.2.6

2 release files

5.2.5

2 release files

5.2.4

2 release files

5.2.2

2 release files

5.2.1

2 release files

5.2.0

2 release files

5.1.41

2 release files

5.1.36

2 release files

5.1.35

2 release files

5.1.34

2 release files

5.1.33

2 release files

5.1.32

2 release files

5.1.31

2 release files

5.1.30

2 release files

5.1.29

2 release files

5.1.27

2 release files

5.1.26

2 release files

5.1.25

2 release files

5.1.24

2 release files

5.1.23

2 release files

5.1.22

2 release files

5.1.21

2 release files

5.1.16

2 release files

5.1.15

2 release files

5.1.14

2 release files

5.1.13

2 release files

5.1.12

2 release files

5.1.11

2 release files

5.1.10

2 release files

5.1.9

2 release files

5.1.8

2 release files

5.1.7

2 release files

5.1.6

2 release files

5.1.5

2 release files

5.1.4

2 release files

5.1.3

2 release files

5.1.2

2 release files

5.1.1

2 release files

5.1.0

2 release files

5.0.99

2 release files

5.0.98

2 release files

5.0.97

2 release files

5.0.95

2 release files

5.0.94

2 release files

5.0.93

2 release files

5.0.92

2 release files

5.0.91

2 release files

5.0.90

2 release files

5.0.89

2 release files

5.0.87

2 release files

5.0.86

2 release files

5.0.85

2 release files

5.0.84

2 release files

5.0.83

2 release files

5.0.82

2 release files

5.0.81

2 release files

5.0.80

2 release files

5.0.79

2 release files

5.0.78

2 release files

5.0.77

2 release files

5.0.76

2 release files

5.0.75

2 release files

5.0.74

2 release files

5.0.73

2 release files

5.0.72

2 release files

5.0.71

2 release files

5.0.70

2 release files

5.0.69

2 release files

5.0.64

2 release files

5.0.63

2 release files

5.0.62

2 release files

5.0.61

2 release files

5.0.60

2 release files

5.0.59

2 release files

5.0.58

2 release files

5.0.57

2 release files

5.0.56

2 release files

5.0.52

2 release files

5.0.51

2 release files

5.0.50

2 release files

5.0.49

2 release files

5.0.48

2 release files

5.0.47

2 release files

5.0.46

2 release files

5.0.45

2 release files

5.0.44

2 release files

5.0.36

2 release files

5.0.35

2 release files

5.0.34

2 release files

5.0.33

2 release files

5.0.32

2 release files

5.0.31

2 release files

5.0.30

2 release files

5.0.29

2 release files

5.0.28

2 release files

5.0.27

2 release files

5.0.26

2 release files

5.0.23

2 release files

5.0.21

2 release files

5.0.20

2 release files

5.0.19

2 release files

5.0.17

2 release files

5.0.16

2 release files

5.0.15

2 release files

5.0.14

2 release files

5.0.13

2 release files

5.0.11

2 release files

5.0.10

2 release files

5.0.9

2 release files

5.0.8

2 release files

5.0.7

2 release files

5.0.6

2 release files

5.0.5

2 release files

5.0.4

2 release files

5.0.3

2 release files

5.0.2

2 release files

5.0.1

2 release files

5.0.0

2 release files

4.0.10

2 release files

4.0.9

2 release files

4.0.8

2 release files

4.0.7

2 release files

4.0.6

2 release files

4.0.5

2 release files

4.0.4

2 release files

4.0.3

2 release files

4.0.2

2 release files

4.0.1

2 release files

4.0.0

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.1

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.3

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page