From 798dd0c8758b154a8a1fae8fd594c87d5a54548f Mon Sep 17 00:00:00 2001 From: Tom Morrell Date: Thu, 21 Mar 2024 16:50:48 +0100 Subject: [PATCH 01/13] cli: Add warnings to reindex command --- docs/reference/cli.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 253016d8..0a6cc2b3 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -480,3 +480,7 @@ invenio rdm rebuild-all-indices -o users,communities,records,requests,request_ev if you don't specify services, The following services will be reindexed: `users, groups, domains, communities, members, records, record-media-files, affiliations, awards, funders, names, subjects, vocabularies, requests, request_events, oaipmh-server` + +Note that the users and groups use bulk indexing and rely on celery running. They will not be reindexed if ceoery is not running. + +This command does not impact usage statistics indexes. You need to manually restore statistics indexes [from a backup](../develop/howtos/backup_search_indices.md). From dead6156a44b681f76db1d95b15c263747f14059 Mon Sep 17 00:00:00 2001 From: Tom Morrell Date: Thu, 21 Mar 2024 16:53:39 +0100 Subject: [PATCH 02/13] cli: Add warnings to reindex command --- docs/reference/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 0a6cc2b3..d6dd4526 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -481,6 +481,6 @@ if you don't specify services, The following services will be reindexed: `users, groups, domains, communities, members, records, record-media-files, affiliations, awards, funders, names, subjects, vocabularies, requests, request_events, oaipmh-server` -Note that the users and groups use bulk indexing and rely on celery running. They will not be reindexed if ceoery is not running. +Note that the users, groups, and members use bulk indexing and rely on celery running. They will not be reindexed if celery is not running. This command does not impact usage statistics indexes. You need to manually restore statistics indexes [from a backup](../develop/howtos/backup_search_indices.md). From dadd92889edf9dcc040fc9a049a98e2c40011dd5 Mon Sep 17 00:00:00 2001 From: Sam Arbid <36583694+Samk13@users.noreply.github.com> Date: Sun, 16 Jun 2024 22:24:50 +0200 Subject: [PATCH 03/13] fix: DataValidationError of pipenv (#664) --- docs/develop/howtos/custom_code.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/develop/howtos/custom_code.md b/docs/develop/howtos/custom_code.md index 5c333eff..9cdd99ba 100644 --- a/docs/develop/howtos/custom_code.md +++ b/docs/develop/howtos/custom_code.md @@ -24,7 +24,7 @@ To generate the site folder, you will need to select option `1 - yes` (this is a ```python hl_lines="3" [packages] ... -my-site = {editable="True", path="./site"} +my-site = {editable=true, path="./site"} ``` This means that the site folder will be installed as a package with the name `my-site`, and it is editable. This package now works as any other package installed in your instance (`invenio-app-rdm`, `invenio-communities`, etc.), allowing you to customize your instance and create new views and features without adding a separate package manually. From 5a7ef8bd4d276c95d4bfc73fff1b07f0ffd3274c Mon Sep 17 00:00:00 2001 From: Sam Arbid <36583694+Samk13@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:10:19 +0200 Subject: [PATCH 04/13] =?UTF-8?q?Global:=20Implement=20Dark=20Mode=20?= =?UTF-8?q?=F0=9F=8C=99=20(#669)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat: Set up dark mode 🌙 * Implement dark mode * Remove outdated overrides * Remove redundant overrides. * Seems like these overrides has no effect with the new version see https://squidfunk.github.io/mkdocs-material/upgrade/#changes-to-html-files_1 * frontpage: remove hard coded values in wave-svg * footer: remove Made with Material for MkDocs * css: adapt custom css to the dark mode * css: cleanup duplicates * Automatic light / dark mode * css: clean up * update btn colors * remove duplicates * css colors: replace hard coded values with vars and cleanup duplicates * footer: bring back made with MKDocs * home: fix toggle not showing on frontpage and features * Remove frontpage_base.html override as we are extending from main * Still need to fix gradient color cut and style diffrence between dark and light mode * fix line showing on screen resize * Update CSS styles to fix gradiant without affecting other pages * Fix homepage gradients without the need to override base.html * fix size change on theme toggle * css: show Github stars and forks * fix transform value * css: cleanup rules and refactor duplicates * Update CSS styles to isolate changes to specific pages * fix console warnings * remove 'Home' on frontpage + adjust indentation --------- Co-authored-by: Guillaume Viger --- .../metadata/custom_fields/records.md | 2 +- docs/reference/metadata.md | 4 +- docs/reference/rest_api_drafts_records.md | 2 +- docs/stylesheets/extra.css | 402 +++++++----------- mkdocs.yml | 29 +- theme/features_base.html | 31 +- theme/features_sub.html | 12 +- theme/frontpage.html | 107 +++-- theme/frontpage_base.html | 217 ---------- theme/partials/footer.html | 58 --- theme/partials/social.html | 22 - 11 files changed, 283 insertions(+), 603 deletions(-) delete mode 100644 theme/frontpage_base.html delete mode 100644 theme/partials/footer.html delete mode 100644 theme/partials/social.html diff --git a/docs/customize/metadata/custom_fields/records.md b/docs/customize/metadata/custom_fields/records.md index a912750d..921ce9c2 100644 --- a/docs/customize/metadata/custom_fields/records.md +++ b/docs/customize/metadata/custom_fields/records.md @@ -283,7 +283,7 @@ You should add the `my_template.html` file in the `my-site/templates` folder in - `field_value`: the value of the field, as it is stored in the record after the UI serialization i.e. what is returned from the `ui_field` method when you [define your custom field](../../../develop/howtos/custom_fields.md). - `field_cfg`: the UI configuration for that specific field as it is defined in the `RDM_CUSTOM_FIELDS_UI` config. -See the example in the [How-to](../../../develop/howtos/custom_fields.md#define-the-template-for-the-record-landing-page). +See the example in the [How-to](../../../develop/howtos/custom_fields.md). ### Search diff --git a/docs/reference/metadata.md b/docs/reference/metadata.md index b4383be3..d07554f4 100644 --- a/docs/reference/metadata.md +++ b/docs/reference/metadata.md @@ -117,7 +117,7 @@ External PIDs are persistent identifiers managed via [Invenio-PIDStore](https:// with external registration services. Persistent identifiers are globally unique in the system, thus you cannot have two records -with the same system-managed persistent identifier (see also [Metadata > Identifiers](#identifiers-0-n)). +with the same system-managed persistent identifier (see also [Metadata > Identifiers](#alternate-identifiers-0-n)). You can add a DOI that is not managed by InvenioRDM by using the provider `external`. You are not able to add `external` DOIs that have a prefix that is configured as part of a different PID provider. @@ -1091,7 +1091,7 @@ Example: IIIF links are only returned for files who are compatible with IIIF. Those formats are defined by the `IIIF_FORMATS` configuration variable. By default _gif_, _jp2_, _jpeg_, _jpg_, _png_, _tif_, and _tiff_. - + ### Default preview (0-1) The default preview field names the filename of the file which should by default diff --git a/docs/reference/rest_api_drafts_records.md b/docs/reference/rest_api_drafts_records.md index 4e737079..abf92234 100644 --- a/docs/reference/rest_api_drafts_records.md +++ b/docs/reference/rest_api_drafts_records.md @@ -285,7 +285,7 @@ Content-Type: application/json | Name | Type | Location | Description | | ---------- | ------ | -------- | ------------------------------------------------------------ | | `id` | string | path | Identifier of the record, e.g. `4d0ns-ntd89` | -| `access` | object | body | [Access options](metadata.md#access-information) for the record. | +| `access` | object | body | [Access options](metadata.md#access) for the record. | | `files` | object | body | [Files options](#files-options) for the record. | | `metadata` | object | body | [Metadata](metadata.md#metadata) of the record. | | `custom_fields` | object | body | [Custom fields](../customize/metadata/custom_fields/records.md#declaring-custom-fields) metadata for the record. (v10 and newer) | diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index c358c25f..a679ff8d 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,249 +1,156 @@ -.md-typeset a, -.md-nav__link--active { - color: #000000; - opacity: 0.54; -} - -.md-typeset a:hover, -.md-nav__link:hover { - color: #000000; -} - -.md-nav__title { - color: unset; -} - -.md-typeset table code { - word-break: normal; -} - -[data-md-color-primary="white"] .md-header { - background: linear-gradient( - 90deg, - rgba(3, 119, 205, 1), - rgba(3, 119, 205, 1) 52.52%, - rgba(251, 130, 115, 0.69)) - no-repeat; - color: #ffffff; -} -[data-md-color-primary="white"] .md-tabs { - background: linear-gradient( +/* + Copyright (C) 2018-2024 CERN. + Copyright (C) 2018-2024 Northwestern University. + Copyright (C) 2022-2024 KTH Royal Institute of Technology. + + Invenio is free software; you can redistribute it and/or modify it + under the terms of the MIT License; see LICENSE file for more details. +*/ +/* Color variables +https://github.com/squidfunk/mkdocs-material/blob/master/src/templates/assets/stylesheets/main/_colors.scss +*/ +:root { + --color-invenio: #0377cd; + --color-black: #000000; + --color-white: #ffffff; + --color-gray: #707070; + --color-dark-blue: #003258; + --color-light-coral: rgba(251, 130, 115, 0.69); +} + +[data-md-color-scheme='default'] { + --md-primary-fg-color: var(--color-gray); + --md-primary-fg-color--light: var(--color-invenio); + --md-primary-fg-color--dark: var(--color-dark-blue); + --gradient-header: linear-gradient( 90deg, - rgba(3, 119, 205, 1), - rgba(3, 119, 205, 1) 52.52%, - rgba(251, 130, 115, 0.69)) - no-repeat; - color: #ffffff; -} - -.md-search form.md-search__form { - background-color: rgba(255,255,255, 0.1); - color: #fff; - transition: 0.3 ease-in; -} - -.md-search form.md-search__form:hover { - background-color: rgba(255,255,255, 0.5); - color: rgba(0,0,0,0.54); -} - -.md-search form.md-search__form:hover .md-search__input::placeholder { - color: rgba(0,0,0,0.54); -} - -.md-search form.md-search__form:hover .md-search__icon.md-icon svg { - fill: rgba(0,0,0,0.54); -} - -[data-md-toggle=search]:checked~.md-header .md-search__inner .md-search__icon.md-icon svg { - fill: rgba(0,0,0,0.54); -} - -.md-search form.md-search__form .md-search__input::placeholder { - color: #fff; -} - -.md-search form.md-search__form .md-search__icon.md-icon svg { - fill: #fff; - transition: 0.3s; -} - -.md-header[data-md-state="shadow"] { - box-shadow: none; - border-bottom: 0.05rem solid #ffffff; -} - -.md-header__topic:first-child { - font-weight: unset; -} - -.md-source__facts { - display: none; -} - -.md-logo img { - width: 131px !important; - height: 28px !important; -} - -.md-footer { - border-top: 0.05rem solid #ffffff; - background-color: #0377cd; -} - -.md-footer__link { - padding-top: 0.8rem; - padding-bottom: 0; - color: #ffffff; - opacity: 0.75; - margin-bottom: 0; - margin-top: 0; -} - -.md-footer__direction { - color: #ffffff; - opacity: 0.75; - font-size: .64rem; - left: 0; - position: absolute; - right: 0; - padding: 0 1rem; - margin-top: -1rem; -} - -.md-footer__title { - line-height: 2.4rem; - position: relative; - margin-bottom: 0; -} - -.md-footer .made-with { - color: var(--md-footer-fg-color--lighter); - font-size: .64rem; -} - -.md-footer__link:hover, -.md-footer__direction:hover { - opacity: 1; -} + var(--color-invenio), + var(--color-invenio) 52.52%, + var(--color-light-coral) + ) no-repeat; + + .md-nav__link--active { + color: var(--color-black); + opacity: 0.54; + } -.md-footer-meta { - background-color: rgb(1, 98, 170); -} + .md-typeset a:hover, + .md-nav__link:hover { + color: var(--color-black); + } -html .md-footer-meta .md-footer-meta__inner a { - color: #ffffff; -} + .md-nav__title { + color: unset; + } -.md-footer-meta__inner { - padding: 0 0.2rem; -} + .md-tabs__link { + color: inherit; + } -.md-footer-copyright { - padding: 0.7rem 0; - color: var(--md-footer-fg-color--lighter); - font-size: .64rem; - width: auto; - margin: auto .6rem; -} + .md-header, + .md-tabs { + background: var(--gradient-header); + color: var(--color-white); + } -.md-footer-copyright__highlight { - color: var(--md-footer-fg-color--light); -} + .md-search form.md-search__form { + background-color: rgba(255, 255, 255, 0.1); + color: var(--color-white); + transition: 0.3 ease-in; + } -.md-footer-social { - padding: 0.4rem 0; - margin: 0 .4rem; -} + .md-search form.md-search__form:hover { + color: rgba(0, 0, 0, 0.54); + } -.md-footer-social__link svg { - fill: currentColor; - max-height: .8rem; - vertical-align: -25%; -} + .md-header[data-md-state='shadow'] { + box-shadow: none; + border-bottom: 0.05rem solid var(--color-white); + } -.md-search-result__link[data-md-state="active"] { - background-color: #ffffff; -} + .md-footer { + background-color: var(--color-invenio); + } -.md-typeset h1[id] .headerlink:focus, -.md-typeset h1[id]:hover .headerlink:hover, -.md-typeset h1[id]:target .headerlink, -.md-typeset h2[id] .headerlink:focus, -.md-typeset h2[id]:hover .headerlink:hover, -.md-typeset h2[id]:target .headerlink, -.md-typeset h3[id] .headerlink:focus, -.md-typeset h3[id]:hover .headerlink:hover, -.md-typeset h3[id]:target .headerlink, -.md-typeset h4[id] .headerlink:focus, -.md-typeset h4[id]:hover .headerlink:hover, -.md-typeset h4[id]:target .headerlink, -.md-typeset h5[id] .headerlink:focus, -.md-typeset h5[id]:hover .headerlink:hover, -.md-typeset h5[id]:target .headerlink, -.md-typeset h6[id] .headerlink:focus, -.md-typeset h6[id]:hover .headerlink:hover, -.md-typeset h6[id]:target .headerlink { - color: #0377cd; -} + .rdm-hero-bg { + background: linear-gradient( + 12deg, + rgba(3, 119, 205, 1), + rgba(3, 119, 205, 1) 52.52%, + rgba(251, 130, 115, 0.69) + ); + } -.md-typeset .md-button--primary { - color: #0377cd; -} + .rdm-hero .rdm-hero-subtitle { + color: rgba(255, 255, 255, 0.6); + } -[data-md-color-primary="white"] .md-typeset .md-button.md-button--primary { - background-color: var(--md-primary-fg-color); - border-color: var(--md-primary-fg-color); - color: #0377cd; + body[data-md-color-scheme] .md-main { + background-color: var(--color-white); + } } -[data-md-color-primary="white"] .md-typeset .md-button { - color: var(--md-primary-fg-color); +/* Dark mode */ +/* --------- */ +[data-md-color-scheme='slate'] { + .rdm-hero-bg { + background: linear-gradient( + 12deg, + hsla(205, 99%, 30%, 0.432), + rgba(1, 88, 150, 0.438) 52.52%, + rgba(179, 93, 81, 0.329) + ); + } } -::placeholder { - color: #ffffff; -} +/* Common styles */ +/* ------------- */ -.rdm-toc { - display: flex; - justify-content: center; -} +.rdm-hero { + height: 557px; + text-align: center; + margin-bottom: -2px; -.rdm-toc-item.level1 { - display: inline-flex; -} + > img { + margin-top: 75px; + height: 80px; + } -.rdm-toc-item.level1 > div > a { - font-weight: bolder; -} + > a.md-button:hover { + background-color: var(--color-white); + border-color: var(--color-white); + color: var(--color-invenio); + } -.rdm-toc-item.level1 > div { - width: 200px; + .rdm-hero-subtitle { + font-size: 30px; + font-weight: 300; + font-family: Oswald, 'Open Sans', sans-serif; + margin: 15px 0px 20px 0px; + } } -.rdm-toc-item.level2 { - font-size: small; +.rdm-hero > a.md-button.md-button--primary:hover { + background-color: transparent; + border-color: var(--color-white); + color: var(--color-white); } .rdm-hero-bg { display: block; width: 100%; height: 673px; - background: linear-gradient( - 12deg, - rgba(3, 119, 205, 1), - rgba(3, 119, 205, 1) 52.52%, - rgba(251, 130, 115, 0.69)); position: absolute; top: 0; z-index: -1; } .rdm-hero-bg .wave-svg { + fill: var(--md-default-bg-color); width: 100%; position: absolute; bottom: 0; + transform: translateY(1px); } @media screen and (min-width: 1920px) { @@ -264,74 +171,53 @@ html .md-footer-meta .md-footer-meta__inner a { } } -@media screen and (min-width: 3500px) { - .rdm-hero-bg { - height: 900px; - } -} - -@media screen and (min-width: 4000px) { +@media screen and (min-width: 4500px) { .rdm-hero-bg { - height: 950px; - } -} + height: 1000px; -@media screen and (min-width: 4500px) { - .rdm-hero-bg .wave-svg { - display: none; + .wave-svg { + display: none; + } } } -.rdm-hero { - height: 557px; - text-align: center; - margin-bottom: -2px; -} - -.rdm-hero > img { - margin-top: 75px; - height: 80px; +.md-typeset table code { + word-break: normal; } -.rdm-hero .rdm-hero-subtitle { - font-size: 30px; - font-weight: 300; - font-family: Oswald, "Open Sans", sans-serif; - color: rgba(255, 255, 255, 0.6); - margin: 15px 0px 20px 0px; +.md-typeset .md-button.md-button--primary { + background-color: var(--color-white); + border-color: var(--color-white); + color: var(--color-invenio); + opacity: 100%; } -.rdm-hero > a { - opacity: 1; +.md-typeset .md-button--primary { + color: var(--color-white); + opacity: 100%; } -.rdm-hero > a.md-button.md-button--primary:hover { - background-color: transparent; - border-color: white; - color: white; +.md-typeset .md-button { + color: var(--color-white); } -.rdm-hero > a.md-button:hover { - background-color: white; - border-color: white; - color: #0377cd; +.rdm-toc { + display: flex; + justify-content: center; } -.frontpage .md-main > .md-main__inner, .frontpage .md-main .md-content__inner { - margin-top: 0; - padding-top: 0; +.rdm-toc-item.level1 { + display: inline-flex; } -.frontpage .md-header { - background: transparent; - position: static; +.rdm-toc-item.level1 > div > a { + font-weight: bolder; } -.frontpage .md-tabs { - border-bottom: none; - background: transparent; +.rdm-toc-item.level1 > div { + width: 200px; } -.frontpage .md-main { - background-color: white; +.rdm-toc-item.level2 { + font-size: small; } diff --git a/mkdocs.yml b/mkdocs.yml index 26c77687..9e6d140a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,11 +10,28 @@ copyright: "Copyright © 2019-2024 CERN, Northwestern University and contrib # Configuration theme: - name: "material" - custom_dir: "theme/" + name: material + custom_dir: theme palette: - primary: "white" - accent: "white" + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + primary: custom + accent: custom + extra_css: + - stylesheets/extra.css + toggle: + icon: material/brightness-7 + name: Switch to dark mode + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: black + accent: orange + toggle: + accent: orange + icon: material/brightness-4 + name: Switch to light mode font: false logo: "images/logo-rdm.png" favicon: "images/favicon.svg" @@ -224,8 +241,8 @@ nav: # Customization extra: social: - - icon: "fontawesome/brands/github" - link: "https://github.com/inveniosoftware" + - icon: fontawesome/brands/github + link: https://github.com/inveniosoftware extra_css: - stylesheets/extra.css diff --git a/theme/features_base.html b/theme/features_base.html index e31b0e6b..f9ba4549 100644 --- a/theme/features_base.html +++ b/theme/features_base.html @@ -1,4 +1,14 @@ -{% extends "frontpage_base.html" %} + +{% extends "main.html" %} {% block styles %} {{ super() }} @@ -6,10 +16,25 @@ {% endblock %} -{% block hero %} +{% block tabs %} +{{ super() }} + +
- +
diff --git a/theme/features_sub.html b/theme/features_sub.html index 326905a1..8526e377 100644 --- a/theme/features_sub.html +++ b/theme/features_sub.html @@ -1,4 +1,14 @@ -{% extends "base.html" %} + +{% extends "main.html" %} {% block styles %} {{ super() }} diff --git a/theme/frontpage.html b/theme/frontpage.html index 9f811a1b..320dae51 100644 --- a/theme/frontpage.html +++ b/theme/frontpage.html @@ -1,4 +1,14 @@ -{% extends "frontpage_base.html" %} + +{% extends "main.html" %} {% macro render(nav_item, path, level) %} {% if nav_item.url %} @@ -10,52 +20,81 @@ {% endif %} {% if nav_item.children and level <= 1 %}
  • -
    - - {{ nav_item.title }} - -
      - {% for nav_item in nav_item.children %} - {{ render(nav_item, path ~ "_" ~ loop.index, level + 1) }} - {% endfor %} -
    -
    +
    + {{ nav_item.title }} +
      + {% for nav_item in nav_item.children %} + {{ render(nav_item, path ~ "_" ~ loop.index, level + 1) }} + {% endfor %} +
    +
  • {% else %}
  • {% endif %} {% endmacro %} -{% block hero %} -
    - - - -
    -
    + +{% block tabs %} +{{ super() }} + + + +
    +
    + + + +
    +
    -
    The turn-key research data management repository
    +
    + The turn-key research data management repository +
    Quick start Demo site -
    +
    + {% endblock %} + {% block content %} -{{super()}} - -
      - {% for nav_item in nav %} - {%- if nav_item.title != "Home" %} - {%- set path = "__nav_" ~ loop.index %} - {%- set level = 1 %} - {{render(nav_item, path, level)}} - {%- endif %} - {% endfor %} -
    + +{% if "material/tags" in config.plugins and tags %} + {% include "partials/tags.html" %} +{% endif %} +{% include "partials/actions.html" %} +{{ page.content }} +{% include "partials/source-file.html" %} +
      + {% for nav_item in nav %} + {%- if nav_item.title != "Home" %} + {%- set path = "__nav_" ~ loop.index %} + {%- set level = 1 %} + {{ render(nav_item, path, level) }} + {%- endif %} + {% endfor %} +
    {% endblock %} diff --git a/theme/frontpage_base.html b/theme/frontpage_base.html deleted file mode 100644 index 1cdd5bd0..00000000 --- a/theme/frontpage_base.html +++ /dev/null @@ -1,217 +0,0 @@ -{#- - This file was originally automatically generated, but we edited it to customize the frontpage. --#} -{% import "partials/language.html" as lang with context %} - - - - {% block site_meta %} - - - {% if page and page.meta and page.meta.description %} - - {% elif config.site_description %} - - {% endif %} - {% if page and page.meta and page.meta.keywords %} - - {% elif config.site_keywords %} - - {% endif %} - {% if page and page.meta and page.meta.author %} - - {% elif config.site_author %} - - {% endif %} - {% if page.canonical_url %} - - {% endif %} - - - {% endblock %} - {% block htmltitle %} - {% if page and page.meta and page.meta.title %} - {{ page.meta.title }} - {{ config.site_name }} - {% elif page and page.title and not page.is_homepage %} - {{ page.title | striptags }} - {{ config.site_name }} - {% else %} - {{ config.site_name }} - {% endif %} - {% endblock %} - {% block styles %} - - - - {% endblock %} - {% block libs %}{% endblock %} - {% block fonts %} - {% if config.theme.font != false %} - {% set font = config.theme.font %} - - - - {% endif %} - {% endblock %} - {% if config.extra.manifest %} - - {% endif %} - {% for path in config["extra_css"] %} - - {% endfor %} - {% block analytics %} - {% include "partials/integrations/analytics.html" %} - {% endblock %} - {% block extrahead %}{% endblock %} - - {% set direction = config.theme.direction or lang.t('direction') %} - {% if config.theme.palette %} - {% set palette = config.theme.palette %} - {% if not palette is mapping %} - {% set palette = palette | first %} - {% endif %} - {% set scheme = palette.scheme | replace(" ", "-") | lower %} - {% set primary = palette.primary | replace(" ", "-") | lower %} - {% set accent = palette.accent | replace(" ", "-") | lower %} - {# CHANGE START - added class frontpage #} - - {% else %} - - {% endif %} - {# CHANGE END #} - {% set features = config.theme.features or [] %} - {% include "partials/javascripts/base.html" %} - {% if not config.theme.palette is mapping %} - {% include "partials/javascripts/palette.html" %} - {% endif %} - - - -
    - {% if page.toc | first is defined %} - {% set skip = page.toc | first %} - - {{ lang.t('skip.link.title') }} - - {% endif %} -
    -
    - {% if self.announce() %} - - {% endif %} -
    - {% block header %} - {% include "partials/header.html" %} - {% endblock %} -
    - {# CHANGE START #} - {% block tabs %} - {% if "navigation.tabs" in features %} - {% include "partials/tabs.html" %} - {% endif %} - {% endblock %} - {% block hero %}{% endblock %} - {# CHANGE END #} -
    -
    - {% block site_nav %} - {% if nav %} - {% if page and page.meta and page.meta.hide %} - {% set hidden = "hidden" if "navigation" in page.meta.hide %} - {% endif %} - - {% endif %} - {% if page.toc and not "toc.integrate" in features %} - {% if page and page.meta and page.meta.hide %} - {% set hidden = "hidden" if "toc" in page.meta.hide %} - {% endif %} - - {% endif %} - {% endblock %} -
    -
    - {% block content %} - {# CHANGE START - remove page edit, title#} - {# CHANGE END #} - {{ page.content }} - {% if page and page.meta %} - {% if page.meta.git_revision_date_localized or - page.meta.revision_date - %} - {% include "partials/source-file.html" %} - {% endif %} - {% endif %} - {% endblock %} -
    -
    -
    - {% if "navigation.top" in features %} - - {% include ".icons/material/arrow-up.svg" %} - {{ lang.t('top.title') }} - - {% endif %} -
    - {% block footer %} - {% include "partials/footer.html" %} - {% endblock %} -
    -
    -
    -
    - {% block config %} - {%- set app = { - "base": base_url, - "features": features, - "translations": {}, - "search": "assets/javascripts/workers/search.53c85856.min.js" | url, - "version": config.extra.version or None - } -%} - {%- set translations = app.translations -%} - {%- for key in [ - "clipboard.copy", - "clipboard.copied", - "search.config.lang", - "search.config.pipeline", - "search.config.separator", - "search.placeholder", - "search.result.placeholder", - "search.result.none", - "search.result.one", - "search.result.other", - "search.result.more.one", - "search.result.more.other", - "search.result.term.missing", - "select.version.title" - ] -%} - {%- set _ = translations.update({ key: lang.t(key) }) -%} - {%- endfor -%} - - {% endblock %} - {% block scripts %} - {% for path in config["extra_javascript"] %} - - {% endfor %} - {% endblock %} - - diff --git a/theme/partials/footer.html b/theme/partials/footer.html deleted file mode 100644 index 2314baba..00000000 --- a/theme/partials/footer.html +++ /dev/null @@ -1,58 +0,0 @@ -{% import "partials/language.html" as lang with context %} - diff --git a/theme/partials/social.html b/theme/partials/social.html deleted file mode 100644 index 2e2a16b9..00000000 --- a/theme/partials/social.html +++ /dev/null @@ -1,22 +0,0 @@ -{% if config.extra.social %} - -{% endif %} From 1b140b006de36e2c9e3ea3eab737bf67258f7ec9 Mon Sep 17 00:00:00 2001 From: phette23 Date: Wed, 26 Jun 2024 12:08:43 -0700 Subject: [PATCH 05/13] reference: add file before setting default_preview --- docs/reference/rest_api_drafts_records.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/reference/rest_api_drafts_records.md b/docs/reference/rest_api_drafts_records.md index abf92234..bfc8c533 100644 --- a/docs/reference/rest_api_drafts_records.md +++ b/docs/reference/rest_api_drafts_records.md @@ -29,6 +29,8 @@ Used for interacting with unpublished or edited draft records. | `default_preview`   | string | body | Filename of file to be previewed by default. | | `order` | array | body | Array of filename strings in display order. | +A file must be uploaded to the draft before it can be used as the default +preview. See "[Start a draft file upload](#start-draft-file-uploads)" below. **Request** From 16ff83302456157657231614014970dca84c671b Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Mon, 1 Jul 2024 13:35:01 +0200 Subject: [PATCH 06/13] howto: restrict access to pages * based on IP ranges, in `nginx` --- docs/develop/howtos/restrict_access.md | 52 ++++++++++++++++++++++++++ docs/develop/index.md | 1 + mkdocs.yml | 1 + 3 files changed, 54 insertions(+) create mode 100644 docs/develop/howtos/restrict_access.md diff --git a/docs/develop/howtos/restrict_access.md b/docs/develop/howtos/restrict_access.md new file mode 100644 index 00000000..05d91412 --- /dev/null +++ b/docs/develop/howtos/restrict_access.md @@ -0,0 +1,52 @@ +# How to restrict access to pages + +Sometimes it can be desirable to live by the motto "better safe than sorry", especially regarding potentially sensitive features like the administration panel (enabled in InvenioRDM v12). + +This guide briefly describes how to narrow down access to subsets of the system. + + +## Restricting access for IP ranges via `nginx` + +While most features in InvenioRDM are guarded by configurable permission policies, this isn't necessarily always the case. +For these exceptions, as well as extra precautions generally, it can be beneficial to restrict access on an `nginx` level. + +!!! info "Current exceptions" + At the time of writing, one of these exceptions is the administration panel which has a hard-coded check for the `administration-access` action. + +An access restriction based on the client's IP address can be put into place via the `nginx` configuration, e.g. by adding nested `location` directives in the existing configuration: + +```nginx +location / { + uwsgi_pass ui_server; + include uwsgi_params; + # ... your configuration for the UI paths ... + + # restrict access to the administration panel UI to your network only + location /administration/ { + # action directives like `uwsgi_pass` aren't inherited like other configs + uwsgi_pass ui_server; + + # allow your networks (replace with your IP ranges) + allow 128.130.0.0/15; + allow 192.35.240.0/22; + allow 2001:629::/32; + # etc. + + # also allow localhost and private networks (e.g. for local access through Docker) + allow 127.0.0.1/8; + allow ::1/128; + allow 10.0.0.0/8; + allow 172.16.0.0/12; + allow 192.168.0.0/16; + allow fd00::/8; + + # disallow anybody else + deny all; + } +} +``` + +!!! info "The `uwsgi_pass` directive doesn't get inherited" + Note that the `uwsgi_pass` directive is part of a [class of directives that do not get inherited in nested locations](https://forum.nginx.org/read.php?2,243488,243488) and thus has to be specified explicitly again. + +Restricting access to API endpoints follows a similar schema, but in the `location /api` block and with `uwsgi_pass api_server` instead. diff --git a/docs/develop/index.md b/docs/develop/index.md index 62eca14c..29e4149b 100644 --- a/docs/develop/index.md +++ b/docs/develop/index.md @@ -53,6 +53,7 @@ Step-by-step guides on how to perform certain tasks: - [Fix a vulnerability](howtos/security-fix.md) - [Test emails locally](howtos/dev_email.md) - [Migrate legacy routes](howtos/route_migration.md) +- [Restrict access to pages](howtos/restrict_access.md) ## Architecture diff --git a/mkdocs.yml b/mkdocs.yml index 9e6d140a..1a61dce3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -138,6 +138,7 @@ nav: - Test emails locally: develop/howtos/dev_email.md - Migrate legacy routes: develop/howtos/route_migration.md - Back up search indices: develop/howtos/backup_search_indices.md + - Restrict access to pages: develop/howtos/restrict_access.md - Architecture: - Introduction: develop/architecture/index.md - Infrastructure: develop/architecture/infrastructure.md From 296df87f6a501b428ba80be91e6cb702b997e3ed Mon Sep 17 00:00:00 2001 From: Pablo Tamarit Date: Tue, 9 Jul 2024 15:15:45 +0200 Subject: [PATCH 07/13] vocabularies: names: link to datasets for all years Also fix the case from "ORCiD" to "ORCID". --- docs/customize/vocabularies/names.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/customize/vocabularies/names.md b/docs/customize/vocabularies/names.md index 79e72fa2..2dd4647a 100644 --- a/docs/customize/vocabularies/names.md +++ b/docs/customize/vocabularies/names.md @@ -17,7 +17,7 @@ A _Name_ record contains: are present they will overwrite `name`. - A list of `identifiers`, composed by their identifier value and scheme. The scheme can potentially be autocompleted if it is known by the _idutils_ - library (e.g. ORCiD). + library (e.g. ORCID). - A list of `affiliations`, which can be represented by its `name` or, if it belongs to the _Affiliations_ vocabulary, by its `id`. @@ -96,7 +96,7 @@ invenio vocabularies update \ ### Creating a `names.yaml` file The Names vocabulary has been implemented with the -[ORCiD public dataset](https://orcid.figshare.com/articles/dataset/ORCID_Public_Data_File_2021/16750535?file=31020067) +[ORCID public dataset](https://support.orcid.org/hc/en-us/articles/360006897394-How-do-I-get-the-public-data-file) as a possible source to import entries from. This means that the functionality to **read** entries from this format is already available. For example, you can use the `vocabularies convert` command to convert this dataset into a YAML @@ -112,7 +112,7 @@ invenio vocabularies convert \ Alternatively, you can simply import it directly: !!! warning "Long and blocking operation" - Note that the import process is done synchronously and the ORCiD dataset is + Note that the import process is done synchronously and the ORCID dataset is very large. Therefore, this operation can take a long time. ```bash From 2247f62faebd6226cd9fa9b683b354a165ad4587 Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Wed, 12 Jun 2024 01:12:17 +0200 Subject: [PATCH 08/13] api: update access link example Changed `expires_at` from ISO 8601 DateTime to Date format to fix validation error. --- docs/reference/rest_api_drafts_records.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/rest_api_drafts_records.md b/docs/reference/rest_api_drafts_records.md index bfc8c533..908b6fab 100644 --- a/docs/reference/rest_api_drafts_records.md +++ b/docs/reference/rest_api_drafts_records.md @@ -1679,7 +1679,7 @@ Content-Type: application/json { "permission": "edit", - "expires_at": "2121-03-25T21:06:29.563235" + "expires_at": "2024-12-25" } ``` From 4fb1ee6f99642bd9c768923d201ac4fdf3e9026a Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Wed, 12 Jun 2024 15:10:20 +0200 Subject: [PATCH 09/13] api: update requests update example Removed created_by.user, receiver.community, and topic.record due to Unknown field validation errors. --- docs/reference/rest_api_requests.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/reference/rest_api_requests.md b/docs/reference/rest_api_requests.md index a0c1aa30..4de5f8ad 100644 --- a/docs/reference/rest_api_requests.md +++ b/docs/reference/rest_api_requests.md @@ -80,16 +80,13 @@ PUT /api/requests/{request_id} HTTP/1.1 Content-Type: application/json { - "created_by": {"user": "1"}, "expires_at": null, "id": "{request_id}", "number": "{request_number}", - "receiver": {"user": "2"}, "revision_id": 1, "status": "draft", "title": "A new title", - "topic": {"record": "abcd-1234"}, - "type": "default-request", + "type": "default-request" } ``` From 265b192471bf86e274046bb58363b0cdf6d9c6c6 Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Wed, 12 Jun 2024 15:26:26 +0200 Subject: [PATCH 10/13] api: Update create access link example to use ISO 8601 Date format for expires_at - update response examples for access links --- docs/reference/rest_api_drafts_records.md | 67 ++++++++++++----------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/docs/reference/rest_api_drafts_records.md b/docs/reference/rest_api_drafts_records.md index 908b6fab..86c924dc 100644 --- a/docs/reference/rest_api_drafts_records.md +++ b/docs/reference/rest_api_drafts_records.md @@ -1593,7 +1593,7 @@ Access links are URLs that can be shared with others to give them access and per | -------- | ------ | -------- | ------------------------------------------------------------ | | `id` | string | path | Identifier of the record, e.g. `cbc2k-q9x58` | | `accept` | string | header | - `application/json` (default)
    - `application/vnd.inveniordm.v1+json` | -| `expires_at` | string | body | Date time string. When the link expires. | +| `expires_at` | string | body | `ISO 8601 Date`Format (YYYY-MM-DD) When the link expires. | | `permission` | string | body | Required. Action that can be undertaken with the link (``view``, ``preview`` or ``edit``). | @@ -1604,7 +1604,8 @@ POST /api/records/{id}/access/links HTTP/1.1 Content-Type: application/json { - "permission": "view" + "permission": "view", + "expires_at": "2024-11-06" } ``` @@ -1615,11 +1616,12 @@ HTTP/1.1 201 CREATED Content-Type: application/json { - "permission": "view", - "created_at": "2021-03-25T21:06:29.563235", - "token": "eyJhbGciOiJIUzUxMiJ9.eyJpZCI6IjNkMzMyMGVhLTA3NTUtNGQ5My1hNzZlLWUyZjJmYzY1NWQyYSIsImRhdGEiOnt9LCJyYW5kb20iOiI2NzZhYTk3OTczMzgwMjkyNTJiM2MwZDBjNjliMTVkYSJ9.dBqk7YzIZ7kwG4oijNgH1VU-cjQmBiQlMQKMoB2y-YjVWmgnZetFAESsqRP6VpGTtaKdftrtob1PVZJF4YGpfg", - "id": "3d3320ea-0755-4d93-a76e-e2f2fc655d2a", - "expires_at": null + "id": "07fb00f3-928c-4ce9-8d2e-8e9c4dca3092", + "created_at": "2024-06-12T13:07:09.951029+00:00", + "expires_at": "2024-11-06", + "permission": "view", + "description": "", + "token": "eyJhbGciOiJIUzUxMiIsImlhdCI6MTcxODE5NzYyOSwiZXhwIjoxNzMwODUxMTk5fQ.eyJpZCI6IjA3ZmIwMGYzLTkyOGMtNGNlOS04ZDJlLThlOWM0ZGNhMzA5MiIsImRhdGEiOnt9LCJyYW5kb20iOiI1NzVjNzEwY2QwNWI3YWFhMTM2MzY3ZmMzZWFkYzA0MSJ9.GPfPBvrbvEu-JMddFXjb5MZKNWRnzAK53oTVOSgfdZOcMIoRfszO39GEglko74dohZiUcJ11jWXj0fwfdq1WnQ" } ``` @@ -1649,11 +1651,12 @@ HTTP/1.1 200 OK Content-Type: application/json { - "permission": "view", - "created_at": "2021-03-25T21:06:29.563235", - "token": "eyJhbGciOiJIUzUxMiJ9.eyJpZCI6IjNkMzMyMGVhLTA3NTUtNGQ5My1hNzZlLWUyZjJmYzY1NWQyYSIsImRhdGEiOnt9LCJyYW5kb20iOiI2NzZhYTk3OTczMzgwMjkyNTJiM2MwZDBjNjliMTVkYSJ9.dBqk7YzIZ7kwG4oijNgH1VU-cjQmBiQlMQKMoB2y-YjVWmgnZetFAESsqRP6VpGTtaKdftrtob1PVZJF4YGpfg", - "id": "3d3320ea-0755-4d93-a76e-e2f2fc655d2a", - "expires_at": null + "id": "61c2d20f-4c88-440d-9978-dd16a69bf97e", + "created_at": "2024-06-12T13:23:11.271139+00:00", + "expires_at": "2024-11-06", + "permission": "view", + "description": "", + "token": "eyJhbGciOiJIUzUxMiIsImlhdCI6MTcxODE5ODU5MSwiZXhwIjoxNzMwODUxMTk5fQ.eyJpZCI6IjYxYzJkMjBmLTRjODgtNDQwZC05OTc4LWRkMTZhNjliZjk3ZSIsImRhdGEiOnt9LCJyYW5kb20iOiI2MWYwZTg4YjgzY2E2ZDhkMjJiMTY0MGFjNmIzMmEwZiJ9.AFEmgQ8_gtEj7dvlZ2MHD9qneKy0UEC1HMByo8J5xVGMYG8PXwuRsyUgeq_k_ZeHybO5W4_Do_P4NVGXsrjHyg" } ``` @@ -1665,10 +1668,10 @@ Content-Type: application/json | Name | Type | Location | Description | | -------- | ------ | -------- | ------------------------------------------------------------ | -| `id` | string | path | Identifier of the record, e.g. `cbc2k-q9x58` | -| `link-id` | string | path | Identifier of the link, e.g. `3d3320ea-0755-4d93-a76e-e2f2fc655d2a` | +| `id` | string | path | Identifier of the record, e.g. `cbc2k-q9x58` | +| `link-id` | string | path | Identifier of the link, e.g. `3d3320ea-0755-4d93-a76e-e2f2fc655d2a` | | `accept` | string | header | - `application/json` (default)
    - `application/vnd.inveniordm.v1+json` | -| `expires_at` | string | body | Date time string. When the link expires. | +| `expires_at` | string | body | `ISO 8601 Date`Format (YYYY-MM-DD) When the link expires. | | `permission` | string | body | Required. Action that can be undertaken with the link. | **Request** @@ -1679,7 +1682,7 @@ Content-Type: application/json { "permission": "edit", - "expires_at": "2024-12-25" + "expires_at": "2024-11-06" } ``` @@ -1690,11 +1693,12 @@ HTTP/1.1 200 OK Content-Type: application/json { - "permission": "edit", - "created_at": "2021-03-25T21:06:29.563235", - "token": "eyJhbGciOiJIUzUxMiJ9.eyJpZCI6IjNkMzMyMGVhLTA3NTUtNGQ5My1hNzZlLWUyZjJmYzY1NWQyYSIsImRhdGEiOnt9LCJyYW5kb20iOiI2NzZhYTk3OTczMzgwMjkyNTJiM2MwZDBjNjliMTVkYSJ9.dBqk7YzIZ7kwG4oijNgH1VU-cjQmBiQlMQKMoB2y-YjVWmgnZetFAESsqRP6VpGTtaKdftrtob1PVZJF4YGpfg", - "id": "3d3320ea-0755-4d93-a76e-e2f2fc655d2a", - "expires_at": "2121-03-25T21:06:29.563235" + "id": "df672812-6b23-411a-b40a-9bb22787f0a2", + "created_at": "2024-06-12T12:48:43.724970+00:00", + "expires_at": "2024-11-06", + "permission": "edit", + "description": "", + "token": "eyJhbGciOiJIUzUxMiJ9.eyJpZCI6ImRmNjcyODEyLTZiMjMtNDExYS1iNDBhLTliYjIyNzg3ZjBhMiIsImRhdGEiOnt9LCJyYW5kb20iOiIwZWE3ZWQ5YTBiZTE3N2ZjMjE4YjNjYzY3M2RiOTI5OSJ9.kqJ_gTvgjEc_-1Jxv-XHqSCUmOpcQDdBzx-T5BP7ybvQItK91wGxmVT_gfHxyHHDQ_7e8_LH1A5TotAZCA8q_w" } ``` @@ -1749,16 +1753,17 @@ Content-Type: application/json { "hits": { - "hits": [ - { - "permission": "view", - "id": "140f69c9-a8a5-41d4-8ae2-3dfbfe0e2796", - "created_at": "2021-03-25T21:48:03.289198", - "expires_at": null, - "token": "eyJhbGciOiJIUzUxMiJ9.eyJpZCI6IjE0MGY2OWM5LWE4YTUtNDFkNC04YWUyLTNkZmJmZTBlMjc5NiIsImRhdGEiOnt9LCJyYW5kb20iOiI2NzE3MmY4MTNkYzhkNGJjZDAwOWFlOTlhOWM3NjU1MSJ9.1O9MwTmt_nfvsCm4qvlkUH0Rpe5bK3hT422A879DJSblOCONsNxPe_feNHrgTV3s6ZA6t6vLziXjhAwgKjHhIQ" - } - ], - "total": 1 + "hits": [ + { + "id": "61c2d20f-4c88-440d-9978-dd16a69bf97e", + "created_at": "2024-06-12T13:23:11.271139+00:00", + "expires_at": "2024-11-06", + "permission": "edit", + "description": "", + "token": "eyJhbGciOiJIUzUxMiIsImlhdCI6MTcxODE5ODU5MSwiZXhwIjoxNzMwODUxMTk5fQ.eyJpZCI6IjYxYzJkMjBmLTRjODgtNDQwZC05OTc4LWRkMTZhNjliZjk3ZSIsImRhdGEiOnt9LCJyYW5kb20iOiI2MWYwZTg4YjgzY2E2ZDhkMjJiMTY0MGFjNmIzMmEwZiJ9.AFEmgQ8_gtEj7dvlZ2MHD9qneKy0UEC1HMByo8J5xVGMYG8PXwuRsyUgeq_k_ZeHybO5W4_Do_P4NVGXsrjHyg" + } + ], + "total": 1 } } ``` From 3768eaf0987d3d55b1b24c57576fcffe8dd07cb7 Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Thu, 13 Jun 2024 01:32:28 +0200 Subject: [PATCH 11/13] api: Update start_date parameter description --- docs/reference/rest_api_communities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/rest_api_communities.md b/docs/reference/rest_api_communities.md index 1228c33b..11f64390 100644 --- a/docs/reference/rest_api_communities.md +++ b/docs/reference/rest_api_communities.md @@ -779,7 +779,7 @@ Content-Type: application/json |----------------|--------|----------|-----------------------------------------------------------------------------------------------| | `accept` | string | header | - `application/json` (default)
    - `application/vnd.inveniordm.v1+json` | | `community_id` | string | path | ID of the community. | -| `start_date` | string | body | Required, datetime in iso format. Community will be featured from this point in time onwards. | +| `start_date` | string | body | Required, ISO 8601 DateTime format in UTC (YYYY-MM-DDTHH:MM:SS.ssssssZ). Community will be featured from this point in time onwards. | **Request** From 4b034c44f3521a9e2560f437a4647ae374120339 Mon Sep 17 00:00:00 2001 From: Martin Obersteiner Date: Tue, 11 Jun 2024 13:15:10 +0200 Subject: [PATCH 12/13] customization: instructions for changing menus --- .../img/communities-dashboard.png | Bin 0 -> 29967 bytes .../look-and-feel/img/settings-menu.png | Bin 0 -> 10336 bytes .../look-and-feel/img/user-dashboard.png | Bin 0 -> 25311 bytes docs/customize/look-and-feel/menus.md | 144 ++++++++++++++++++ mkdocs.yml | 1 + 5 files changed, 145 insertions(+) create mode 100644 docs/customize/look-and-feel/img/communities-dashboard.png create mode 100644 docs/customize/look-and-feel/img/settings-menu.png create mode 100644 docs/customize/look-and-feel/img/user-dashboard.png create mode 100644 docs/customize/look-and-feel/menus.md diff --git a/docs/customize/look-and-feel/img/communities-dashboard.png b/docs/customize/look-and-feel/img/communities-dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..7e04b1c734e474a3d914795ece3980ba15097b09 GIT binary patch literal 29967 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 z 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 TR+o7}zpAHWcrNSA?Fat_cb)1% literal 0 HcmV?d00001 diff --git a/docs/customize/look-and-feel/img/settings-menu.png b/docs/customize/look-and-feel/img/settings-menu.png new file mode 100644 index 0000000000000000000000000000000000000000..76a4950c95e9c33ef2286e4734f9003e5b3b6960 GIT binary patch literal 10336 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 must be of type `callable[[], bool]`
    - `CONDITION_TRUE` is just a named `lambda: True`
    - use `CONDITION_FALSE` to hide a submenu | +| ... | ... | in addtion to the above properties, all arguments for `flask_menu.menu:MenuNode.register` are configurable | + +For an example consider the user-dashboard pictured above. +Its *Uploads* submenu has the following default configuration: +```python +{ + "endpoint": "invenio_app_rdm_users.uploads", + "order": 1, # small number as to show this submenu left-most + "text": _("Uploads"), + "visible_when": flask_menu.menu.CONDITION_TRUE, # always show this submenu + ..., # advanced configuration properties omitted for brevity +} +``` + +## Add new submenus to existing menu + +Existing menus can be extended by custom-configured submenus. +To add a new submenu to an existing menu: + +1. get the name of the to-be-added-to menu from the [list of menus](#list-of-menus) + For example, the user-dashboard is named `"dashboard"` (most names of menus/submenus are straightforward). +2. write a function that registers the new submenu + ```python + # ext.py # ext.py is commonly used, you may use another file though + + from flask_menu import current_menu + from invenio_i18n import lazy_gettext as _ # for translations + + def finalize_app(): + # get the user-dashboard menu via its name "dashboard": + user_dashboard_menu = current_menu.submenu("dashboard") + + # register a new submenu to the user-dashboard: + user_dashboard_menu.register( + "name-of-submenu", + endpoint="my_blueprint.my_endpoint", + order=4, # the three already existing submenus have `order` 1 through 3 + text=_("Title of new Submenu"), # could also use an untranslated bare string + # note: could add other properties here, otherwise their default is used + # note: `visible_when` defaults to always visible + ) + + ... # could .register more submenus here (or do so in another package) + ``` +3. have the endpoint `invenio_base.finalize_app` point at your function + This will make your function be called at the app-finalization build-step. + For example, when using setuptools' `setup.cfg` with your python-package, add: + ```ini + # setup.cfg + + [options.entry_points] + invenio_base.finalize_app = + my_package_name = my_package_name.ext:finalize_app + ``` + +!!! info "For entrypoints to take effect" + For entrypoint changes to be picked up, you will need to reinstall the python package. + *This is necessary even if the package is installed editably!* + +!!! info "Have you tried to turn it off and on again?" + After entrypoint changes were picked up, + you will further need to restart the server for changes to take effect: + ```shell + + invenio-cli run + ``` + +## Modify existing submenus + +The defaults of submenus' properties are selectively overridable via config-variables. +To modify an existing submenu's properties: + +1. find the name of the corresponding override-variable in the [list of menus](#list-of-menus) + For example, the override-variable for the user-dashboard is named `USER_DASHBOARD_MENU_OVERRIDES`. +2. find the name of the to-be-overridden submenu in that same [list of menus](#list-of-menus) + For example, the user-dashboard has a submenu for communities. + This submenu is named (obviously enough) `"communities"`. +3. add to your `invenio.cfg`: + ```python + # invenio.cfg + + from flask_menu.menu import CONDITION_FALSE + + USER_DASHBOARD_MENU_OVERRIDES = { + "communities": { + "visible_when": CONDITION_FALSE, + # other properties will be left unchanged + } + # other submenus will be left unchanged + } + ``` + +The above example hides the *Communities* submenu from the user-dashboard menu +by overriding its `visible_when` property. +For other overridable properties see [configurable properties](#configurable-properties). + +!!! info "Have you tried to turn it off and on again?" + You will need to restart the server for changes to take effect: + ```shell + + invenio-cli run + ``` + +!!! warning "On overriding user-added submenus: DON'T" + Currently, (sub)menu-overrides are adopted at app-finalization. + Users adding their own submenus (as described above) is also done at app-finalization. + Hence attempting to override submenus added by (other) users depends on + loading order of app-finalization entrypoints and might break anytime. + +## List of menus + +The following list of menus is non-exhaustive. +Not all menus are overridable, but all menus can be extended by additional submenus. + +| Image | Description | Name of menu and its submenus | Name of override-variable | +|-------|-------------|-------------------------------|---------------------------| +| ![User's personal dashboard with three tabs labeled (left-to-right) "Uploads", "Communities", and "Requests"](./img/user-dashboard.png) | Dashboard on user's personal page | `"dashboard"`
    ├─`"uploads"`
    ├─`"communities"`
    └─`"requests"` | `USER_DASHBOARD_MENU_OVERRIDES` | +| ![Communities dashboard with its 6 default tabs](./img/communities-dashboard.png) | Dashboard on communities page | `"communities"`
    ├─`"home"`
    ├─`"search"`
    ├─`"requests"`
    ├─`"submit"`
    ├─`"members"`
    ├─`"settings"`
    ├─`"curation_policy"`
    └─`"about"` | No associated override-variable | +| ![User-settings menu with its 5 default entries](./img/settings-menu.png) | User settings menu | `"settings"`
    ├─`"profile"`
    ├─`"change_password"`
    ├─`"security"`
    ├─`"notifications"`
    ├─`"oauthclient"`
    └─`"applications"` | No associated override-variable | diff --git a/mkdocs.yml b/mkdocs.yml index 1a61dce3..c8e4262b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -72,6 +72,7 @@ nav: - Change templates: "customize/look-and-feel/templates.md" - Change theme: "customize/look-and-feel/theme.md" - Change font: "customize/look-and-feel/font.md" + - Change menus: "customize/look-and-feel/menus.md" - Authentication: "customize/authentication.md" - Sending emails: "customize/emails.md" - Search: From f4738cdb57e7dd739d49d69bff8b5eb2b2cbb4f4 Mon Sep 17 00:00:00 2001 From: Guillaume Viger Date: Wed, 10 Jul 2024 09:44:52 -0400 Subject: [PATCH 13/13] customizations: enhance menu customization docs --- docs/customize/look-and-feel/menus.md | 40 +++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/docs/customize/look-and-feel/menus.md b/docs/customize/look-and-feel/menus.md index bf68026d..75bf7569 100644 --- a/docs/customize/look-and-feel/menus.md +++ b/docs/customize/look-and-feel/menus.md @@ -1,10 +1,17 @@ -# Change Menus +# Change Menus/Tabs + +For navigation, InvenioRDM often uses menus or tabs. For example, one such menu is the user-dropdown menu: + +![User-settings menu with its 5 default entries](./img/settings-menu.png) + +And one such set of tabs is at the top of the user-dashboard: -For navigation, InvenioRDM uses *menu*s. For example, one such menu is at the -top of the dashboard shown to users on their personal page (with submenus -*Uploads*, *Communities*, and *Requests*): ![User's personal dashboard with three tabs labeled (left-to-right) "Uploads", "Communities", and "Requests"](./img/user-dashboard.png) -Menus are configurable in the following ways: + +In the codebase, menus and sets of tabs like those are referred as *menus*, so we do so here for the remainder of this how-to as well. +Their options (e.g., "Uploads", "Profile") are referred as *submenus*. + +These *menus* can be configured in the following ways: - which submenus to show - what title-text to show in those submenus @@ -13,9 +20,9 @@ Menus are configurable in the following ways: ## Configurable Properties -All submenus share the following properties. Properties of existing submenus can be overridden, properties of newly added submenus can be freely chosen. +All submenus share the following properties: | Name | Example values | Notes | |----------------|--------------------------------------|-----------------------------------------------------| @@ -25,7 +32,7 @@ properties of newly added submenus can be freely chosen. | `visible_when` | `flask_menu.menu.CONDITION_TRUE` | when to show this submenu
    - must be of type `callable[[], bool]`
    - `CONDITION_TRUE` is just a named `lambda: True`
    - use `CONDITION_FALSE` to hide a submenu | | ... | ... | in addtion to the above properties, all arguments for `flask_menu.menu:MenuNode.register` are configurable | -For an example consider the user-dashboard pictured above. +For example, consider the user-dashboard pictured above. Its *Uploads* submenu has the following default configuration: ```python { @@ -42,9 +49,9 @@ Its *Uploads* submenu has the following default configuration: Existing menus can be extended by custom-configured submenus. To add a new submenu to an existing menu: -1. get the name of the to-be-added-to menu from the [list of menus](#list-of-menus) +1. Get the name of the to-be-added-to menu from the [list of menus](#list-of-menus) For example, the user-dashboard is named `"dashboard"` (most names of menus/submenus are straightforward). -2. write a function that registers the new submenu +2. Write a function that registers the new submenu ```python # ext.py # ext.py is commonly used, you may use another file though @@ -67,9 +74,9 @@ To add a new submenu to an existing menu: ... # could .register more submenus here (or do so in another package) ``` -3. have the endpoint `invenio_base.finalize_app` point at your function - This will make your function be called at the app-finalization build-step. - For example, when using setuptools' `setup.cfg` with your python-package, add: +3. Register your function with the `invenio_base.finalize_app` entrypoint. + This will make your function be called at the app-finalization build-step. + For example, when using setuptools' `setup.cfg` with your python package, add: ```ini # setup.cfg @@ -82,8 +89,7 @@ To add a new submenu to an existing menu: For entrypoint changes to be picked up, you will need to reinstall the python package. *This is necessary even if the package is installed editably!* -!!! info "Have you tried to turn it off and on again?" - After entrypoint changes were picked up, + After entrypoint changes are picked up, you will further need to restart the server for changes to take effect: ```shell @@ -95,12 +101,12 @@ To add a new submenu to an existing menu: The defaults of submenus' properties are selectively overridable via config-variables. To modify an existing submenu's properties: -1. find the name of the corresponding override-variable in the [list of menus](#list-of-menus) +1. Find the name of the corresponding override-variable in the [list of menus](#list-of-menus) For example, the override-variable for the user-dashboard is named `USER_DASHBOARD_MENU_OVERRIDES`. -2. find the name of the to-be-overridden submenu in that same [list of menus](#list-of-menus) +2. Find the name of the to-be-overridden submenu in that same [list of menus](#list-of-menus) For example, the user-dashboard has a submenu for communities. This submenu is named (obviously enough) `"communities"`. -3. add to your `invenio.cfg`: +3. Add to your `invenio.cfg`: ```python # invenio.cfg