diff --git a/README.md b/README.md
index fe94dccc56540c4daa1d36266b9fe1b64f8e2659..edbcea40e6977f927b4922fd0ed82a7db9459172 100644
--- a/README.md
+++ b/README.md
@@ -60,8 +60,8 @@ in development.
    From the gui project root folder:
 
    ```sh
-   python3.11 -m venv .pyenv
-   source .pyenv/bin/activate
+   python3.11 -m venv .venv
+   source .venv/bin/activate
    pip install uv
    uv pip install --upgrade pip
    uv pip install -e infra \
@@ -79,20 +79,18 @@ in development.
 
 3. Run the required infrastructure services. Typically you will run them through a `docker-compose.yaml` file that is part of your development setup.
 
-
 4. Run NOMAD. Run from the `infra` directory it has the necessary `nomad.yaml` file:
 
    ```sh
    cd infra
    nomad admin run appworker
-   ````
+   ```
 
 5. Upload some data. Again, mind the directory. Run from `infra`.
 
    ```sh
    cd infra
-   nomad client upload --upload-name demo-schema --ignore-path-prefix data/demo-schema
-   nomad client upload --upload-name entry-data --ignore-path-prefix  data/entry-data
+   nomad client upload --upload-name demo-schema --ignore-path-prefix src/nomad_plugin_gui/example_uploads/ui_demonstration
    nomad client upload --upload-name upload-navigation data/upload-navigation.zip
    ```
 
diff --git a/docs/Archive.mdx b/docs/Archive.mdx
index bd32a9b965d003da4ea632a4920231f0fffd40e6..e0a08939b97f1de11e6532d6de30a4b7207e0e2d 100644
--- a/docs/Archive.mdx
+++ b/docs/Archive.mdx
@@ -4,7 +4,6 @@ To show and edit processed data and data from `archive.json` raw-files (e.g. "ar
 we provide some functionality to manage archive data in the UI. This
 functionality can be use via the `useArchive` hook.
 
-
 ## Goals
 
 - load and maintain partial archives, successively update them with subsequent
@@ -13,14 +12,12 @@ functionality can be use via the `useArchive` hook.
 - tracking changes to the archive data and allowing to save changes back to the
   API
 
-
 ## Basic usage
 
 There are several hooks to interact with the archive. In any case, the archive
 is always tight to the current entry. Where the current entry is determined
 based on the current route.
 
-
 ### useArchive
 
 This hook gives you access to the archive object. See also the doc strings
@@ -32,10 +29,8 @@ const archive = useArchive()
 
 const onFetch = useCallback(
   (data: EntryResponse) => {
-    archive.updateArchive(
-      request.archive as MSectionRequest,
-      data?.archive as MSectionResponse,
-    )
+    archive.startUpdate(request.archive as MSectionRequest)
+    archive.commitUpdate(data?.archive as MSectionResponse)
   },
   [archive, request],
 )
@@ -66,9 +61,8 @@ propery within the archive. The path segments are names of sub-sections and
 quantities; numbers are used for indexing repeating sub-sections. As such
 paths should be mostly compatible with the graph API and Metainfo references.
 
-
 ### useArchiveChanges
 
 This hooks provides access to the changes made to the archive. When a
 property is changed via `useArchiveProperty(path).change(...)`, the change is
-tracked and stored in a stack of changes.
\ No newline at end of file
+tracked and stored in a stack of changes.
diff --git a/infra/README.md b/infra/README.md
index 547c72d16ec74dd1b10dd978c49a821ca1adbdfa..ad24c8e259d0eaccea74a187c2aeacab8c7c67d8 100644
--- a/infra/README.md
+++ b/infra/README.md
@@ -10,8 +10,8 @@ This is how you run NOMAD, upload some data, and start using the GUI with it:
    From the gui project root folder:
 
 ```sh
-python3.11 -m venv .pyenv
-source .pyenv/bin/activate
+python3.11 -m venv .venv
+source .venv/bin/activate
 pip install uv
 uv pip install --upgrade pip
 uv pip install -e infra \
diff --git a/infra/nomad.yaml b/infra/nomad.yaml
index 48639927c8f6e5933d578b70dfe8d9a3e0959f27..d333579c4e1c62d06a0b344d176ed7de6acc7b51 100644
--- a/infra/nomad.yaml
+++ b/infra/nomad.yaml
@@ -1,7 +1,6 @@
 keycloak:
-  server_url: 'http://keycloak:8080/'
+  server_url: 'https://nomad-lab.eu/fairdi/keycloak/auth/'
   realm_name: 'fairdi_nomad_test'
-  public_server_url: 'http://localhost:8080/'
 services:
   admin_user_id: 'c97facc2-92ec-4fa6-80cf-a08ed957255b'
 client:
diff --git a/infra/pyproject.toml b/infra/pyproject.toml
index 15b2168dd1cd26ce1a3f2ab6a5c6c795071284fb..3508134fd43a727b4ec4c170026228ddf76b84ce 100644
--- a/infra/pyproject.toml
+++ b/infra/pyproject.toml
@@ -6,11 +6,11 @@ build-backend = "setuptools.build_meta"
 name = "nomad-plugin-gui"
 description = "The NOMAD plugin for the new NOMAD GUI."
 authors = [
-    { name = "NOMAD Laboratory", email = 'markus.scheidgen@physik.hu-berlin.de' },
+  { name = "NOMAD Laboratory", email = 'markus.scheidgen@physik.hu-berlin.de' },
 ]
 dynamic = ["version"]
 requires-python = ">=3.9"
-dependencies = ["nomad-lab[parsing,infrastructure]>=1.3.4"]
+dependencies = ["nomad-lab[parsing,infrastructure]==1.3.13"]
 [project.optional-dependencies]
 dev = ["pytest"]
 
@@ -69,4 +69,4 @@ gui_api = "nomad_plugin_gui.apis:gui_api"
 demo_schema = "nomad_plugin_gui.schema_packages:demo_schema"
 values_test_schema = "nomad_plugin_gui.schema_packages:values_test_schema"
 excercise_schema = "nomad_plugin_gui.schema_packages:exercise_schema"
-ui_demonstration_example_upload = "nomad_plugin_gui.example_uploads:ui_demonstration_example_upload"
\ No newline at end of file
+ui_demonstration_example_upload = "nomad_plugin_gui.example_uploads:ui_demonstration_example_upload"
diff --git a/infra/src/nomad_plugin_gui/example_uploads/ui_demonstration/entry-data.archive.yaml b/infra/src/nomad_plugin_gui/example_uploads/ui_demonstration/entry-data.archive.yaml
index b78a6314081e645f20a260f9763ea4d845e1f4a4..2ae880cdddd0f949cef4bb59091bc338f99721dc 100644
--- a/infra/src/nomad_plugin_gui/example_uploads/ui_demonstration/entry-data.archive.yaml
+++ b/infra/src/nomad_plugin_gui/example_uploads/ui_demonstration/entry-data.archive.yaml
@@ -19,3 +19,14 @@ data:
     unit_quantity: 'm'
     section_reference: '#/data/referenced'
   referenced: {}
+  sub_section: {
+    string_quantity: 'Hello World'
+  }
+  repeated_sub_section: [
+    {
+      string_quantity: 'Hello World'
+    },
+    {
+      string_quantity: 'Hello World'
+    }
+  ]
diff --git a/infra/src/nomad_plugin_gui/schema_packages/values_test_schema.py b/infra/src/nomad_plugin_gui/schema_packages/values_test_schema.py
index 8897d6379b41abf5f9653416faec2c68a1d42668..8bcd161f2c0edebfd488fbb488b08b08bf028518 100644
--- a/infra/src/nomad_plugin_gui/schema_packages/values_test_schema.py
+++ b/infra/src/nomad_plugin_gui/schema_packages/values_test_schema.py
@@ -53,9 +53,15 @@ class QuantityTypes(MSection):
 
     section_reference = Quantity(type=Reference(Referenced))
 
+class ASection(MSection):
+    string_quantity = Quantity(type=str)
 
 class Main(Schema):
     quantity_types = SubSection(sub_section=QuantityTypes)
+    sub_section = SubSection(sub_section=ASection)
+    repeated_sub_section = SubSection(sub_section=ASection, repeats=True)
+    empty_sub_section = SubSection(sub_section=ASection)
+    empty_repeated_sub_section = SubSection(sub_section=ASection, repeats=True)
     referenced = SubSection(sub_section=Referenced)
 
 
diff --git a/public/config.js b/public/config.js
index 9d8981b01c147582618b1187c0bcc3aa3db0fb78..6ed1474f201bb4bbe8b47a51c57ad234e9405d92 100644
--- a/public/config.js
+++ b/public/config.js
@@ -1 +1 @@
-window.nomadConfig = {"keycloak": {"realm_name": "fairdi_nomad_test", "client_id": "nomad_public", "public_server_url": "http://localhost:8080"}, "services": {"console_log_level": 30, "api_host": "localhost", "api_port": 8000, "api_base_path": "/fairdi/nomad/latest", "api_secret": "defaultApiSecret", "api_timeout": 600, "https": false, "https_upload": false, "admin_user_id": "c97facc2-92ec-4fa6-80cf-a08ed957255b", "encyclopedia_base": "https://nomad-lab.eu/prod/rae/encyclopedia/#", "optimade_enabled": true, "dcat_enabled": true, "h5grove_enabled": true, "upload_limit": 10, "force_raw_file_decoding": false, "max_entry_download": 50000, "unavailable_value": "unavailable", "app_token_max_expires_in": 2592000, "html_resource_http_max_age": 60, "image_resource_http_max_age": 2592000, "upload_members_group_search_enabled": false, "log_api_queries": true}, "ui": {"unit_systems": {"items": [{"label": "Custom", "units": {"angle": {"definition": "\u00b0", "locked": false}, "energy": {"definition": "eV", "locked": false}, "length": {"definition": "\u00c5", "locked": false}, "pressure": {"definition": "GPa", "locked": false}, "time": {"definition": "fs", "locked": false}, "dimensionless": {"definition": "dimensionless", "locked": false}, "mass": {"definition": "kg", "locked": false}, "current": {"definition": "A", "locked": false}, "temperature": {"definition": "K", "locked": false}, "luminosity": {"definition": "cd", "locked": false}, "luminous_flux": {"definition": "lm", "locked": false}, "substance": {"definition": "mol", "locked": false}, "information": {"definition": "bit", "locked": false}, "force": {"definition": "N", "locked": false}, "power": {"definition": "W", "locked": false}, "charge": {"definition": "C", "locked": false}, "resistance": {"definition": "\u03a9", "locked": false}, "conductance": {"definition": "S", "locked": false}, "inductance": {"definition": "H", "locked": false}, "magnetic_flux": {"definition": "Wb", "locked": false}, "magnetic_field": {"definition": "T", "locked": false}, "frequency": {"definition": "Hz", "locked": false}, "luminance": {"definition": "nit", "locked": false}, "illuminance": {"definition": "lx", "locked": false}, "electric_potential": {"definition": "V", "locked": false}, "capacitance": {"definition": "F", "locked": false}, "activity": {"definition": "kat", "locked": false}}, "id": "Custom"}, {"label": "International System of Units (SI)", "units": {"activity": {"definition": "kat", "locked": true}, "angle": {"definition": "rad", "locked": true}, "capacitance": {"definition": "F", "locked": true}, "charge": {"definition": "C", "locked": true}, "conductance": {"definition": "S", "locked": true}, "current": {"definition": "A", "locked": true}, "dimensionless": {"definition": "dimensionless", "locked": true}, "electric_potential": {"definition": "V", "locked": true}, "energy": {"definition": "J", "locked": true}, "force": {"definition": "N", "locked": true}, "frequency": {"definition": "Hz", "locked": true}, "illuminance": {"definition": "lx", "locked": true}, "inductance": {"definition": "H", "locked": true}, "information": {"definition": "bit", "locked": true}, "length": {"definition": "m", "locked": true}, "luminance": {"definition": "nit", "locked": true}, "luminosity": {"definition": "cd", "locked": true}, "luminous_flux": {"definition": "lm", "locked": true}, "magnetic_field": {"definition": "T", "locked": true}, "magnetic_flux": {"definition": "Wb", "locked": true}, "mass": {"definition": "kg", "locked": true}, "power": {"definition": "W", "locked": true}, "pressure": {"definition": "Pa", "locked": true}, "resistance": {"definition": "\u03a9", "locked": true}, "substance": {"definition": "mol", "locked": true}, "temperature": {"definition": "K", "locked": true}, "time": {"definition": "s", "locked": true}}, "id": "SI"}, {"label": "Hartree atomic units (AU)", "units": {"activity": {"definition": "kat", "locked": false}, "angle": {"definition": "rad", "locked": false}, "capacitance": {"definition": "F", "locked": false}, "charge": {"definition": "C", "locked": false}, "conductance": {"definition": "S", "locked": false}, "current": {"definition": "atomic_unit_of_current", "locked": true}, "dimensionless": {"definition": "dimensionless", "locked": true}, "electric_potential": {"definition": "V", "locked": false}, "energy": {"definition": "Ha", "locked": true}, "force": {"definition": "atomic_unit_of_force", "locked": true}, "frequency": {"definition": "Hz", "locked": false}, "illuminance": {"definition": "lx", "locked": false}, "inductance": {"definition": "H", "locked": false}, "information": {"definition": "bit", "locked": false}, "length": {"definition": "bohr", "locked": true}, "luminance": {"definition": "nit", "locked": false}, "luminosity": {"definition": "cd", "locked": false}, "luminous_flux": {"definition": "lm", "locked": false}, "magnetic_field": {"definition": "T", "locked": false}, "magnetic_flux": {"definition": "Wb", "locked": false}, "mass": {"definition": "m_e", "locked": true}, "power": {"definition": "W", "locked": false}, "pressure": {"definition": "atomic_unit_of_pressure", "locked": true}, "resistance": {"definition": "\u03a9", "locked": false}, "substance": {"definition": "mol", "locked": false}, "temperature": {"definition": "atomic_unit_of_temperature", "locked": true}, "time": {"definition": "atomic_unit_of_time", "locked": true}}, "id": "AU"}], "selected": "Custom"}}, "plugins": {"entry_points": {"items": [{"id": "apps/1_all/1_entries", "entry_point_type": "app", "app": {"label": "Entries", "path": "entries", "resource": "entries", "category": "All", "description": "Search entries across all domains", "readme": "This page allows you to search **entries** within NOMAD. Entries represent any individual data items that have been uploaded to NOMAD, no matter whether they come from theoretical calculations, experiments, lab notebooks or any other source of data. This allows you to perform cross-domain queries, but if you are interested in a specific subfield, you should see if a specific application exists for it in the explore menu to get more details.", "pagination": {"order_by": "upload_create_time", "order": "desc", "page_size": 20}, "columns": [{"search_quantity": "entry_name", "selected": true, "title": "Name", "align": "left"}, {"search_quantity": "results.material.chemical_formula_hill", "selected": true, "title": "Formula", "align": "left"}, {"search_quantity": "entry_type", "selected": true, "align": "left"}, {"search_quantity": "upload_create_time", "selected": true, "title": "Upload time", "align": "left"}, {"search_quantity": "authors", "selected": true, "align": "left"}, {"search_quantity": "upload_name", "selected": false, "align": "left"}, {"search_quantity": "upload_id", "selected": false, "align": "left"}, {"search_quantity": "results.method.method_name", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.program_name", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.apw_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.basis_set", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.k_line_density", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.native_tier", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.material.structural_type", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.crystal_system", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_symbol", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_number", "selected": false, "align": "left"}, {"search_quantity": "results.eln.lab_ids", "selected": false, "align": "left"}, {"search_quantity": "results.eln.sections", "selected": false, "align": "left"}, {"search_quantity": "results.eln.methods", "selected": false, "align": "left"}, {"search_quantity": "results.eln.tags", "selected": false, "align": "left"}, {"search_quantity": "results.eln.instruments", "selected": false, "align": "left"}, {"search_quantity": "mainfile", "selected": false, "align": "left"}, {"search_quantity": "comment", "selected": false, "align": "left"}, {"search_quantity": "references", "selected": false, "align": "left"}, {"search_quantity": "datasets", "selected": false, "align": "left"}, {"search_quantity": "published", "selected": false, "title": "Access", "align": "left"}], "rows": {"actions": {"enabled": true}, "details": {"enabled": true}, "selection": {"enabled": true}}, "menu": {"width": 12, "show_header": true, "title": "Filters", "type": "menu", "size": "sm", "indentation": 0, "items": [{"width": 12, "show_header": true, "title": "Material", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Elements / Formula", "type": "menu", "size": "xxl", "indentation": 1, "items": [{"type": "periodic_table", "search_quantity": "results.material.elements", "scale": "linear", "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_hill", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_iupac", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_reduced", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_anonymous", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.material.n_elements", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Structure / Symmetry", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.material.structural_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.bravais_lattice", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.structure_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.strukturbericht_designation", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.point_group", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.hall_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.prototype_aflow_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Method", "type": "menu", "size": "md", "items": [{"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.program_version", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Precision", "type": "menu", "size": "md", "indentation": 1, "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.k_line_density", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.native_tier", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.basis_set", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.apw_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DFT": {"label": "Search DFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.xc_functional_names", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.core_electron_treatment", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.relativity_method", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "TB", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"TB": {"label": "Search TB entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.tb.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.tb.localization_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "GW", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"GW": {"label": "Search GW entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.gw.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "BSE", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"BSE": {"label": "Search BSE entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.bse.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.solver", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.gw_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DMFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DMFT": {"label": "Search DMFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dmft.impurity_solver_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.inverse_temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.magnetic_state", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.u", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.jh", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.analytical_continuation", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "EELS", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"EELS": {"label": "Search EELS entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.spectroscopic.spectra.provenance.eels", "items": [{"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.detector_type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.resolution", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.min_energy", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.max_energy", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Workflow", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Molecular dynamics", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.workflow_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"MolecularDynamics": {"label": "Search molecular dynamics entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.thermodynamic.trajectory", "items": [{"search_quantity": "results.properties.thermodynamic.trajectory.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 4, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Geometry Optimization", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"geometry_optimization": {"label": "Search geometry optimization entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.geometry_optimization", "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_energy_difference", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_force_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_displacement_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Properties", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Electronic", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "electronic_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic.band_gap", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.dos_electronic", "items": [{"search_quantity": "results.properties.electronic.dos_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Vibrational", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "vibrational_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Mechanical", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "mechanical_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.bulk_modulus", "items": [{"search_quantity": "results.properties.mechanical.bulk_modulus.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.bulk_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.shear_modulus", "items": [{"search_quantity": "results.properties.mechanical.shear_modulus.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.shear_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.energy_volume_curve", "items": [{"search_quantity": "results.properties.mechanical.energy_volume_curve.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Use Cases", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Solar Cells", "type": "menu", "size": "md", "indentation": 1, "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.efficiency", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.fill_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.device_area", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.device_architecture", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.device_stack", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.absorber", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.absorber_fabrication", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.electron_transport_layer", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.hole_transport_layer", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.substrate", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.back_contact", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Heterogeneous Catalysis", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.catalytic.reaction.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.catalytic.reaction.reactants", "items": [{"search_quantity": "results.properties.catalytic.reaction.reactants.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reactants.conversion", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reactants.mole_fraction_in", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reactants.mole_fraction_out", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.catalytic.reaction.products", "items": [{"search_quantity": "results.properties.catalytic.reaction.products.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.products.selectivity", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.products.mole_fraction_out", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.catalytic.catalyst", "items": [{"search_quantity": "results.properties.catalytic.catalyst.catalyst_type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.support", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.preparation_method", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.catalyst_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.characterization_methods", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.catalyst.surface_area", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Author / Origin / Dataset", "type": "menu", "size": "lg", "items": [{"search_quantity": "authors.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "upload_create_time", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "external_db", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.doi", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Visibility / IDs / Schema", "type": "menu", "size": "md", "items": [{"width": 12, "show_header": true, "type": "visibility"}, {"search_quantity": "entry_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.material_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "definitions"}]}, {"width": 12, "show_header": true, "title": "Optimade", "type": "menu", "size": "lg", "items": [{"width": 12, "show_header": true, "type": "optimade"}]}]}, "search_quantities": {"exclude": ["mainfile", "entry_name", "combine"]}, "search_syntaxes": {"exclude": ["free_text"]}}}, {"id": "apps/2_theory/1_calculations", "entry_point_type": "app", "app": {"label": "Calculations", "path": "calculations", "resource": "entries", "category": "Theory", "description": "Search calculations", "readme": "This page allows you to search **calculations** within NOMAD. Calculations typically come from a specific simulation software that uses an approximate model to investigate and report different physical properties.", "pagination": {"order_by": "upload_create_time", "order": "desc", "page_size": 20}, "columns": [{"search_quantity": "results.material.chemical_formula_hill", "selected": true, "title": "Formula", "align": "left"}, {"search_quantity": "results.method.simulation.program_name", "selected": true, "align": "left"}, {"search_quantity": "results.method.method_name", "selected": true, "align": "left"}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "selected": true, "align": "left"}, {"search_quantity": "upload_create_time", "selected": true, "title": "Upload time", "align": "left"}, {"search_quantity": "authors", "selected": true, "align": "left"}, {"search_quantity": "results.method.simulation.precision.apw_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.basis_set", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.k_line_density", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.native_tier", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.material.structural_type", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.crystal_system", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_symbol", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_number", "selected": false, "align": "left"}, {"search_quantity": "entry_name", "selected": false, "title": "Name", "align": "left"}, {"search_quantity": "mainfile", "selected": false, "align": "left"}, {"search_quantity": "comment", "selected": false, "align": "left"}, {"search_quantity": "references", "selected": false, "align": "left"}, {"search_quantity": "datasets", "selected": false, "align": "left"}, {"search_quantity": "published", "selected": false, "title": "Access", "align": "left"}], "rows": {"actions": {"enabled": true}, "details": {"enabled": true}, "selection": {"enabled": true}}, "menu": {"width": 12, "show_header": true, "title": "Filters", "type": "menu", "size": "sm", "indentation": 0, "items": [{"width": 12, "show_header": true, "title": "Material", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Elements / Formula", "type": "menu", "size": "xxl", "indentation": 1, "items": [{"type": "periodic_table", "search_quantity": "results.material.elements", "scale": "linear", "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_hill", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_iupac", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_reduced", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_anonymous", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.material.n_elements", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Structure / Symmetry", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.material.structural_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.bravais_lattice", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.structure_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.strukturbericht_designation", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.point_group", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.hall_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.prototype_aflow_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Method", "type": "menu", "size": "md", "items": [{"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.program_version", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Precision", "type": "menu", "size": "md", "indentation": 1, "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.k_line_density", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.native_tier", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.basis_set", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.apw_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DFT": {"label": "Search DFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.xc_functional_names", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.core_electron_treatment", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.relativity_method", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "TB", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"TB": {"label": "Search TB entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.tb.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.tb.localization_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "GW", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"GW": {"label": "Search GW entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.gw.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "BSE", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"BSE": {"label": "Search BSE entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.bse.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.solver", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.gw_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DMFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DMFT": {"label": "Search DMFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dmft.impurity_solver_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.inverse_temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.magnetic_state", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.u", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.jh", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.analytical_continuation", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Workflow", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Molecular dynamics", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.workflow_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"MolecularDynamics": {"label": "Search molecular dynamics entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.thermodynamic.trajectory", "items": [{"search_quantity": "results.properties.thermodynamic.trajectory.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 4, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Geometry Optimization", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"geometry_optimization": {"label": "Search geometry optimization entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.geometry_optimization", "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_energy_difference", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_force_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_displacement_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Properties", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Electronic", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "electronic_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic.band_gap", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.dos_electronic", "items": [{"search_quantity": "results.properties.electronic.dos_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Vibrational", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "vibrational_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Mechanical", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "mechanical_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.bulk_modulus", "items": [{"search_quantity": "results.properties.mechanical.bulk_modulus.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.bulk_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.shear_modulus", "items": [{"search_quantity": "results.properties.mechanical.shear_modulus.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.shear_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.energy_volume_curve", "items": [{"search_quantity": "results.properties.mechanical.energy_volume_curve.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Author / Origin / Dataset", "type": "menu", "size": "lg", "items": [{"search_quantity": "authors.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "upload_create_time", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "external_db", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.doi", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Visibility / IDs / Schema", "type": "menu", "size": "md", "items": [{"width": 12, "show_header": true, "type": "visibility"}, {"search_quantity": "entry_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.material_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "definitions"}]}, {"width": 12, "show_header": true, "title": "Optimade", "type": "menu", "size": "lg", "items": [{"width": 12, "show_header": true, "type": "optimade"}]}]}, "search_quantities": {"exclude": ["mainfile", "entry_name", "combine"]}, "dashboard": {"widgets": [{"type": "periodictable", "search_quantity": "results.material.elements", "scale": "linear", "layout": {"lg": {"h": 11, "w": 14, "x": 0, "y": 0, "minH": 3, "minW": 3}, "md": {"h": 8, "w": 12, "x": 0, "y": 0, "minH": 3, "minW": 3}, "sm": {"h": 8, "w": 12, "x": 0, "y": 0, "minH": 3, "minW": 3}, "xl": {"h": 11, "w": 14, "x": 0, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 13, "x": 0, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "layout": {"lg": {"h": 5, "w": 5, "x": 19, "y": 6, "minH": 3, "minW": 3}, "md": {"h": 6, "w": 6, "x": 12, "y": 8, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 6, "y": 13, "minH": 3, "minW": 3}, "xl": {"h": 6, "w": 6, "x": 24, "y": 5, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 6, "x": 30, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.material.structural_type", "type": "terms", "scale": "log", "show_input": false, "layout": {"lg": {"h": 6, "w": 5, "x": 19, "y": 0, "minH": 3, "minW": 3}, "md": {"h": 6, "w": 6, "x": 0, "y": 8, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 6, "y": 8, "minH": 3, "minW": 3}, "xl": {"h": 11, "w": 5, "x": 19, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 6, "x": 19, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "log", "show_input": true, "layout": {"lg": {"h": 6, "w": 5, "x": 14, "y": 0, "minH": 3, "minW": 3}, "md": {"h": 8, "w": 6, "x": 12, "y": 0, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 0, "y": 8, "minH": 3, "minW": 3}, "xl": {"h": 11, "w": 5, "x": 14, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 6, "x": 13, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "layout": {"lg": {"h": 5, "w": 5, "x": 14, "y": 6, "minH": 3, "minW": 3}, "md": {"h": 6, "w": 6, "x": 6, "y": 8, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 0, "y": 13, "minH": 3, "minW": 3}, "xl": {"h": 5, "w": 6, "x": 24, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 5, "x": 25, "y": 0, "minH": 3, "minW": 3}}}]}, "filters_locked": {"quantities": "results.method.simulation.program_name"}, "search_syntaxes": {"exclude": ["free_text"]}}}, {"id": "apps/2_theory/2_materials", "entry_point_type": "app", "app": {"label": "Materials", "path": "materials", "resource": "materials", "category": "Theory", "description": "Search materials that are identified from calculations", "readme": "This page allows you to search **materials** within NOMAD. NOMAD can often automatically detect the material from individual calculations that contain the full atomistic structure and can then group the data by using these detected materials. This allows you to search individual materials which have properties that are aggregated from several entries. Following the link for a specific material will take you to the corresponding [NOMAD Encyclopedia](https://nomad-lab.eu/prod/rae/encyclopedia/#/search) page for that material. NOMAD Encyclopedia is a service that is specifically oriented towards materials property exploration.\nNotice that by default the properties that you search can be combined from several different entries. If instead you wish to search for a material with an individual entry fullfilling your search criteria, uncheck the **combine results from several entries**-checkbox.", "pagination": {"order_by": "chemical_formula_hill", "order": "asc", "page_size": 20}, "columns": [{"search_quantity": "chemical_formula_hill", "selected": true, "title": "Formula", "align": "left"}, {"search_quantity": "structural_type", "selected": true, "align": "left"}, {"search_quantity": "symmetry.structure_name", "selected": true, "align": "left"}, {"search_quantity": "symmetry.space_group_number", "selected": true, "align": "left"}, {"search_quantity": "symmetry.crystal_system", "selected": true, "align": "left"}, {"search_quantity": "symmetry.space_group_symbol", "selected": false, "align": "left"}, {"search_quantity": "material_id", "selected": false, "align": "left"}], "rows": {"actions": {"enabled": true}, "details": {"enabled": false}, "selection": {"enabled": false}}, "menu": {"width": 12, "show_header": true, "title": "Filters", "type": "menu", "size": "sm", "indentation": 0, "items": [{"width": 12, "show_header": true, "title": "Material", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Elements / Formula", "type": "menu", "size": "xxl", "indentation": 1, "items": [{"type": "periodic_table", "search_quantity": "results.material.elements", "scale": "linear", "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_hill", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_iupac", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_reduced", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_anonymous", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.material.n_elements", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Structure / Symmetry", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.material.structural_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.bravais_lattice", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.structure_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.strukturbericht_designation", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.point_group", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.hall_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.prototype_aflow_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Method", "type": "menu", "size": "md", "items": [{"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.program_version", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DFT": {"label": "Search DFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.xc_functional_names", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.core_electron_treatment", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.relativity_method", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "TB", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"TB": {"label": "Search TB entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.tb.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.tb.localization_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "GW", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"GW": {"label": "Search GW entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.gw.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "BSE", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"BSE": {"label": "Search BSE entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.bse.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.solver", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.gw_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DMFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DMFT": {"label": "Search DMFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dmft.impurity_solver_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.inverse_temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.magnetic_state", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.u", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.jh", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.analytical_continuation", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Workflow", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Molecular dynamics", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.workflow_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"MolecularDynamics": {"label": "Search molecular dynamics entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.thermodynamic.trajectory", "items": [{"search_quantity": "results.properties.thermodynamic.trajectory.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 4, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Geometry Optimization", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"geometry_optimization": {"label": "Search geometry optimization entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.geometry_optimization", "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_energy_difference", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_force_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_displacement_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Properties", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Electronic", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "electronic_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic.band_gap", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.dos_electronic", "items": [{"search_quantity": "results.properties.electronic.dos_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Vibrational", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "vibrational_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Mechanical", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "mechanical_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.bulk_modulus", "items": [{"search_quantity": "results.properties.mechanical.bulk_modulus.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.bulk_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.shear_modulus", "items": [{"search_quantity": "results.properties.mechanical.shear_modulus.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.shear_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.energy_volume_curve", "items": [{"search_quantity": "results.properties.mechanical.energy_volume_curve.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Author / Origin / Dataset", "type": "menu", "size": "lg", "items": [{"search_quantity": "authors.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "upload_create_time", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "external_db", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.doi", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Visibility / IDs / Schema", "type": "menu", "size": "md", "items": [{"width": 12, "show_header": true, "type": "visibility"}, {"search_quantity": "entry_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.material_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "definitions"}]}, {"width": 12, "show_header": true, "title": "Optimade", "type": "menu", "size": "lg", "items": [{"width": 12, "show_header": true, "type": "optimade"}]}, {"search_quantity": "combine", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"True": {"label": "Combine results from several entries", "description": "If selected, your filters may be matched from several entries that contain the same material. When unchecked, the material has to have a single entry that matches all your filters."}}, "n_columns": 1, "sort_static": true, "show_statistics": false}]}, "search_quantities": {"exclude": ["mainfile", "entry_name"]}, "search_syntaxes": {"exclude": ["free_text"]}}}]}}};
+window.nomadConfig = {"keycloak": {"realm_name": "fairdi_nomad_test", "client_id": "nomad_public", "public_server_url": "https://nomad-lab.eu/fairdi/keycloak/auth/"}, "services": {"api_host": "localhost", "api_port": 8000, "api_base_path": "/fairdi/nomad/latest", "api_secret": "defaultApiSecret", "api_timeout": 600, "https": false, "https_upload": false, "admin_user_id": "c97facc2-92ec-4fa6-80cf-a08ed957255b", "encyclopedia_base": "https://nomad-lab.eu/prod/rae/encyclopedia/#", "optimade_enabled": true, "dcat_enabled": true, "h5grove_enabled": true, "console_log_level": 30, "upload_limit": 10, "force_raw_file_decoding": false, "max_entry_download": 50000, "unavailable_value": "unavailable", "app_token_max_expires_in": 2592000, "html_resource_http_max_age": 60, "image_resource_http_max_age": 2592000, "upload_members_group_search_enabled": false, "log_api_queries": true}, "ui": {"unit_systems": {"items": [{"label": "Custom", "units": {"angle": {"definition": "\u00b0", "locked": false}, "energy": {"definition": "eV", "locked": false}, "length": {"definition": "\u00c5", "locked": false}, "pressure": {"definition": "GPa", "locked": false}, "time": {"definition": "fs", "locked": false}, "dimensionless": {"definition": "dimensionless", "locked": false}, "mass": {"definition": "kg", "locked": false}, "current": {"definition": "A", "locked": false}, "temperature": {"definition": "K", "locked": false}, "luminosity": {"definition": "cd", "locked": false}, "luminous_flux": {"definition": "lm", "locked": false}, "substance": {"definition": "mol", "locked": false}, "information": {"definition": "bit", "locked": false}, "force": {"definition": "N", "locked": false}, "power": {"definition": "W", "locked": false}, "charge": {"definition": "C", "locked": false}, "resistance": {"definition": "\u03a9", "locked": false}, "conductance": {"definition": "S", "locked": false}, "inductance": {"definition": "H", "locked": false}, "magnetic_flux": {"definition": "Wb", "locked": false}, "magnetic_field": {"definition": "T", "locked": false}, "frequency": {"definition": "Hz", "locked": false}, "luminance": {"definition": "nit", "locked": false}, "illuminance": {"definition": "lx", "locked": false}, "electric_potential": {"definition": "V", "locked": false}, "capacitance": {"definition": "F", "locked": false}, "activity": {"definition": "kat", "locked": false}}, "id": "Custom"}, {"label": "International System of Units (SI)", "units": {"activity": {"definition": "kat", "locked": true}, "angle": {"definition": "rad", "locked": true}, "capacitance": {"definition": "F", "locked": true}, "charge": {"definition": "C", "locked": true}, "conductance": {"definition": "S", "locked": true}, "current": {"definition": "A", "locked": true}, "dimensionless": {"definition": "dimensionless", "locked": true}, "electric_potential": {"definition": "V", "locked": true}, "energy": {"definition": "J", "locked": true}, "force": {"definition": "N", "locked": true}, "frequency": {"definition": "Hz", "locked": true}, "illuminance": {"definition": "lx", "locked": true}, "inductance": {"definition": "H", "locked": true}, "information": {"definition": "bit", "locked": true}, "length": {"definition": "m", "locked": true}, "luminance": {"definition": "nit", "locked": true}, "luminosity": {"definition": "cd", "locked": true}, "luminous_flux": {"definition": "lm", "locked": true}, "magnetic_field": {"definition": "T", "locked": true}, "magnetic_flux": {"definition": "Wb", "locked": true}, "mass": {"definition": "kg", "locked": true}, "power": {"definition": "W", "locked": true}, "pressure": {"definition": "Pa", "locked": true}, "resistance": {"definition": "\u03a9", "locked": true}, "substance": {"definition": "mol", "locked": true}, "temperature": {"definition": "K", "locked": true}, "time": {"definition": "s", "locked": true}}, "id": "SI"}, {"label": "Hartree atomic units (AU)", "units": {"activity": {"definition": "kat", "locked": false}, "angle": {"definition": "rad", "locked": false}, "capacitance": {"definition": "F", "locked": false}, "charge": {"definition": "C", "locked": false}, "conductance": {"definition": "S", "locked": false}, "current": {"definition": "atomic_unit_of_current", "locked": true}, "dimensionless": {"definition": "dimensionless", "locked": true}, "electric_potential": {"definition": "V", "locked": false}, "energy": {"definition": "Ha", "locked": true}, "force": {"definition": "atomic_unit_of_force", "locked": true}, "frequency": {"definition": "Hz", "locked": false}, "illuminance": {"definition": "lx", "locked": false}, "inductance": {"definition": "H", "locked": false}, "information": {"definition": "bit", "locked": false}, "length": {"definition": "bohr", "locked": true}, "luminance": {"definition": "nit", "locked": false}, "luminosity": {"definition": "cd", "locked": false}, "luminous_flux": {"definition": "lm", "locked": false}, "magnetic_field": {"definition": "T", "locked": false}, "magnetic_flux": {"definition": "Wb", "locked": false}, "mass": {"definition": "m_e", "locked": true}, "power": {"definition": "W", "locked": false}, "pressure": {"definition": "atomic_unit_of_pressure", "locked": true}, "resistance": {"definition": "\u03a9", "locked": false}, "substance": {"definition": "mol", "locked": false}, "temperature": {"definition": "atomic_unit_of_temperature", "locked": true}, "time": {"definition": "atomic_unit_of_time", "locked": true}}, "id": "AU"}], "selected": "Custom"}}, "plugins": {"entry_points": {"items": [{"id": "apps/1_all/1_entries", "entry_point_type": "app", "app": {"label": "Entries", "path": "entries", "resource": "entries", "category": "All", "description": "Search entries across all domains", "readme": "This page allows you to search **entries** within NOMAD. Entries represent any individual data items that have been uploaded to NOMAD, no matter whether they come from theoretical calculations, experiments, lab notebooks or any other source of data. This allows you to perform cross-domain queries, but if you are interested in a specific subfield, you should see if a specific application exists for it in the explore menu to get more details.", "pagination": {"order_by": "upload_create_time", "order": "desc", "page_size": 20}, "columns": [{"search_quantity": "entry_name", "selected": true, "title": "Name", "align": "left"}, {"search_quantity": "results.material.chemical_formula_hill", "selected": true, "title": "Formula", "align": "left"}, {"search_quantity": "entry_type", "selected": true, "align": "left"}, {"search_quantity": "upload_create_time", "selected": true, "title": "Upload time", "align": "left"}, {"search_quantity": "authors", "selected": true, "align": "left"}, {"search_quantity": "upload_name", "selected": false, "align": "left"}, {"search_quantity": "upload_id", "selected": false, "align": "left"}, {"search_quantity": "results.method.method_name", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.program_name", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.apw_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.basis_set", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.k_line_density", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.native_tier", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.material.structural_type", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.crystal_system", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_symbol", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_number", "selected": false, "align": "left"}, {"search_quantity": "results.eln.lab_ids", "selected": false, "align": "left"}, {"search_quantity": "results.eln.sections", "selected": false, "align": "left"}, {"search_quantity": "results.eln.methods", "selected": false, "align": "left"}, {"search_quantity": "results.eln.tags", "selected": false, "align": "left"}, {"search_quantity": "results.eln.instruments", "selected": false, "align": "left"}, {"search_quantity": "mainfile", "selected": false, "align": "left"}, {"search_quantity": "comment", "selected": false, "align": "left"}, {"search_quantity": "references", "selected": false, "align": "left"}, {"search_quantity": "datasets", "selected": false, "align": "left"}, {"search_quantity": "published", "selected": false, "title": "Access", "align": "left"}], "rows": {"actions": {"enabled": true, "items": []}, "details": {"enabled": true}, "selection": {"enabled": true}}, "menu": {"width": 12, "show_header": true, "title": "Filters", "type": "menu", "size": "sm", "indentation": 0, "items": [{"width": 12, "show_header": true, "title": "Material", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Elements / Formula", "type": "menu", "size": "xxl", "indentation": 1, "items": [{"type": "periodic_table", "search_quantity": "results.material.elements", "scale": "linear", "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_hill", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_iupac", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_reduced", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_anonymous", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.material.n_elements", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Structure / Symmetry", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.material.structural_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.bravais_lattice", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.structure_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.strukturbericht_designation", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.point_group", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.hall_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.prototype_aflow_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Method", "type": "menu", "size": "md", "items": [{"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.program_version", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Precision", "type": "menu", "size": "md", "indentation": 1, "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.k_line_density", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.native_tier", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.basis_set", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.apw_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DFT": {"label": "Search DFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.xc_functional_names", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.core_electron_treatment", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.relativity_method", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "TB", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"TB": {"label": "Search TB entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.tb.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.tb.localization_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "GW", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"GW": {"label": "Search GW entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.gw.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "BSE", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"BSE": {"label": "Search BSE entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.bse.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.solver", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.gw_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DMFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DMFT": {"label": "Search DMFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dmft.impurity_solver_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.inverse_temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.magnetic_state", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.u", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.jh", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.analytical_continuation", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "EELS", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"EELS": {"label": "Search EELS entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.spectroscopic.spectra.provenance.eels", "items": [{"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.detector_type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.resolution", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.min_energy", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.spectroscopic.spectra.provenance.eels.max_energy", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Workflow", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Molecular dynamics", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.workflow_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"MolecularDynamics": {"label": "Search molecular dynamics entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.thermodynamic.trajectory", "items": [{"search_quantity": "results.properties.thermodynamic.trajectory.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 4, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Geometry Optimization", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"geometry_optimization": {"label": "Search geometry optimization entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.geometry_optimization", "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_energy_difference", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_force_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_displacement_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Properties", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Electronic", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "electronic_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic.band_gap", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.dos_electronic", "items": [{"search_quantity": "results.properties.electronic.dos_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Vibrational", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "vibrational_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Mechanical", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "mechanical_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.bulk_modulus", "items": [{"search_quantity": "results.properties.mechanical.bulk_modulus.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.bulk_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.shear_modulus", "items": [{"search_quantity": "results.properties.mechanical.shear_modulus.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.shear_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.energy_volume_curve", "items": [{"search_quantity": "results.properties.mechanical.energy_volume_curve.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Use Cases", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Solar Cells", "type": "menu", "size": "md", "indentation": 1, "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.efficiency", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.fill_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.optoelectronic.solar_cell.device_area", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.device_architecture", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.device_stack", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.absorber", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.absorber_fabrication", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.electron_transport_layer", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.hole_transport_layer", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.substrate", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.optoelectronic.solar_cell.back_contact", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Heterogeneous Catalysis", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.catalytic.reaction.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.catalytic.reaction.reactants", "items": [{"search_quantity": "results.properties.catalytic.reaction.reactants.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reactants.conversion", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reactants.mole_fraction_in", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reactants.mole_fraction_out", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.catalytic.reaction.products", "items": [{"search_quantity": "results.properties.catalytic.reaction.products.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.products.selectivity", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.products.mole_fraction_out", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.catalytic.catalyst", "items": [{"search_quantity": "results.properties.catalytic.catalyst.catalyst_type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.support", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.preparation_method", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.catalyst_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.catalytic.catalyst.characterization_methods", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.catalytic.catalyst.surface_area", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Author / Origin / Dataset", "type": "menu", "size": "lg", "items": [{"search_quantity": "authors.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "upload_create_time", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "external_db", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.doi", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Visibility / IDs / Schema", "type": "menu", "size": "md", "items": [{"width": 12, "show_header": true, "type": "visibility"}, {"search_quantity": "entry_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.material_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "definitions"}]}, {"width": 12, "show_header": true, "title": "Optimade", "type": "menu", "size": "lg", "items": [{"width": 12, "show_header": true, "type": "optimade"}]}]}, "search_quantities": {"exclude": ["mainfile", "entry_name", "combine"]}, "search_syntaxes": {"exclude": ["free_text"]}}}, {"id": "apps/2_theory/1_calculations", "entry_point_type": "app", "app": {"label": "Calculations", "path": "calculations", "resource": "entries", "category": "Theory", "description": "Search calculations", "readme": "This page allows you to search **calculations** within NOMAD. Calculations typically come from a specific simulation software that uses an approximate model to investigate and report different physical properties.", "pagination": {"order_by": "upload_create_time", "order": "desc", "page_size": 20}, "columns": [{"search_quantity": "results.material.chemical_formula_hill", "selected": true, "title": "Formula", "align": "left"}, {"search_quantity": "results.method.simulation.program_name", "selected": true, "align": "left"}, {"search_quantity": "results.method.method_name", "selected": true, "align": "left"}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "selected": true, "align": "left"}, {"search_quantity": "upload_create_time", "selected": true, "title": "Upload time", "align": "left"}, {"search_quantity": "authors", "selected": true, "align": "left"}, {"search_quantity": "results.method.simulation.precision.apw_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.basis_set", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.k_line_density", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.native_tier", "selected": false, "align": "left"}, {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "selected": false, "align": "left"}, {"search_quantity": "results.material.structural_type", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.crystal_system", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_symbol", "selected": false, "align": "left"}, {"search_quantity": "results.material.symmetry.space_group_number", "selected": false, "align": "left"}, {"search_quantity": "entry_name", "selected": false, "title": "Name", "align": "left"}, {"search_quantity": "mainfile", "selected": false, "align": "left"}, {"search_quantity": "comment", "selected": false, "align": "left"}, {"search_quantity": "references", "selected": false, "align": "left"}, {"search_quantity": "datasets", "selected": false, "align": "left"}, {"search_quantity": "published", "selected": false, "title": "Access", "align": "left"}], "rows": {"actions": {"enabled": true, "items": []}, "details": {"enabled": true}, "selection": {"enabled": true}}, "menu": {"width": 12, "show_header": true, "title": "Filters", "type": "menu", "size": "sm", "indentation": 0, "items": [{"width": 12, "show_header": true, "title": "Material", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Elements / Formula", "type": "menu", "size": "xxl", "indentation": 1, "items": [{"type": "periodic_table", "search_quantity": "results.material.elements", "scale": "linear", "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_hill", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_iupac", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_reduced", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.chemical_formula_anonymous", "type": "terms", "scale": "linear", "show_input": true, "width": 6, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.material.n_elements", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Structure / Symmetry", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.material.structural_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.bravais_lattice", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.structure_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.strukturbericht_designation", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.point_group", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.hall_symbol", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.symmetry.prototype_aflow_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Method", "type": "menu", "size": "md", "items": [{"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.program_version", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Precision", "type": "menu", "size": "md", "indentation": 1, "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.k_line_density", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.native_tier", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.precision.basis_set", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.planewave_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.precision.apw_cutoff", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DFT": {"label": "Search DFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dft.xc_functional_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.xc_functional_names", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.exact_exchange_mixing_factor", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dft.hubbard_kanamori_model.u_effective", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.core_electron_treatment", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dft.relativity_method", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "TB", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"TB": {"label": "Search TB entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.tb.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.tb.localization_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "GW", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"GW": {"label": "Search GW entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.gw.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.gw.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "BSE", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"BSE": {"label": "Search BSE entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.bse.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.solver", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.starting_point_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.basis_set_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.bse.gw_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "DMFT", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.method_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"DMFT": {"label": "Search DMFT entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"search_quantity": "results.method.simulation.dmft.impurity_solver_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 2, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.inverse_temperature", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.magnetic_state", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.u", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.method.simulation.dmft.jh", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "results.method.simulation.dmft.analytical_continuation", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Workflow", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Molecular dynamics", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.method.workflow_name", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"MolecularDynamics": {"label": "Search molecular dynamics entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.thermodynamic.trajectory", "items": [{"search_quantity": "results.properties.thermodynamic.trajectory.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 4, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.ensemble_type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.thermodynamic.trajectory.provenance.molecular_dynamics.time_step", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Geometry Optimization", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "results.properties.available_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": false, "options": {"geometry_optimization": {"label": "Search geometry optimization entries"}}, "n_columns": 1, "sort_static": true, "show_statistics": false}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.geometry_optimization", "items": [{"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_energy_difference", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_force_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.geometry_optimization.final_displacement_maximum", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Properties", "type": "menu", "size": "md"}, {"width": 12, "show_header": true, "title": "Electronic", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "electronic_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic.band_gap", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 2, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.electronic.band_structure_electronic.band_gap.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.band_structure_electronic", "items": [{"search_quantity": "results.properties.electronic.band_structure_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.electronic.dos_electronic", "items": [{"search_quantity": "results.properties.electronic.dos_electronic.spin_polarized", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Vibrational", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "vibrational_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Mechanical", "type": "menu", "size": "md", "indentation": 1, "items": [{"search_quantity": "mechanical_properties", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.bulk_modulus", "items": [{"search_quantity": "results.properties.mechanical.bulk_modulus.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.bulk_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.shear_modulus", "items": [{"search_quantity": "results.properties.mechanical.shear_modulus.type", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "results.properties.mechanical.shear_modulus.value", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "type": "nested_object", "path": "results.properties.mechanical.energy_volume_curve", "items": [{"search_quantity": "results.properties.mechanical.energy_volume_curve.type", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}]}]}, {"width": 12, "show_header": true, "title": "Author / Origin / Dataset", "type": "menu", "size": "lg", "items": [{"search_quantity": "authors.name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"type": "histogram", "show_input": true, "x": {"search_quantity": "upload_create_time", "scale": "linear"}, "y": {"scale": "linear"}, "autorange": false, "width": 12, "show_header": true, "show_statistics": true}, {"search_quantity": "external_db", "type": "terms", "scale": "linear", "show_input": false, "width": 12, "show_header": true, "options": 5, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.doi", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}]}, {"width": 12, "show_header": true, "title": "Visibility / IDs / Schema", "type": "menu", "size": "md", "items": [{"width": 12, "show_header": true, "type": "visibility"}, {"search_quantity": "entry_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "upload_name", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "results.material.material_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"search_quantity": "datasets.dataset_id", "type": "terms", "scale": "linear", "show_input": true, "width": 12, "show_header": true, "options": 0, "n_columns": 1, "sort_static": true, "show_statistics": true}, {"width": 12, "show_header": true, "type": "definitions"}]}, {"width": 12, "show_header": true, "title": "Optimade", "type": "menu", "size": "lg", "items": [{"width": 12, "show_header": true, "type": "optimade"}]}]}, "search_quantities": {"exclude": ["mainfile", "entry_name", "combine"]}, "dashboard": {"widgets": [{"type": "periodictable", "search_quantity": "results.material.elements", "scale": "linear", "layout": {"lg": {"h": 11, "w": 14, "x": 0, "y": 0, "minH": 3, "minW": 3}, "md": {"h": 8, "w": 12, "x": 0, "y": 0, "minH": 3, "minW": 3}, "sm": {"h": 8, "w": 12, "x": 0, "y": 0, "minH": 3, "minW": 3}, "xl": {"h": 11, "w": 14, "x": 0, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 13, "x": 0, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.material.symmetry.space_group_symbol", "type": "terms", "scale": "linear", "show_input": true, "layout": {"lg": {"h": 5, "w": 5, "x": 19, "y": 6, "minH": 3, "minW": 3}, "md": {"h": 6, "w": 6, "x": 12, "y": 8, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 6, "y": 13, "minH": 3, "minW": 3}, "xl": {"h": 6, "w": 6, "x": 24, "y": 5, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 6, "x": 30, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.material.structural_type", "type": "terms", "scale": "log", "show_input": false, "layout": {"lg": {"h": 6, "w": 5, "x": 19, "y": 0, "minH": 3, "minW": 3}, "md": {"h": 6, "w": 6, "x": 0, "y": 8, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 6, "y": 8, "minH": 3, "minW": 3}, "xl": {"h": 11, "w": 5, "x": 19, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 6, "x": 19, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.method.simulation.program_name", "type": "terms", "scale": "log", "show_input": true, "layout": {"lg": {"h": 6, "w": 5, "x": 14, "y": 0, "minH": 3, "minW": 3}, "md": {"h": 8, "w": 6, "x": 12, "y": 0, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 0, "y": 8, "minH": 3, "minW": 3}, "xl": {"h": 11, "w": 5, "x": 14, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 6, "x": 13, "y": 0, "minH": 3, "minW": 3}}}, {"search_quantity": "results.material.symmetry.crystal_system", "type": "terms", "scale": "linear", "show_input": false, "layout": {"lg": {"h": 5, "w": 5, "x": 14, "y": 6, "minH": 3, "minW": 3}, "md": {"h": 6, "w": 6, "x": 6, "y": 8, "minH": 3, "minW": 3}, "sm": {"h": 5, "w": 6, "x": 0, "y": 13, "minH": 3, "minW": 3}, "xl": {"h": 5, "w": 6, "x": 24, "y": 0, "minH": 3, "minW": 3}, "xxl": {"h": 9, "w": 5, "x": 25, "y": 0, "minH": 3, "minW": 3}}}]}, "filters_locked": {"quantities": "results.method.simulation.program_name"}, "search_syntaxes": {"exclude": ["free_text"]}}}]}}};
diff --git a/src/components/app/MainMenu.tsx b/src/components/app/MainMenu.tsx
index 17f66bdf678399cd65ab3ce20f9dd2602e3765bc..d1e3f0a7d56fd64e52cc97de374a2ae7801152ba 100644
--- a/src/components/app/MainMenu.tsx
+++ b/src/components/app/MainMenu.tsx
@@ -1,5 +1,5 @@
 import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'
-import {List} from '@mui/material'
+import {Badge, BadgeProps, List} from '@mui/material'
 import Box from '@mui/material/Box'
 import Divider from '@mui/material/Divider'
 import Drawer from '@mui/material/Drawer'
@@ -10,17 +10,10 @@ import ListItemText from '@mui/material/ListItemText'
 import {CSSObject, Theme, styled} from '@mui/material/styles'
 import * as React from 'react'
 
+import {UploadsMainMenuItem} from '../../pages/uploads/UploadsPage'
 import {SxProps} from '../../utils/types'
 import useDevTools from '../devTools/useDevTools'
-import {
-  Analyze,
-  Dev,
-  Explore,
-  Group,
-  Manage,
-  Menu,
-  ToggleColorMode,
-} from '../icons'
+import {Analyze, Dev, Explore, Group, Menu, ToggleColorMode} from '../icons'
 import Link from '../routing/Link'
 import useRoute from '../routing/useRoute'
 import {Logo} from '../theme/Theme'
@@ -81,6 +74,10 @@ export type MainMenuItemProps = React.PropsWithChildren<{
    * Whether the item is active and should be highlighted
    */
   active?: boolean
+  /**
+   * Props for a MUI badge to show on icon of the item
+   */
+  badge?: BadgeProps
 }> &
   ListItemButtonProps &
   SxProps
@@ -93,11 +90,30 @@ export const MainMenuItem = React.forwardRef<HTMLElement, MainMenuItemProps>(
       icon,
       active = false,
       children,
+      badge,
       sx = {},
       ...listItemButtonProps
     },
     ref,
   ) {
+    const iconElement = icon && (
+      <Badge
+        {...badge}
+        sx={{
+          '& .MuiBadge-badge': {left: 0, right: 'initial'},
+        }}
+      >
+        <ListItemIcon
+          sx={{
+            minWidth: 0,
+            mr: open ? 3 : 'auto',
+            justifyContent: 'center',
+          }}
+        >
+          {icon}
+        </ListItemIcon>
+      </Badge>
+    )
     return (
       <ListItem
         ref={ref as React.Ref<HTMLLIElement>}
@@ -140,17 +156,7 @@ export const MainMenuItem = React.forwardRef<HTMLElement, MainMenuItemProps>(
               {children}
             </Box>
           )}
-          {icon && (
-            <ListItemIcon
-              sx={{
-                minWidth: 0,
-                mr: open ? 3 : 'auto',
-                justifyContent: 'center',
-              }}
-            >
-              {icon}
-            </ListItemIcon>
-          )}
+          {iconElement}
           <ListItemText primary={label} sx={{opacity: open ? 1 : 0}} />
         </ListItemButton>
       </ListItem>
@@ -193,14 +199,7 @@ export default function MainMenu() {
       </List>
       <Divider />
       <List sx={{flexGrow: 1}}>
-        <MainMenuItem
-          label='Manage'
-          open={open}
-          icon={<Manage />}
-          component={Link}
-          to='/uploads'
-          active={matches('/uploads')}
-        />
+        <UploadsMainMenuItem open={open} component={Link} />
         <MainMenuItem
           label='Explore'
           open={open}
diff --git a/src/components/archive/EditStatus.tsx b/src/components/archive/EditStatus.tsx
index 3cac3796a0c37e36f978f44b23e834502daaa0c2..fee1de21a3deb4345dbea6ebc43c5b4577e1ac4c 100644
--- a/src/components/archive/EditStatus.tsx
+++ b/src/components/archive/EditStatus.tsx
@@ -1,20 +1,21 @@
-import {Button} from '@mui/material'
+import {Button, IconButton} from '@mui/material'
 import {useAsyncFn} from 'react-use'
 
+import {Redo, Undo} from '../../components/icons'
 import useAuth from '../../hooks/useAuth'
 import {MSectionResponse} from '../../models/graphResponseModels'
-import entryRoute from '../../pages/entry/entryRoute'
+import useEntryRouteData from '../../pages/entry/useEntryRouteData'
 import {archiveEditApi} from '../../utils/api'
 import {assert} from '../../utils/utils'
 import useRoute from '../routing/useRoute'
-import useRouteData from '../routing/useRouteData'
-import {useArchiveChanges} from './useArchive'
+import useArchive, {useArchiveChanges} from './useArchive'
 
 export default function EditStatus() {
   const {user} = useAuth()
   const {reload} = useRoute()
-  const {entry_id} = useRouteData(entryRoute)
+  const {entry_id} = useEntryRouteData()
   const {changeStack, clearChangeStack} = useArchiveChanges()
+  const archive = useArchive()
 
   const [saving, save] = useAsyncFn(async () => {
     const apiChanges = changeStack.map((change) => {
@@ -29,6 +30,9 @@ export default function EditStatus() {
         }
         delete (apiChange.new_value as MSectionResponse)['m_def']
       }
+      if (apiChange.oldValue) {
+        delete apiChange['oldValue']
+      }
 
       return apiChange
     })
@@ -40,16 +44,30 @@ export default function EditStatus() {
   }, [changeStack, clearChangeStack, reload])
 
   return (
-    <Button
-      onClick={save}
-      variant='contained'
-      disabled={changeStack.length === 0 || saving.loading}
-    >
-      {saving.loading
-        ? 'saving ...'
-        : changeStack.length === 0
-        ? 'no changes to save'
-        : `save changes`}
-    </Button>
+    <>
+      <IconButton
+        disabled={!archive.hasChanges()}
+        onClick={() => archive.undo()}
+      >
+        <Undo />
+      </IconButton>
+      <IconButton
+        disabled={!archive.hasUnDoneChanges()}
+        onClick={() => archive.redo()}
+      >
+        <Redo />
+      </IconButton>
+      <Button
+        onClick={save}
+        variant='contained'
+        disabled={changeStack.length === 0 || saving.loading}
+      >
+        {saving.loading
+          ? 'saving ...'
+          : changeStack.length === 0
+          ? 'no changes to save'
+          : `save changes`}
+      </Button>
+    </>
   )
 }
diff --git a/src/components/archive/Section.tsx b/src/components/archive/Section.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..83dd6dc68a7ad2cffa26db4ba76bc662b413a5e4
--- /dev/null
+++ b/src/components/archive/Section.tsx
@@ -0,0 +1,170 @@
+import {Box, Card, CardContent, CardHeader} from '@mui/material'
+import {useCallback, useMemo} from 'react'
+
+import {MSectionRequest} from '../../models/graphRequestModels'
+import {MSectionResponse} from '../../models/graphResponseModels'
+import {
+  Quantity as QuantityDefinition,
+  Section as SectionDefinition,
+  SubSection as SubSectionDefinition,
+} from '../../utils/metainfo'
+import {JSONObject, JSONValue} from '../../utils/types'
+import {assert} from '../../utils/utils'
+import ErrorBoundary from '../ErrorBoundary'
+import {getPropertyLabel} from '../editor/PropertyEditor'
+import SubSectionNavEditor from '../editor/SubSectionNavEditor'
+import JsonViewer from '../fileviewer/JsonViewer'
+import useRouteData from '../routing/useRouteData'
+import DynamicValue from '../values/utils/DynamicValue'
+import {createDynamicComponentSpec} from '../values/utils/dynamicComponents'
+import SectionProvider from './SectionProvider'
+import {useArchiveProperty} from './useArchive'
+import useSubSectionPath from './useSubSectionPath'
+
+type SubSectionProps = {
+  definition: SubSectionDefinition
+  editable?: boolean
+}
+
+function SubSection({definition, editable = false}: SubSectionProps) {
+  return (
+    <SubSectionNavEditor
+      layout={{
+        label: getPropertyLabel(definition.name),
+        type: 'subSectionNav',
+        property: definition.name,
+        editable,
+      }}
+    />
+  )
+}
+
+type QuantityProps = {
+  definition: QuantityDefinition
+  editable?: boolean
+}
+
+function Quantity({definition, editable = false}: QuantityProps) {
+  const path = useSubSectionPath(definition.name)
+
+  const {value, loading, change} = useArchiveProperty<
+    JSONValue | undefined,
+    QuantityDefinition
+  >(path)
+
+  assert(!loading, 'Loading should already be handled')
+
+  const handleChange = useCallback(
+    (newValue: JSONValue | undefined) => {
+      change('upsert', newValue)
+    },
+    [change],
+  )
+
+  const component = createDynamicComponentSpec(definition)
+
+  return (
+    <DynamicValue
+      component={component}
+      label={getPropertyLabel(definition.name)}
+      placeholder='no value'
+      editable={editable}
+      value={value}
+      fullWidth={component.Matrix ? false : true}
+      onChange={handleChange}
+    />
+  )
+}
+
+export type SectionProps = {
+  editable?: boolean
+  path: string
+}
+
+export default function Section({path, editable = false}: SectionProps) {
+  const {value} = useArchiveProperty<MSectionResponse>(path)
+  const definition = value?.m_def as SectionDefinition
+  const data = useRouteData<MSectionRequest, MSectionResponse>()
+
+  assert(
+    value !== undefined,
+    `The section ${path} should have been loaded by now.`,
+  )
+  assert(
+    definition !== undefined,
+    'The section definition should have been loaded by now.',
+  )
+
+  const subSections = useMemo(() => {
+    return Object.keys(definition.all_sub_sections)
+      .map((key) => definition.all_sub_sections[key])
+      .toSorted((a, b) => a.name.localeCompare(b.name))
+  }, [definition])
+
+  const quantities = useMemo(() => {
+    return Object.keys(definition.all_quantities).map(
+      (key) => definition.all_quantities[key],
+    )
+  }, [definition.all_quantities])
+
+  const sortRawDataKeys = (a: string, b: string) => {
+    if (a.startsWith('m_') === b.startsWith('m_')) {
+      return a.localeCompare(b)
+    }
+    if (a.startsWith('m_')) {
+      return -1
+    }
+    return 1
+  }
+
+  return (
+    <Box sx={{display: 'flex', flexDirection: 'column', gap: 2}}>
+      {subSections.length > 0 && (
+        <ErrorBoundary>
+          <Card>
+            <CardHeader title='Sub Sections' />
+            <CardContent
+              sx={{display: 'flex', flexDirection: 'column', gap: 2}}
+            >
+              <SectionProvider path={path}>
+                {subSections.map((subSection) => (
+                  <ErrorBoundary key={subSection.name}>
+                    <SubSection definition={subSection} editable={editable} />
+                  </ErrorBoundary>
+                ))}
+              </SectionProvider>
+            </CardContent>
+          </Card>
+        </ErrorBoundary>
+      )}
+      {definition.name !== 'EntryArchive' && quantities.length > 0 && (
+        <ErrorBoundary>
+          <Card>
+            <CardHeader title='Quantities' />
+            <CardContent
+              sx={{display: 'flex', flexDirection: 'column', gap: 2}}
+            >
+              <SectionProvider path={path}>
+                {quantities.map((quantity) => (
+                  <ErrorBoundary key={quantity.name}>
+                    <Quantity definition={quantity} editable={editable} />
+                  </ErrorBoundary>
+                ))}
+              </SectionProvider>
+            </CardContent>
+          </Card>
+        </ErrorBoundary>
+      )}
+      <Card>
+        <CardHeader title='Raw data' />
+        <CardContent>
+          <JsonViewer
+            value={data as JSONObject}
+            defaultInspectDepth={1}
+            objectSortKeys={sortRawDataKeys}
+          />
+        </CardContent>
+      </Card>
+    </Box>
+  )
+}
diff --git a/src/components/archive/SectionProvider.tsx b/src/components/archive/SectionProvider.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..851e9390b191c64a0e160cf2c870efbcd3a2ebb4
--- /dev/null
+++ b/src/components/archive/SectionProvider.tsx
@@ -0,0 +1,14 @@
+import {PropsWithChildren} from 'react'
+
+import {subSectionContext} from './useSubSectionPath'
+
+export default function SectionProvider({
+  path: path,
+  children,
+}: {path: string} & PropsWithChildren) {
+  return (
+    <subSectionContext.Provider value={{path}}>
+      {children}
+    </subSectionContext.Provider>
+  )
+}
diff --git a/src/components/archive/archive.helper.tsx b/src/components/archive/archive.helper.tsx
index 2caa1f891c144eae639dccbb1ba43f7c63c9485d..e6df20bee68c69314ad63c0c9e2069fae349c181 100644
--- a/src/components/archive/archive.helper.tsx
+++ b/src/components/archive/archive.helper.tsx
@@ -2,18 +2,18 @@ import {useEffect, useState} from 'react'
 import {vi} from 'vitest'
 
 import {UseDataResult} from '../../hooks/useData'
-import {ArchiveChange} from '../../models/entryEditRequestModels'
 import {MDefResponse, MSectionResponse} from '../../models/graphResponseModels'
 import {Quantity, Section, SubSection} from '../../utils/metainfo'
-import {DefaultToObject} from '../../utils/types'
+import {DefaultToObject, JSONObject} from '../../utils/types'
 import * as useDataForRoute from '../routing/useDataForRoute'
 import * as useRouteData from '../routing/useRouteData'
-import {Archive, allArchives} from './useArchive'
+import {ArchiveChangeWithOldValue, allArchives, getArchive} from './useArchive'
 
 export type MockArchiveArgs = {
   entryId?: string
   data?: MSectionResponse
-  changes?: ArchiveChange[]
+  changes?: ArchiveChangeWithOldValue[]
+  clearArchives?: boolean
 }
 
 /**
@@ -25,14 +25,18 @@ export function mockArchive({
   entryId = 'entryId',
   data,
   changes = [],
+  clearArchives = true,
 }: MockArchiveArgs = {}) {
-  allArchives.clear()
-  const archive = new Archive()
+  if (clearArchives) {
+    allArchives.clear()
+  }
+  const archive = getArchive(entryId)
   if (data) {
     archive.archive = data
     archive.loading = false
+  } else {
+    archive.loading = true
   }
-  allArchives.set(entryId, archive)
   archive.changeStack.push(...changes)
   vi.spyOn(useRouteData, 'default').mockReturnValue({
     entry_id: entryId,
@@ -116,9 +120,9 @@ export function addDefinitions(
       if (Array.isArray(value)) {
         if (value.length === 0 || typeof value[0] === 'object') {
           // repeating sub section
-          const sectionDefs = value.map((item, index) =>
-            visit(item, `${childPath}/${index}`),
-          )
+          const sectionDefs = value
+            .filter((item) => !!item)
+            .map((item, index) => visit(item, `${childPath}/${index}`))
           all_sub_sections[key] = {
             m_def: 'SubSection',
             name: key,
@@ -192,13 +196,15 @@ export function addDefinitions(
  * Recursively removes `m_def`s from the given response. This is useful
  * if you want to compare responses with manually written expected responses.
  */
-export function removeDefinitions(data: MSectionResponse) {
+export function removeDefinitions(data: JSONObject) {
   delete data.m_def
   for (const value of Object.values(data)) {
     if (Array.isArray(value)) {
-      value.forEach((item) => removeDefinitions(item))
+      value
+        .filter((item) => !!item)
+        .forEach((item) => removeDefinitions(item as JSONObject))
     } else if (typeof value === 'object') {
-      removeDefinitions(value as MSectionResponse)
+      removeDefinitions(value as JSONObject)
     }
   }
 
diff --git a/src/components/archive/useArchive.test.tsx b/src/components/archive/useArchive.test.tsx
index 286c36c2416a84639e41c63b087c41d2228c019d..ed3890d666f4494878599d1e1a7f9213db36df51 100644
--- a/src/components/archive/useArchive.test.tsx
+++ b/src/components/archive/useArchive.test.tsx
@@ -5,6 +5,7 @@ import {ArchiveChangeAction} from '../../models/entryEditRequestModels'
 import {MSectionRequest} from '../../models/graphRequestModels'
 import {MSectionResponse} from '../../models/graphResponseModels'
 import {archiveRequest} from '../../pages/entry/entryRoute'
+import {JSONObject} from '../../utils/types'
 import {assert} from '../../utils/utils'
 import * as useRouteData from '../routing/useRouteData'
 import {addDefinitions, mockArchive, removeDefinitions} from './archive.helper'
@@ -13,8 +14,13 @@ import useArchive, {
   allArchives,
   useArchiveChanges,
   useArchiveProperty,
+  useChangedArchives,
 } from './useArchive'
 
+afterEach(() => {
+  allArchives.clear()
+})
+
 describe('useArchive', () => {
   describe('Archive', () => {
     let archive: Archive
@@ -74,11 +80,39 @@ describe('useArchive', () => {
       ],
       [
         'updating an existing repeating SubSection',
-        {r: [{}]},
+        {r: [{q: 1}]},
         {r: '*'},
-        {r: [{}]},
-        {r: [{}]},
-        [],
+        {r: [{q: 2}]},
+        {r: [{q: 2}]},
+        [['r', [{q: 2}]]],
+      ],
+      [
+        'updating and closing hole in a repeating SubSection',
+        {r: [undefined, {q: 2}]},
+        {r: '*'},
+        {r: [{q: 1}, {q: 2}]},
+        {r: [{q: 1}, {q: 2}]},
+        [['r', [{q: 1}, {q: 2}]]],
+      ],
+      [
+        'indirectly updating and closing hole in a repeating SubSection',
+        {r: [undefined, {q: 2}]},
+        {r: {q: '*'}},
+        {r: [{q: 1}, {q: 2}]},
+        {r: [{q: 1}, {q: 2}]},
+        [
+          ['r', [{q: 1}, {q: 2}]],
+          ['r/0/q', 1],
+          ['r/1/q', 2],
+        ],
+      ],
+      [
+        'updating an existing repeating SubSection recursively',
+        {r: [{q: 1}]},
+        {r: {q: '*'}},
+        {r: [{q: 2}]},
+        {r: [{q: 2}]},
+        [['r/0/q', 2]],
       ],
       ['ignoring a repeating SubSection', {r: [{}]}, {}, {}, {r: [{}]}, []],
       // a sub section in a repeating sub section
@@ -90,6 +124,22 @@ describe('useArchive', () => {
         {r: [{}]},
         [['r', [{}]]],
       ],
+      [
+        'index adding to a repeating SubSection with a whole',
+        {},
+        {'r[1]': '*'},
+        {r: [null, {}]},
+        {r: [undefined, {}]},
+        [['r', [undefined, {}]]],
+      ],
+      [
+        'index adding to an existing repeating SubSection',
+        {r: [{q: 1}]},
+        {'r[1]': '*'},
+        {r: [null, {q: 2}]},
+        {r: [{q: 1}, {q: 2}]},
+        [['r/1', {q: 2}]],
+      ],
       [
         'index removing from a repeating SubSection',
         {r: [{}]},
@@ -116,11 +166,38 @@ describe('useArchive', () => {
       ],
       [
         'index updating in a repeating SubSection',
-        {r: [{}]},
+        {r: [{q: 1}]},
         {'r[0]': '*'},
-        {r: [{}]},
-        {r: [{}]},
-        [],
+        {r: [{q: 2}]},
+        {r: [{q: 2}]},
+        [['r/0', {q: 2}]],
+      ],
+      [
+        'index updating a missing section in a repeating SubSection',
+        {r: [undefined, undefined, {q: 2}]},
+        {'r[1]': '*'},
+        {r: [null, {q: 1}]},
+        {r: [undefined, {q: 1}, {q: 2}]},
+        [['r/1', {q: 1}]],
+      ],
+      [
+        'index updating a missing section in a repeating SubSection recursively',
+        {r: [undefined, undefined, {q: 2}]},
+        {'r[1]': {q: '*'}},
+        {r: [null, {q: 1}]},
+        {r: [undefined, {q: 1}, {q: 2}]},
+        [
+          ['r/1', {q: 1}],
+          ['r/1/q', 1],
+        ],
+      ],
+      [
+        'index updating in a repeating SubSection recursively',
+        {r: [{q: 1}]},
+        {'r[0]': {q: '*'}},
+        {r: [{q: 2}]},
+        {r: [{q: 2}]},
+        [['r/0/q', 2]],
       ],
       [
         'ignoring a SubSection in a repeating SubSection',
@@ -167,14 +244,16 @@ describe('useArchive', () => {
         addDefinitions(response, {q: 1, s: {}, r: []})
 
         archive.archive = initialArchive
-        const updates = archive.updateArchive(request, response, {})
+        archive.startUpdate(request)
+        const {changes} = archive.commitUpdate(response, {})
         expect(archive.archive.m_def).not.toBeUndefined()
 
         // remove definitions to make the comparison simpler
-        removeDefinitions(archive.archive)
+        removeDefinitions(archive.archive as JSONObject)
+        removeDefinitions(changes as unknown as JSONObject)
 
         expect(archive.archive).toEqual(expectedArchive)
-        expect(updates).toEqual(expectedUpdates)
+        expect(changes).toEqual(expectedUpdates)
       },
     )
   })
@@ -211,7 +290,10 @@ describe('useArchive', () => {
   it('re-renders on update', () => {
     const {result} = renderHook(() => useArchiveWithRenderCounter('q'))
     expect(result.current.value).toEqual(undefined)
-    act(() => archive.updateArchive({q: '*'}, addDefinitions({q: 1}), {}))
+    act(() => {
+      archive.startUpdate({q: '*'})
+      archive.commitUpdate(addDefinitions({q: 1}), {})
+    })
     expect(result.current.value).toEqual(1)
     expect(renderCounter).toHaveBeenCalledTimes(2)
   })
@@ -219,7 +301,10 @@ describe('useArchive', () => {
   it('does not re-render if something else updates', () => {
     const {result} = renderHook(() => useArchiveWithRenderCounter('q'))
     expect(result.current.value).toEqual(undefined)
-    act(() => archive.updateArchive({s: '*'}, addDefinitions({s: {}}), {}))
+    act(() => {
+      archive.startUpdate({s: '*'})
+      archive.commitUpdate(addDefinitions({s: {}}), {})
+    })
     expect(result.current.value).toEqual(undefined)
     expect(renderCounter).toHaveBeenCalledTimes(1)
   })
@@ -256,8 +341,9 @@ describe('useArchive', () => {
       entry_id: 'otherEntryId',
     })
     const {result, rerender} = renderHook(() => useArchive())
-    result.current.updateArchive(
-      {data: {ref: '*'}},
+    const archive = result.current
+    archive.startUpdate({data: {ref: '*'}})
+    archive.commitUpdate(
       addDefinitions({data: {ref: '/uploads/1/entries/1/archive/data'}}),
       {
         uploads: {
@@ -272,6 +358,109 @@ describe('useArchive', () => {
       q: 'test',
     })
   })
+
+  it.each([
+    ['quantity set', {q: '*'}, {q: 1}, 'q', 'upsert', 2],
+    ['nested quantity set', {s: {q: '*'}}, {s: {q: 1}}, 's/q', 'upsert', 2],
+    [
+      'repeated nested quantity set',
+      {s: [{q: '*'}]},
+      {s: [{q: 1}]},
+      's/0/q',
+      'upsert',
+      2,
+    ],
+    [
+      'repeated nested quantity set unnormalized',
+      {s: [{q: '*'}]},
+      {s: [{q: 1}]},
+      's[0]/q',
+      'upsert',
+      2,
+    ],
+    ['sub-section replace', {s: '*'}, {s: {q: 1}}, 's', 'upsert', {q: 2}],
+    [
+      'repeated sub-section replace implicit',
+      {s: '*'},
+      {s: [{q: 1}]},
+      's',
+      'upsert',
+      [{q: 2}],
+    ],
+    [
+      'repeated sub-section implicit add',
+      {s: '*'},
+      {s: [{q: 1}]},
+      's',
+      'upsert',
+      [{q: 1}, {q: 2}],
+    ],
+    [
+      'repeated sub-section implicit remove',
+      {s: '*'},
+      {s: [{q: 1}, {q: 2}]},
+      's',
+      'upsert',
+      [{q: 1}],
+    ],
+    [
+      'repeated sub-section explicit replace',
+      {s: '*'},
+      {s: [{q: 1}]},
+      's/0',
+      'upsert',
+      {q: 2},
+    ],
+    [
+      'repeated sub-section explicit add',
+      {s: '*'},
+      {s: [{q: 1}]},
+      's/1',
+      'upsert',
+      {q: 2},
+    ],
+    [
+      'repeated sub-section explicit remove',
+      {s: '*'},
+      {s: [{q: 1}, {q: 2}]},
+      's/1',
+      'remove',
+      undefined,
+    ],
+  ])(
+    'does undo/redo %s',
+    (description, request, response, path, action, value) => {
+      const dispatch = vi.fn()
+      const changeListener = vi.fn()
+      const {result} = renderHook(() => useArchive())
+      act(() => {
+        archive.startUpdate(request)
+        archive.commitUpdate(addDefinitions(response), {})
+      })
+      const oldValue = result.current.getValue(path)
+      act(() => {
+        archive.registerElement(path, dispatch)
+        archive.registerChangeListener(changeListener)
+        archive.submitElementChange(path, action as 'upsert' | 'remove', value)
+      })
+      expect(result.current.getValue(path)).toBe(value)
+      expect(dispatch).toHaveBeenCalledTimes(1)
+      expect(changeListener).toHaveBeenCalledTimes(1)
+      expect(result.current.changeStack).toHaveLength(1)
+
+      act(() => result.current.undo())
+      expect(result.current.changeStack).toHaveLength(0)
+      expect(result.current.getValue(path)).toBe(oldValue)
+      expect(dispatch).toHaveBeenCalledTimes(2)
+      expect(changeListener).toHaveBeenCalledTimes(2)
+
+      act(() => result.current.redo())
+      expect(result.current.changeStack).toHaveLength(1)
+      expect(result.current.getValue(path)).toBe(value)
+      expect(dispatch).toHaveBeenCalledTimes(3)
+      expect(changeListener).toHaveBeenCalledTimes(3)
+    },
+  )
 })
 
 describe('useArchiveProperty', () => {
@@ -292,6 +481,7 @@ describe('useArchiveProperty', () => {
     'quantity',
     'sub_section/quantity',
     'repeating_sub_section/0/quantity',
+    'repeating_sub_section[0]/quantity',
     'sub_section/nested_sub_section/quantity',
     'sub_section',
     'sub_section/nested_sub_section',
@@ -386,8 +576,10 @@ describe('useArchiveProperty', () => {
       entry_id: 'otherEntryId',
     })
     const {result} = renderHook(() => useArchive())
-    result.current.updateArchive(
-      {data: {ref: '*'}},
+    const archive = result.current
+
+    archive.startUpdate({data: {ref: '*'}})
+    archive.commitUpdate(
       addDefinitions({data: {ref: '/uploads/1/entries/1/archive/data'}}),
       {
         uploads: {
@@ -430,3 +622,76 @@ describe('useArchiveChanges', () => {
     expect(result.current.changeStack.length).toBe(0)
   })
 })
+
+describe('useChangedArchives', () => {
+  it('returns empty list with no archives', () => {
+    const {result} = renderHook(() => useChangedArchives())
+    expect(result.current).toHaveLength(0)
+  })
+
+  it('returns empty list with no changes', () => {
+    vi.spyOn(useRouteData, 'default').mockReturnValue({
+      entry_id: 'entryId',
+    })
+    renderHook(() => useArchive())
+    const {result} = renderHook(() => useChangedArchives())
+    expect(result.current).toHaveLength(0)
+  })
+
+  it('returns the list of changed archives', () => {
+    mockArchive({
+      entryId: 'entryId0',
+      data: addDefinitions({
+        quantity: 'test_value',
+      }),
+      changes: [{path: 'quantity', new_value: 'new_value', action: 'upsert'}],
+    })
+    mockArchive({
+      clearArchives: false,
+      entryId: 'entryId1',
+      data: addDefinitions({
+        quantity: 'test_value',
+      }),
+      changes: [
+        {path: 'quantity', new_value: 'new_value', action: 'upsert'},
+        {path: 'quantity', new_value: 'new_value', action: 'upsert'},
+      ],
+    })
+    mockArchive({
+      clearArchives: false,
+      entryId: 'entryId2',
+      data: addDefinitions({
+        quantity: 'test_value',
+      }),
+      changes: [],
+    })
+    const {result} = renderHook(() => useChangedArchives())
+    expect(result.current).toHaveLength(2)
+  })
+
+  it('renders on change', () => {
+    const archive = mockArchive({
+      data: addDefinitions({
+        quantity: 'test_value',
+      }),
+    })
+    const {result} = renderHook(() => useChangedArchives())
+    expect(result.current).toHaveLength(0)
+    act(() => archive.submitElementChange('quantity', 'upsert', 'new_value'))
+    expect(result.current).toHaveLength(1)
+  })
+
+  it('renders on new changed archive', () => {
+    const {result} = renderHook(() => useChangedArchives())
+    expect(result.current).toHaveLength(0)
+    act(() =>
+      mockArchive({
+        data: addDefinitions({
+          quantity: 'test_value',
+        }),
+        changes: [{path: 'quantity', new_value: 'new_value', action: 'upsert'}],
+      }),
+    )
+    expect(result.current).toHaveLength(1)
+  })
+})
diff --git a/src/components/archive/useArchive.tsx b/src/components/archive/useArchive.tsx
index 1848762f48eab7454cc335f592d961dbc404f1f8..09bab42a185d89016c0083eebc203b532c5a3e06 100644
--- a/src/components/archive/useArchive.tsx
+++ b/src/components/archive/useArchive.tsx
@@ -11,11 +11,16 @@ import {
   MSectionResponse,
   UploadResponse,
 } from '../../models/graphResponseModels'
-import entryRoute from '../../pages/entry/entryRoute'
+import useEntryRouteData from '../../pages/entry/useEntryRouteData'
 import {Property, Section, resolveRef} from '../../utils/metainfo'
 import {assert} from '../../utils/utils'
 import {getIndexedKey} from '../routing/loader'
-import useRouteData from '../routing/useRouteData'
+
+export type ArchiveChangeConflict = {
+  type: 'parent' | 'child' | 'exact'
+  change: ArchiveChange
+}
+export type ArchiveChangeWithOldValue = ArchiveChange & {oldValue?: unknown}
 
 class MultiMap<K, V> {
   map = new Map<K, V[]>()
@@ -54,28 +59,36 @@ type ArchivePropertyState<T> = {
 
 type ArchivePropertyDispatch = React.Dispatch<ArchivePropertyState<unknown>>
 
+type ArchiveEntry = Pick<
+  EntryResponse,
+  'entry_id' | 'upload_id' | 'mainfile_path'
+>
+
 /**
  * A class to manage the client-side state of an entry's archive. See
  * `useArchive` for the hook that provides access it.
  */
 export class Archive {
+  entry: ArchiveEntry
   elements: MultiMap<string, ArchivePropertyDispatch>
   changeListener: (() => void)[]
   archive: MSectionResponse
-  changeStack: ArchiveChange[]
+  changeStack: ArchiveChangeWithOldValue[]
+  redoStack: ArchiveChangeWithOldValue[]
   loading: boolean
   responsesWithReferencedArchives: MultiMap<string, GraphResponse>
+  currentUpdateRequests: MSectionRequest | undefined
 
-  constructor() {
+  constructor(entry?: ArchiveEntry) {
+    this.entry = entry || {}
     this.elements = new MultiMap<string, ArchivePropertyDispatch>()
     this.changeListener = []
     this.archive = {}
     this.changeStack = []
+    this.redoStack = []
     this.responsesWithReferencedArchives = new MultiMap()
-
-    // TODO loading needs to be integrated with routing and the use of
-    // useDataForRoute
-    this.loading = true
+    this.loading = false
+    this.currentUpdateRequests = undefined
   }
 
   registerElement(path: string, dispatch: ArchivePropertyDispatch) {
@@ -85,6 +98,12 @@ export class Archive {
     }
   }
 
+  /**
+   * Registers a callback that is called when the archive changes.
+   *
+   * @param listener The callback that is called on each change.
+   * @returns A function to unregister the listener.
+   */
   registerChangeListener(listener: () => void) {
     this.changeListener.push(listener)
     return () => {
@@ -99,6 +118,96 @@ export class Archive {
     this.changeListener.forEach((listener) => listener())
   }
 
+  hasUnDoneChanges() {
+    return this.redoStack.length > 0
+  }
+
+  hasChanges() {
+    return this.changeStack.length > 0
+  }
+
+  /**
+   * Removes the last change from the change stack and
+   * - pushes it to the redo stack
+   * - applies the change to the archive
+   * - notifies all components that have registered to the particular path
+   *   via `useArchiveProperty` (and `registerElement`).
+   * - notifies all components that have registered to via `registerChangeListener`.
+   */
+  undo() {
+    const change = this.changeStack.pop()
+    assert(change, 'No changes to undo.')
+    this.applyAndDispatchValue(change.path, change.oldValue)
+    this.redoStack.push(change)
+    if (change) {
+      this.changeListener.forEach((listener) => listener())
+    }
+  }
+
+  /**
+   * Removes the last change from the redo stack and
+   * - pushes it back to the change stack
+   * - applies the change (old value) to the archive
+   * - notifies all components that have registered to the particular path
+   *   via `useArchiveProperty` (and `registerElement`).
+   * - notifies all components that have registered to via `registerChangeListener`.
+   */
+  redo() {
+    const change = this.redoStack.pop()
+    assert(change, 'No changes to redo.')
+    this.applyAndDispatchValue(change.path, change.new_value)
+    this.changeStack.push(change)
+    if (change) {
+      this.changeListener.forEach((listener) => listener())
+    }
+  }
+
+  /**
+   * Perform a change on the archive data and notify all components that have
+   * registered to the particular path via `useArchiveProperty` (and
+   * `registerElement`).
+   *
+   * @param path The path to the property.
+   * @param value The new value to set.
+   * @returns The old value of the property.
+   */
+  private applyAndDispatchValue(path: string, value: unknown) {
+    // apply
+    let current = this.archive
+    const parts = normalizeArchivePath(path)
+    const subSections = parts.slice(0, -1)
+    for (const key of subSections) {
+      current = current[key] as MSectionResponse
+    }
+    const quantityOrIndex = parts[parts.length - 1]
+    const oldValue = current[quantityOrIndex]
+    current[quantityOrIndex] = value
+
+    // additionally remove deleted sub sections at the end of repeated
+    // sub sections
+    if (
+      value === undefined &&
+      Array.isArray(current) &&
+      current.length === parseInt(quantityOrIndex) + 1
+    ) {
+      current.pop()
+    }
+
+    // additionally dispatch the repeated sub section if a section was
+    // added or removed
+    if (Array.isArray(current)) {
+      for (const dispatch of this.elements.get(subSections.join('/'))) {
+        dispatch({value: current, loading: false})
+      }
+    }
+    // dispatch change
+    for (const dispatch of this.elements.get(path)) {
+      dispatch({value, loading: false})
+    }
+
+    return oldValue
+  }
+
   /**
    * Submits a change to the archive. This will update the archive,
    * dispatch the change to all registered elements, and keep track
@@ -116,37 +225,28 @@ export class Archive {
     value: unknown,
     index?: number,
   ) {
-    // apply the value to the archive
-    let current = this.archive
-    const parts = path.split('/')
-    const subSections = parts.slice(0, -1)
-    for (const key of subSections) {
-      current = current[key] as MSectionResponse
-    }
-    const valueIndex = parts[parts.length - 1]
-    current[valueIndex] = value
-
-    // dispatch change
-    for (const dispatch of this.elements.get(path)) {
-      dispatch({value, loading: false})
-    }
+    assert(!this.loading)
+    const oldValue = this.applyAndDispatchValue(path, value)
 
     // translate the change into an ArchiveChange and keep the change in
     // this.changes and this.changeStack
     let change
     if (index !== undefined) {
       assert(Array.isArray(value), 'Value must be an array for indexed changes')
+      assert(Array.isArray(oldValue) || oldValue === undefined)
       change = {
         path: `${path}/${index}`,
         new_value: action === 'remove' ? undefined : {...value[index]},
+        oldValue: action === 'remove' ? oldValue?.[index] : undefined,
         action,
-      } satisfies ArchiveChange
+      } satisfies ArchiveChangeWithOldValue
     } else {
       change = {
         path,
         new_value: action === 'remove' ? undefined : value,
+        oldValue: oldValue,
         action,
-      } satisfies ArchiveChange
+      } satisfies ArchiveChangeWithOldValue
 
       if (this.changeStack.length > 0) {
         const lastChange = this.changeStack[this.changeStack.length - 1]
@@ -173,7 +273,7 @@ export class Archive {
     if (path === '') {
       return current as T
     }
-    for (const key of path.split('/')) {
+    for (const key of normalizeArchivePath(path)) {
       if (current[key] === undefined) {
         return undefined
       }
@@ -215,18 +315,57 @@ export class Archive {
     return resolved
   }
 
+  /**
+   * Detects conflicts between changing the given path and the changes in the
+   * current change stack. The function returns 'parent' if the path is a
+   * prefix to a path in the change stack, 'child' if a path in the change stack
+   * is a prefix to the given path, 'none' if there is no conflict, and 'exact'
+   * of the path is exactly the same as a path in the change stack.
+   * If multiple conflicting changes exist, the function returns the change
+   * with the shortest path.
+   */
+  conflictsWithChangeStack(path: string): ArchiveChangeConflict | undefined {
+    // TODO if this ever causes performance issues (On), we need to use some more
+    // efficient data structure here, e.g. represent the change stack as a
+    // tree (Ologn).
+    const conflicts: ArchiveChangeConflict[] = []
+    for (const change of this.changeStack) {
+      if (change.path === path) {
+        conflicts.push({type: 'exact', change})
+      }
+      if (change.path.startsWith(path)) {
+        conflicts.push({type: 'parent', change})
+      }
+      if (path.startsWith(change.path)) {
+        conflicts.push({type: 'child', change})
+      }
+    }
+
+    if (conflicts.length === 0) {
+      return undefined
+    }
+
+    return conflicts.sort(
+      (a, b) => a.change.path.length - b.change.path.length,
+    )[0]
+  }
+
   /**
    * Merges new archive data represented as a request/response pair into the
    * archive. It detects a collection of changes and dispatches them to the
    * registered elements.
+   *
+   * TODO what happens when the update effects something that we already
+   * have local user changes for?
    */
-  updateArchive(
+  private updateArchive(
     request: MSectionRequest,
     response: MSectionResponse,
     apiResponse: GraphResponse,
     path?: string,
   ) {
     const changes: [string, unknown][] = []
+    const conflicts: ArchiveChangeConflict[] = []
 
     // collect referenced archives (this might include the current one for
     // intra-entry references)
@@ -251,6 +390,16 @@ export class Archive {
       })
     })
 
+    const checkForConflicts = (path: string) => {
+      const conflict = this.conflictsWithChangeStack(path)
+      if (conflict) {
+        conflicts.push(conflict)
+        return true
+      } else {
+        return false
+      }
+    }
+
     // traverse
     const visit = (
       path: string,
@@ -258,6 +407,7 @@ export class Archive {
       originalRequest: MSectionRequest,
       response: MSectionResponse,
     ) => {
+      assert(archive && response)
       const m_def = response.m_def as Section
       assert(m_def, `MSectionResponse for ${path} must come with a definition`)
       // TODO Is this good? Do we need to merge something here? What if
@@ -311,6 +461,10 @@ export class Archive {
 
         if (response[key] === undefined) {
           // delete
+          if (checkForConflicts(pathForCurrentKey)) {
+            continue
+          }
+
           if (!archive[key]) {
             continue
           }
@@ -331,50 +485,92 @@ export class Archive {
           changes.push([pathForCurrentKey, response[key]])
         } else if (archive[key] === undefined) {
           // add
+          if (checkForConflicts(pathForCurrentKey)) {
+            continue
+          }
+
           if (indexed) {
-            const archiveList =
-              (archive[key] as unknown as MSectionResponse[]) || []
+            const archiveList: MSectionResponse[] = []
             archive[key] = archiveList
             const responseList = response[key] as MSectionResponse[]
-            archiveList[index] = responseList[index]
+            archiveList[index] = responseList[index] || undefined
+            changes.push([
+              pathForCurrentKey,
+              responseList.map((item) => item || undefined),
+            ])
           } else {
             archive[key] = response[key]
+            changes.push([pathForCurrentKey, response[key]])
           }
-
-          changes.push([pathForCurrentKey, response[key]])
         } else {
           // update
           if (!childIsSubSection) {
+            if (checkForConflicts(pathForCurrentKey)) {
+              continue
+            }
+
             archive[key] = response[key]
             changes.push([pathForCurrentKey, response[key]])
           } else if (childIsRepeatingSubSection) {
-            // The semantics is that the sections with the same index are
-            // the same. Even if a section is removed from the middle of the
-            // list.
-            // The recursion will update the sections themsleves.
-            // Here, we only remove/add at the end of the list.
-            const archiveList = archive[key] as MSectionResponse[]
-            archive[key] = archiveList
-            const responseList = response[key] as MSectionResponse[]
-            if (responseList.length !== archiveList.length) {
-              if (responseList.length > archiveList.length) {
-                for (
-                  let index = archiveList.length;
-                  index < responseList.length;
-                  index++
-                ) {
-                  archiveList.push(responseList[index])
-                }
+            if (indexed) {
+              const indexedPathForCurrentKey = `${pathForCurrentKey}/${index}`
+              if (checkForConflicts(indexedPathForCurrentKey)) {
+                continue
               }
-              if (responseList.length < archiveList.length) {
-                archiveList.splice(
-                  responseList.length,
-                  archiveList.length - responseList.length,
-                )
+
+              const archiveList = archive[key] as MSectionResponse[]
+              const responseList = response[key] as MSectionResponse[]
+              if (archiveList[index]) {
+                // update
+                if (requestValue === '*') {
+                  archiveList[index] = responseList[index] || undefined
+                  changes.push([indexedPathForCurrentKey, responseList[index]])
+                } // else { nothing to do, the recursion will update the section }
+              } else {
+                // add
+                archiveList[index] = responseList[index] || undefined
+                changes.push([indexedPathForCurrentKey, responseList[index]])
+              }
+            } else {
+              if (checkForConflicts(pathForCurrentKey)) {
+                continue
               }
-              changes.push([pathForCurrentKey, response[key]])
+
+              // The semantics is that the sections with the same index are
+              // the same. Even if a section is removed from the middle of the
+              // list.
+              // We remove/add at the end of the list, if the response is shorter/longer.
+              // We replace the section, if the request was about the whole sections.
+              // We leave it to recursion if the request goes deeper into the sections.
+              const archiveList = archive[key] as MSectionResponse[]
+              assert(
+                Array.isArray(archiveList),
+                `Expected array for key "${key}", but got "${archiveList}"`,
+              )
+              const responseList = response[key] as MSectionResponse[]
+              if (responseList.length !== archiveList.length) {
+                if (responseList.length > archiveList.length) {
+                  for (
+                    let index = archiveList.length;
+                    index < responseList.length;
+                    index++
+                  ) {
+                    archiveList.push(responseList[index] || undefined)
+                  }
+                }
+                if (responseList.length < archiveList.length) {
+                  archiveList.splice(
+                    responseList.length,
+                    archiveList.length - responseList.length,
+                  )
+                }
+                changes.push([pathForCurrentKey, response[key]])
+              } else if (requestValue === '*') {
+                archive[key] = response[key]
+                changes.push([pathForCurrentKey, response[key]])
+              } // else { nothing to do, the recursion will update the section }
             }
-          } // else { nothing to do, the recursion will update the section }
+          }
         }
 
         // recurse
@@ -392,8 +588,22 @@ export class Archive {
             const archiveList = archive[key] as MSectionResponse[]
             const responseList = response[key] as MSectionResponse[]
             for (let index = 0; index < responseList.length; index++) {
+              const archiveListItem = archiveList[index] || undefined
+              archiveList[index] = archiveListItem
+              const indexedPathForCurrentKey = `${pathForCurrentKey}/${index}`
+              if (archiveListItem === undefined) {
+                // patching a hole in the list
+                if (checkForConflicts(indexedPathForCurrentKey)) {
+                  continue
+                }
+                archiveList[index] = responseList[index] || undefined
+                changes.push([
+                  pathForCurrentKey,
+                  responseList.map((item) => item || undefined),
+                ])
+              }
               visit(
-                `${pathForCurrentKey}/${index}`,
+                indexedPathForCurrentKey,
                 archiveList[index],
                 requestValue as MSectionRequest,
                 responseList[index],
@@ -419,29 +629,71 @@ export class Archive {
       visit('', this.archive, request, response)
     }
 
-    // TODO the loading state needs to be properly handled.
-    if (this.loading) {
-      this.loading = false
-      for (const [path, elements] of this.elements.map.entries()) {
-        for (const dispatch of elements) {
+    if (!this.loading) {
+      for (const [path, value] of changes) {
+        for (const dispatch of this.elements.get(path)) {
           dispatch?.({
-            value: this.getValue(path),
+            value,
             loading: false,
           })
         }
       }
-    } else {
-      for (const [path, value] of changes) {
-        for (const dispatch of this.elements.get(path)) {
+    }
+
+    return {
+      changes,
+      conflicts,
+    }
+  }
+
+  startUpdate(request: MSectionRequest, setLoading: boolean = false) {
+    assert(
+      this.currentUpdateRequests === undefined,
+      'Update already in progress',
+    )
+    this.currentUpdateRequests = request
+    if (setLoading) {
+      this.setLoading(true)
+    }
+  }
+
+  commitUpdate(
+    response: MSectionResponse,
+    apiResponse: GraphResponse,
+  ): {changes: [string, unknown][]; conflicts: ArchiveChangeConflict[]} {
+    assert(this.currentUpdateRequests, 'No update in progress')
+    const result = this.updateArchive(
+      this.currentUpdateRequests,
+      response,
+      apiResponse,
+    )
+    this.currentUpdateRequests = undefined
+    this.setLoading(false)
+    return result
+  }
+
+  abortUpdate() {
+    this.currentUpdateRequests = undefined
+    this.setLoading(false)
+  }
+
+  private setLoading(loading: boolean) {
+    if (this.loading === loading) {
+      return
+    }
+
+    this.loading = loading
+
+    if (!this.loading) {
+      for (const [path, elements] of this.elements.map.entries()) {
+        for (const dispatch of elements) {
           dispatch?.({
-            value,
+            value: this.getValue(path),
             loading: false,
           })
         }
       }
     }
-
-    return changes
   }
 
   /**
@@ -458,11 +710,13 @@ export class Archive {
     assert(pathWithoutIndex, `Invalid property path ${path}`)
 
     let section = this.archive
+    assert(section, 'No archive loaded')
     const parts = path.split('/')
     const subSections = parts.slice(0, -1)
     const property = parts[parts.length - 1]
     for (const key of subSections) {
       section = section[key] as MSectionResponse
+      assert(section, `No section for path ${path}, ${key} is missing`)
     }
     const sectionDef = section.m_def as Section
     const propertyDef = sectionDef?.all_properties?.[property]
@@ -477,11 +731,30 @@ export class Archive {
 
 export const allArchives = new Map<string, Archive>()
 
-export function getArchive(entry_id: string) {
+export function getArchive(entry_id: string, entry?: ArchiveEntry) {
   if (!allArchives.has(entry_id)) {
-    allArchives.set(entry_id, new Archive())
+    const archive = new Archive(entry)
+    allArchives.set(entry_id, archive)
+    allArchivesChangeListeners.forEach((listener) => listener())
+  }
+  const archive = allArchives.get(entry_id) as Archive
+  archive.entry = {...archive.entry, ...entry}
+  return archive
+}
+
+const allArchivesChangeListeners = new Set<() => void>()
+
+/**
+ * Registers a callback that is called when a new archive is created.
+ *
+ * @param listener The callback that is called when a new archive is created.
+ * @returns A function to unregister the listener.
+ */
+function registerArchivesChangeListener(listener: () => void) {
+  allArchivesChangeListeners.add(listener)
+  return () => {
+    allArchivesChangeListeners.delete(listener)
   }
-  return allArchives.get(entry_id) as Archive
 }
 
 /**
@@ -490,16 +763,68 @@ export function getArchive(entry_id: string) {
  * the client-side state of the archive. This includes the archive data
  * updated from the latest API requests and user changes, the stack of
  * unsaved changes, and a registry for components listening to properties
- * of the archive via `useArhiveProperty`.
+ * of the archive via `useArchiveProperty`.
+ *
+ * The archive is constant for the current entry and this hook will not
+ * re-render on archive changes. Use `useArchiveChanges` or `useArchiveProperty`
+ * or `useChangedArchives` to react to changes.
  */
 export default function useArchive() {
-  const {entry_id} = useRouteData(entryRoute)
+  const {entry_id, mainfile_path, upload_id} = useEntryRouteData()
   assert(entry_id, 'UseArchive only works within an entry route.')
-  return getArchive(entry_id)
+  return getArchive(entry_id, {entry_id, upload_id, mainfile_path})
+}
+
+/**
+ * A hook that returns a list of all archives that have been loaded and
+ * re-renders when a new archive is loaded.
+ */
+function useArchives() {
+  const [archives, setArchives] = useState<Archive[]>(
+    Array.from(allArchives.values()),
+  )
+
+  useEffect(() => {
+    return registerArchivesChangeListener(() => {
+      setArchives(Array.from(allArchives.values()))
+    })
+  }, [])
+
+  return archives
+}
+
+/**
+ * A hook that returns a list of archives that have unsaved changes.
+ * The hook causes a re-render, if there are new changes.
+ */
+export function useChangedArchives() {
+  const archives = useArchives()
+
+  const [changedArchives, setChangedArchives] = useState<Archive[]>(
+    archives.filter((archive) => archive.hasChanges()),
+  )
+
+  useEffect(() => {
+    const handleChange = () => {
+      setChangedArchives(archives.filter((archive) => archive.hasChanges()))
+    }
+
+    const listeners = Array.from(allArchives.values()).map((archive) =>
+      archive.registerChangeListener(handleChange),
+    )
+
+    handleChange()
+
+    return () => {
+      listeners.forEach((unregister) => unregister())
+    }
+  }, [archives])
+
+  return changedArchives
 }
 
 export type ArchiveChanges = {
-  changeStack: ArchiveChange[]
+  changeStack: ArchiveChangeWithOldValue[]
   clearChangeStack: () => void
   // undo: () => void,
   // redo: () => void,
@@ -511,7 +836,7 @@ export type ArchiveChanges = {
  */
 export function useArchiveChanges() {
   const archive = useArchive()
-  const [changeStack, setChangeStack] = useState<ArchiveChange[]>([
+  const [changeStack, setChangeStack] = useState<ArchiveChangeWithOldValue[]>([
     ...archive.changeStack,
   ])
 
@@ -570,6 +895,27 @@ export type ArchiveProperty<Type, DefinitionType extends Property> = {
   resolveRef: (ref: string) => MSectionResponse | undefined
 }
 
+/**
+ * Normalizes the use of repeated sub section syntax in paths. The
+ * normalized syntax uses index segments (e.g. `section/0`) instead
+ * of having the index in the sub section segment (e.g. `section[0]`).
+ *
+ * @param path The path to normalize.
+ * @returns The normalized path.
+ */
+function normalizeArchivePath(path: string) {
+  const result: string[] = []
+  path.split('/').forEach((segment) => {
+    const match = segment.match(/([^[]+)\[(\d+)\]$/)
+    if (match) {
+      result.push(match[1], match[2])
+    } else {
+      result.push(segment)
+    }
+  })
+  return result
+}
+
 /**
  * A hook that interacts with the archive of the current entry. It allows
  * to get, set, and react to changes of individual properties in the archive.
@@ -579,7 +925,7 @@ export type ArchiveProperty<Type, DefinitionType extends Property> = {
  * root to the property. The paths use `/` as separator and align with the syntax
  * of the graph API or archive references.
  *
- * What it means that an propery changes depends on the
+ * What it means that an property changes depends on the
  * kind of property. A quantity value changes if the value changes, a (repeating)
  * sub-section changes if a/the section is added, removed, or replaced.
  *
@@ -592,6 +938,7 @@ export type ArchiveProperty<Type, DefinitionType extends Property> = {
 export function useArchiveProperty<T = unknown, D extends Property = Property>(
   path: string,
 ): ArchiveProperty<T, D> {
+  path = normalizeArchivePath(path).join('/')
   const archive = useArchive()
 
   const previousPath = usePrevious(path)
@@ -600,8 +947,6 @@ export function useArchiveProperty<T = unknown, D extends Property = Property>(
     'Archive path must not change',
   )
 
-  // TODO the value in the archive might have changed for the same path,
-  // but we keep relying on the old and wrong localState.
   const propertyState = archive.getState(path) as ArchivePropertyState<T>
   const render = useRender()
 
diff --git a/src/components/editor/useSubSectionPath.tsx b/src/components/archive/useSubSectionPath.tsx
similarity index 100%
rename from src/components/editor/useSubSectionPath.tsx
rename to src/components/archive/useSubSectionPath.tsx
diff --git a/src/components/editor/ImagePreviewItem.tsx b/src/components/editor/ImagePreviewItem.tsx
index 96d89a3d179082e54478a7607216c3f84436e609..7ca4b4f61e053c4e2a1e532b07ff938b3056701f 100644
--- a/src/components/editor/ImagePreviewItem.tsx
+++ b/src/components/editor/ImagePreviewItem.tsx
@@ -1,9 +1,9 @@
 import {Skeleton} from '@mui/material'
 
 import {useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
 import {LayoutItem} from '../layout/Layout'
 import {AbstractProperty} from './PropertyEditor'
-import useSubSectionPath from './useSubSectionPath'
 
 export type ImagePreview = AbstractProperty & {
   type: 'imagePreview'
diff --git a/src/components/editor/PlotEditor.tsx b/src/components/editor/PlotEditor.tsx
index 0f0076473c67ee8c85d92898b17fb5a098830fda..4e55e97e6da53110fe4e90a75e9c32effa2700e2 100644
--- a/src/components/editor/PlotEditor.tsx
+++ b/src/components/editor/PlotEditor.tsx
@@ -3,9 +3,9 @@ import {useLayoutEffect, useRef} from 'react'
 import {useAsync} from 'react-use'
 
 import {useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
 import {LayoutItem} from '../layout/Layout'
 import {AbstractProperty} from './PropertyEditor'
-import useSubSectionPath from './useSubSectionPath'
 
 export type Plot = AbstractProperty & {
   type: 'plot'
diff --git a/src/components/editor/QuantityEditor.tsx b/src/components/editor/QuantityEditor.tsx
index 987bf2de03dd7470dd2a0ca1263a7d8126a23ef8..6eec46fa1106c74a7fe4008b766b1f042e140b51 100644
--- a/src/components/editor/QuantityEditor.tsx
+++ b/src/components/editor/QuantityEditor.tsx
@@ -3,6 +3,7 @@ import {useCallback} from 'react'
 
 import {Quantity as QuantityDefinition} from '../../utils/metainfo'
 import {useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
 import {LayoutItem} from '../layout/Layout'
 import ContainerProps, {
   DynamicContainerProps,
@@ -13,7 +14,6 @@ import {
   createDynamicComponentSpec,
 } from '../values/utils/dynamicComponents'
 import {AbstractProperty, getLabel} from './PropertyEditor'
-import useSubSectionPath from './useSubSectionPath'
 
 export type Quantity = AbstractProperty & {
   type: 'quantity'
diff --git a/src/components/editor/RichTextEditor.tsx b/src/components/editor/RichTextEditor.tsx
index 2c443b361f0f38429bd18571c9cc113ae166e439..7f48ed0fc94612b54a689a8563f53c8626030115 100644
--- a/src/components/editor/RichTextEditor.tsx
+++ b/src/components/editor/RichTextEditor.tsx
@@ -2,10 +2,10 @@ import {Skeleton} from '@mui/material'
 import {useCallback, useRef} from 'react'
 
 import {useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
 import {LayoutItem} from '../layout/Layout'
 import Editor, {RichTextEditorProps} from '../richText/RichTextEditor'
 import {AbstractProperty, getLabel} from './PropertyEditor'
-import useSubSectionPath from './useSubSectionPath'
 
 export type RichText = AbstractProperty & {
   type: 'richText'
diff --git a/src/components/editor/SubSectionEditor.tsx b/src/components/editor/SubSectionEditor.tsx
index 8b67c02b3bb99dd084d710c81a257548c168966f..53cf63f2fdb8d04930a2848b9f6ec80a5720ecc5 100644
--- a/src/components/editor/SubSectionEditor.tsx
+++ b/src/components/editor/SubSectionEditor.tsx
@@ -1,27 +1,17 @@
 import {Box, Button, IconButton} from '@mui/material'
 import Grid from '@mui/material/Grid2'
-import {PropsWithChildren, useCallback} from 'react'
+import {useCallback} from 'react'
 
 import {MSectionResponse} from '../../models/graphResponseModels'
 import {SubSection as SubSectionDefinition} from '../../utils/metainfo'
 import {assert, splice} from '../../utils/utils'
+import SectionProvider from '../archive/SectionProvider'
 import {ArchiveProperty, useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
 import {Remove} from '../icons'
 import {Item, Layout, LayoutItem} from '../layout/Layout'
-import {layoutPropsContext} from '../layout/useLayoutProps'
+import {editableLayout, layoutPropsContext} from '../layout/useLayoutProps'
 import {AbstractProperty, getLabel} from './PropertyEditor'
-import useSubSectionPath, {subSectionContext} from './useSubSectionPath'
-
-function SectionProvider({
-  path: path,
-  children,
-}: {path: string} & PropsWithChildren) {
-  return (
-    <subSectionContext.Provider value={{path}}>
-      {children}
-    </subSectionContext.Provider>
-  )
-}
 
 function SubSectionComponent({
   label,
@@ -163,7 +153,11 @@ type SubSectionData = MSectionResponse | MSectionResponse[] | undefined
  */
 export default function SubSectionEditor({layout}: {layout: LayoutItem}) {
   const subSection = layout as SubSection
-  const {property: propertyName, layout: subSectionLayout} = subSection
+  const {
+    property: propertyName,
+    layout: subSectionLayout,
+    editable,
+  } = subSection
   const label = getLabel(subSection)
   const path = useSubSectionPath(propertyName)
 
@@ -183,7 +177,7 @@ export default function SubSectionEditor({layout}: {layout: LayoutItem}) {
   return (
     <SubSectionComponent
       label={label}
-      layout={subSectionLayout}
+      layout={editableLayout(subSectionLayout, editable)}
       property={property}
     />
   )
diff --git a/src/components/editor/SubSectionNavEditor.test.tsx b/src/components/editor/SubSectionNavEditor.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f64dd1d8f19de92b6a8628a3326cf96928e38e27
--- /dev/null
+++ b/src/components/editor/SubSectionNavEditor.test.tsx
@@ -0,0 +1,226 @@
+import {Link} from '@mui/material'
+import {act, render, screen} from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+import {PropsWithChildren} from 'react'
+import {vi} from 'vitest'
+
+import entryRoute from '../../pages/entry/entryRoute'
+import {addDefinitions, mockArchive} from '../archive/archive.helper'
+import {Layout} from '../layout/Layout'
+import {RouteData} from '../routing/types'
+import * as useRoute from '../routing/useRoute'
+import * as useRouter from '../routing/useRouter'
+import {SubSectionNav} from './SubSectionNavEditor'
+
+describe('SubSectionNavEditor', async () => {
+  const layout = {
+    type: 'subSectionNav',
+    property: 'test_subsection',
+    editable: true,
+  } as SubSectionNav
+
+  function mockData(args?: {
+    repeats?: boolean
+    withLoading?: boolean
+    empty?: boolean
+    definitionsExtra?: Record<string, unknown>
+  }) {
+    const {
+      repeats = false,
+      withLoading = false,
+      empty = false,
+      definitionsExtra,
+    } = args || {}
+    const defaultSubSectionData = {
+      test_quantity: 'test_value',
+    }
+    let subSectionData
+    if (repeats) {
+      if (empty) {
+        subSectionData = []
+      } else {
+        subSectionData = [defaultSubSectionData]
+      }
+    } else {
+      if (empty) {
+        subSectionData = undefined
+      } else {
+        subSectionData = defaultSubSectionData
+      }
+    }
+    const data = addDefinitions(
+      {
+        ...(subSectionData
+          ? {
+              test_subsection: subSectionData,
+            }
+          : {}),
+      },
+      definitionsExtra,
+    )
+    return mockArchive({
+      data: withLoading ? undefined : data,
+    })
+  }
+
+  const url = vi.fn()
+  vi.spyOn(useRoute, 'default').mockReturnValue({
+    url,
+    fullMatch: [
+      {
+        path: '/test',
+        route: {...entryRoute, path: '/test'},
+      },
+    ],
+  } as unknown as RouteData)
+
+  const createLink = vi
+    .fn()
+    .mockImplementation(({to, ...props}: {to: string} & PropsWithChildren) => (
+      <Link href={to} {...props} />
+    ))
+  vi.spyOn(useRouter, 'default').mockReturnValue({
+    createLink,
+  } as unknown as useRouter.RouterValue)
+
+  beforeEach(() => {
+    url.mockReset()
+  })
+
+  it('initially renders with loading indicator', async () => {
+    mockData({withLoading: true})
+    render(<Layout layout={layout} />)
+    expect(screen.queryByText('test subsection')).not.toBeInTheDocument()
+  })
+
+  it('renders sub section', async () => {
+    mockData()
+    render(<Layout layout={layout} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    expect(url).toHaveBeenCalledWith({path: '/test/archive/test_subsection'})
+  })
+
+  it('allows to remove non repeating sub section', async () => {
+    const archive = mockData()
+    render(<Layout layout={layout} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    await userEvent.click(screen.getByRole('button', {name: 'remove'}))
+
+    expect(archive.changeStack.length).toBe(1)
+    expect(archive.changeStack[0]).toMatchObject({
+      action: 'remove',
+      new_value: undefined,
+      path: 'test_subsection',
+    })
+  })
+
+  it('hides remove button for non repeating sub section if not editable', async () => {
+    mockData()
+    render(<Layout layout={{...layout, editable: false}} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    expect(
+      screen.queryByRole('button', {name: 'remove'}),
+    ).not.toBeInTheDocument()
+  })
+
+  it('allows to add non repeating sub section', async () => {
+    const archive = mockData({
+      empty: true,
+      definitionsExtra: {test_subsection: {test_quantity: 'test_value'}},
+    })
+    render(<Layout layout={layout} />)
+    const addButton = screen.getByRole('button', {name: 'add'})
+    expect(addButton).toBeInTheDocument()
+    await userEvent.click(addButton)
+
+    expect(archive.changeStack.length).toBe(1)
+    expect(archive.changeStack[0]).toMatchObject({
+      action: 'upsert',
+      new_value: expect.objectContaining({m_def: expect.objectContaining({})}),
+      path: 'test_subsection',
+    })
+  })
+
+  it('hides add button for non repeating sub section if not editable', async () => {
+    mockData({
+      empty: true,
+      definitionsExtra: {test_subsection: {test_quantity: 'test_value'}},
+    })
+    render(<Layout layout={{...layout, editable: false}} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    expect(screen.queryByRole('button', {name: 'add'})).not.toBeInTheDocument()
+  })
+
+  it('renders repeating sub section', async () => {
+    mockData({repeats: true})
+    render(<Layout layout={layout} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    expect(url).not.toHaveBeenCalled()
+  })
+
+  it('expands repeating sub section', async () => {
+    mockData({repeats: true})
+    render(<Layout layout={layout} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    await act(async () => {
+      await userEvent.click(screen.getByText('test subsection'))
+    })
+    expect(screen.getByText('0')).toBeInTheDocument()
+    expect(url).toHaveBeenCalledWith({path: '/test/archive/test_subsection[0]'})
+  })
+
+  it('allows to remove repeating sub section', async () => {
+    url.mockReturnValue('/test/archive/test_subsection[0]')
+    const archive = mockData({repeats: true})
+    render(<Layout layout={layout} />)
+    await act(async () => {
+      await userEvent.click(screen.getByText('test subsection'))
+    })
+    const removeButton = screen.getByRole('button', {name: 'remove'})
+    await userEvent.click(removeButton)
+
+    expect(archive.changeStack.length).toBe(1)
+    expect(archive.changeStack[0]).toMatchObject({
+      action: 'remove',
+      new_value: {},
+      path: 'test_subsection/0',
+    })
+  })
+
+  it('hides remove button for repeating sub section if not editable', async () => {
+    mockData({repeats: true})
+    render(<Layout layout={{...layout, editable: false}} />)
+    await act(async () => {
+      await userEvent.click(screen.getByText('test subsection'))
+    })
+    expect(screen.getByText('0')).toBeInTheDocument()
+    expect(
+      screen.queryByRole('button', {name: 'remove'}),
+    ).not.toBeInTheDocument()
+  })
+
+  it('allows to add repeating sub section', async () => {
+    const archive = mockData({
+      empty: true,
+      repeats: true,
+      definitionsExtra: {test_subsection: [{test_quantity: 'test_value'}]},
+    })
+    render(<Layout layout={layout} />)
+    const addButton = screen.getByRole('button', {name: 'add'})
+    await userEvent.click(addButton)
+
+    expect(archive.changeStack.length).toBe(1)
+    expect(archive.changeStack[0]).toMatchObject({
+      action: 'upsert',
+      new_value: expect.objectContaining({}),
+      path: 'test_subsection/0',
+    })
+  })
+
+  it('hides add button for repeating sub section if not editable', async () => {
+    mockData({empty: true, repeats: true})
+    render(<Layout layout={{...layout, editable: false}} />)
+    expect(screen.getByText('test subsection')).toBeInTheDocument()
+    expect(screen.queryByRole('button', {name: 'add'})).not.toBeInTheDocument()
+  })
+})
diff --git a/src/components/editor/SubSectionNavEditor.tsx b/src/components/editor/SubSectionNavEditor.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..40709f8236ca1d0f74e58d2045ef4d2e2e732deb
--- /dev/null
+++ b/src/components/editor/SubSectionNavEditor.tsx
@@ -0,0 +1,278 @@
+import {Box, IconButton, Skeleton, Typography} from '@mui/material'
+import {MouseEventHandler, useCallback, useMemo, useState} from 'react'
+
+import Link from '../../components/routing/Link'
+import {MSectionResponse} from '../../models/graphResponseModels'
+import {appEntryRoute} from '../../pages/apps/appsRoute'
+import entryRoute from '../../pages/entry/entryRoute'
+import {SubSection as SubSectionDefinition} from '../../utils/metainfo'
+import {assert, splice} from '../../utils/utils'
+import {ArchiveProperty, useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
+import {Add, Remove} from '../icons'
+import {LayoutItem} from '../layout/Layout'
+import NavItem from '../navigation/NavItem'
+import useRoute from '../routing/useRoute'
+import {AbstractProperty, getLabel} from './PropertyEditor'
+
+function SubSectionNavComponent({
+  label,
+  property,
+  editable,
+}: {
+  label: string
+  property: ArchiveProperty<SubSectionData, SubSectionDefinition>
+  editable?: boolean
+}) {
+  const {url, fullMatch} = useRoute()
+  const {value, getDefinition, change, path} = property
+  const definition = useMemo(() => getDefinition(), [getDefinition])
+  const repeats = definition?.repeats
+
+  const entryRouteIndex = useMemo(() => {
+    const entryRouteIndex = fullMatch.findIndex(
+      (part) => part.route.routeId === entryRoute.routeId,
+    )
+    const appEntryRouteIndex = fullMatch.findIndex(
+      (part) => part.route.routeId === appEntryRoute.routeId,
+    )
+    return entryRouteIndex === -1 ? appEntryRouteIndex : entryRouteIndex
+  }, [fullMatch])
+
+  const archivePath =
+    fullMatch
+      .filter((part, index) => index <= entryRouteIndex)
+      .map((part) => part.path)
+      .join('/') + '/archive'
+
+  // TODO implement remove and add
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  const handleRemove = useCallback(
+    (event: React.MouseEvent<HTMLSpanElement>, index?: number) => {
+      event.stopPropagation()
+      event.nativeEvent.stopImmediatePropagation()
+      event.preventDefault()
+      if (repeats) {
+        assert(
+          index !== undefined,
+          'Update operation on repeating sub section without index',
+        )
+        change(
+          'remove',
+          splice((value || []) as MSectionResponse[], index, 1),
+          index,
+        )
+      } else {
+        change('remove', undefined)
+      }
+    },
+    [repeats, change, value],
+  )
+
+  // TODO implement remove and add
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  const handleAdd = useCallback<MouseEventHandler<HTMLSpanElement>>(
+    (event) => {
+      // TODO the definition might not be available. With an improved
+      // useArchive implementation, it might still be just a references and
+      // we might still need to explicitly fetch to actual definition.
+      // I.e., getDefinition() might need to be async.
+      event.stopPropagation()
+      event.nativeEvent.stopImmediatePropagation()
+      event.preventDefault()
+      const newSubSectionData = {
+        m_def: getDefinition()?.sub_section,
+      } as MSectionResponse
+      if (repeats) {
+        assert(value === undefined || Array.isArray(value))
+        change(
+          'upsert',
+          [...((value || []) as MSectionResponse[]), newSubSectionData],
+          (value || []).length,
+        )
+      } else {
+        change('upsert', newSubSectionData)
+      }
+    },
+    [repeats, change, value, getDefinition],
+  )
+
+  const [expanded, setExpanded] = useState(false)
+  const handleExpand = useCallback(() => {
+    setExpanded((expanded) => !expanded)
+  }, [])
+
+  if (repeats) {
+    assert(value === undefined || Array.isArray(value))
+    const subSections = value || []
+    return (
+      <NavItem
+        label={label}
+        variant='wide'
+        expandable
+        expanded={expanded}
+        onToggle={handleExpand}
+        onSelect={handleExpand}
+        actions={
+          editable && (
+            <IconButton
+              component='span'
+              size='small'
+              onClick={handleAdd}
+              aria-label='add'
+              title='add'
+            >
+              <Add />
+            </IconButton>
+          )
+        }
+        sx={{
+          margin: -1,
+          '& .NavItem-button': {
+            paddingX: 1.5,
+          },
+        }}
+      >
+        {expanded && (
+          <Box
+            sx={{
+              display: 'flex',
+              flexDirection: 'column',
+              gap: 2,
+              marginBottom: 1,
+            }}
+          >
+            {subSections.length === 0 ? (
+              <Typography
+                sx={(theme) => ({
+                  marginLeft: 6,
+                  fontStyle: 'italic',
+                  color: theme.palette.action.disabled,
+                })}
+              >
+                empty
+              </Typography>
+            ) : (
+              subSections.map((subSection, index) => (
+                <NavItem
+                  key={index}
+                  variant='wide'
+                  label={`${index}`}
+                  expandable={false}
+                  expanded={false}
+                  component={Link}
+                  to={url({path: `${archivePath}/${path}[${index}]`})}
+                  actions={
+                    editable && (
+                      <IconButton
+                        component='span'
+                        size='small'
+                        onClick={(event) => handleRemove(event, index)}
+                        aria-label='remove'
+                        title='remove'
+                      >
+                        <Remove />
+                      </IconButton>
+                    )
+                  }
+                  sx={{
+                    margin: -1,
+                    '& .NavItem-button': {
+                      paddingLeft: 6,
+                    },
+                  }}
+                />
+              ))
+            )}
+          </Box>
+        )}
+      </NavItem>
+    )
+  }
+
+  return (
+    <NavItem
+      disabled={value === undefined}
+      label={label}
+      expandable={false}
+      expanded={false}
+      component={Link}
+      to={url({path: `${archivePath}/${path}`})}
+      variant='wide'
+      sx={{
+        margin: -1,
+        '& .NavItem-button': {
+          paddingX: 1.5,
+        },
+      }}
+      actions={
+        editable &&
+        (value !== undefined ? (
+          <IconButton
+            component='span'
+            size='small'
+            onClick={handleRemove}
+            aria-label='remove'
+            title='remove'
+          >
+            <Remove />
+          </IconButton>
+        ) : (
+          <IconButton
+            component='span'
+            size='small'
+            onClick={handleAdd}
+            aria-label='add'
+            title='add'
+            sx={{pointerEvents: 'auto'}}
+          >
+            <Add />
+          </IconButton>
+        ))
+      }
+    />
+  )
+}
+export type SubSectionNav = AbstractProperty & {
+  type: 'subSectionNav'
+}
+
+type SubSectionData = MSectionResponse | MSectionResponse[] | undefined
+
+/**
+ * Renders all sections in a sub section including actions to modify
+ * the sub section. Uses SectionEditor to render each sub section.
+ */
+export default function SubSectionNavEditor({layout}: {layout: LayoutItem}) {
+  const subSection = layout as SubSectionNav
+  const {property: propertyName, editable} = subSection
+  const label = getLabel(subSection)
+  const path = useSubSectionPath(propertyName)
+
+  const property = useArchiveProperty<SubSectionData, SubSectionDefinition>(
+    path,
+  )
+  const {loading} = property
+
+  if (loading) {
+    return (
+      <Skeleton>
+        <NavItem
+          label='loading'
+          variant='treeNode'
+          sx={{
+            margin: -1,
+          }}
+        />
+      </Skeleton>
+    )
+  }
+
+  return (
+    <SubSectionNavComponent
+      label={label}
+      property={property}
+      editable={editable}
+    />
+  )
+}
diff --git a/src/components/editor/SubSectionTableEditor.test.tsx b/src/components/editor/SubSectionTableEditor.test.tsx
index de242bbcaee08affe317dd205344285c1959d140..6003c896dc0bdb0cc49332b301e36aca2689c1cc 100644
--- a/src/components/editor/SubSectionTableEditor.test.tsx
+++ b/src/components/editor/SubSectionTableEditor.test.tsx
@@ -8,15 +8,16 @@ import {SubSectionTable} from './SubSectionTableEditor'
 
 describe('SubSectionTableEditor', async () => {
   const layout = {
+    editable: true,
     type: 'table',
     property: 'test_subsection',
     columns: [
       {
         property: 'quantity',
+        editable: false,
       },
       {
         property: 'editable_quantity',
-        editable: true,
       },
     ],
   } as SubSectionTable
diff --git a/src/components/editor/SubSectionTableEditor.tsx b/src/components/editor/SubSectionTableEditor.tsx
index 28daf9b266c8d2dac279d8bd66931225f0da90c0..ceea79ed2df424a211f6eb3f1f3b490259a1c84a 100644
--- a/src/components/editor/SubSectionTableEditor.tsx
+++ b/src/components/editor/SubSectionTableEditor.tsx
@@ -8,6 +8,7 @@ import {
 } from '../../utils/metainfo'
 import {assert, splice} from '../../utils/utils'
 import useArchive, {useArchiveProperty} from '../archive/useArchive'
+import useSubSectionPath from '../archive/useSubSectionPath'
 import {LayoutItem} from '../layout/Layout'
 import RichTableEditor, {
   RichTableEditorColumn,
@@ -23,7 +24,6 @@ import {
 } from '../values/utils/dynamicComponents'
 import {AbstractProperty, getLabel} from './PropertyEditor'
 import {Quantity} from './QuantityEditor'
-import useSubSectionPath from './useSubSectionPath'
 
 export type SubSectionTable = AbstractProperty & {
   type: 'table'
@@ -64,7 +64,7 @@ function createCellEditor(
 
 export default function SubSectionTableEditor({layout}: {layout: LayoutItem}) {
   const table = layout as SubSectionTable
-  const {property, title, columns} = table
+  const {property, title, columns, editable} = table
   const label = getLabel(table)
 
   const path = useSubSectionPath(property)
@@ -185,6 +185,7 @@ export default function SubSectionTableEditor({layout}: {layout: LayoutItem}) {
         onAdd={handleAdd}
         onDelete={handleDelete}
         itemLabel={label}
+        editable={editable}
       />
     </>
   )
diff --git a/src/components/editor/utils.ts b/src/components/editor/utils.ts
index 40844b1e219527b7dde442e552608ce4dfa6a944..0d99d1cdaab4f9aa6280abbd395604723700f857 100644
--- a/src/components/editor/utils.ts
+++ b/src/components/editor/utils.ts
@@ -1,7 +1,7 @@
 import {has, isEqual, isObject, merge} from 'lodash'
 
 import {MSectionRequest} from '../../models/graphRequestModels'
-import {mDefRquest} from '../../pages/entry/entryRoute'
+import {mDefRequest} from '../../pages/entry/entryRoute'
 import {assert} from '../../utils/utils'
 import {LayoutItem} from '../layout/Layout'
 
@@ -11,7 +11,7 @@ export const defaultSubSectionRequest = {
     include_definition: 'both',
     exclude: ['*'],
   },
-  m_def: mDefRquest,
+  m_def: mDefRequest,
 } as MSectionRequest
 
 /**
diff --git a/src/components/icons.tsx b/src/components/icons.tsx
index 97bc8b78dbc91d9d79fc932347e265bb49ac1ec3..c74127c22e565b55c9e2eed1a62e40d7b98f397c 100644
--- a/src/components/icons.tsx
+++ b/src/components/icons.tsx
@@ -28,7 +28,9 @@ import PieChartIcon from '@mui/icons-material/PieChart'
 import PublicIcon from '@mui/icons-material/Public'
 import PushPinIcon from '@mui/icons-material/PushPin'
 import QuestionMarkIcon from '@mui/icons-material/QuestionMark'
+import RedoIcon from '@mui/icons-material/Redo'
 import SearchIcon from '@mui/icons-material/Search'
+import UndoIcon from '@mui/icons-material/Undo'
 import UploadIcon from '@mui/icons-material/Upload'
 import VisibilityIcon from '@mui/icons-material/Visibility'
 import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'
@@ -68,6 +70,8 @@ export const Help = HelpIcon
 export const Dataset = DatasetIcon
 export const Pin = PushPinIcon
 export const Group = GroupIcon
+export const Undo = UndoIcon
+export const Redo = RedoIcon
 
 export function ToggleColorMode() {
   const theme = useTheme()
diff --git a/src/components/layout/CardItem.tsx b/src/components/layout/CardItem.tsx
index 8018eceeedd41e4531f71fcb5256ccdd7d727141..ce037dc290b5f47c5afcfa17a37e190e8c4fced3 100644
--- a/src/components/layout/CardItem.tsx
+++ b/src/components/layout/CardItem.tsx
@@ -10,7 +10,7 @@ import {
 import React, {useCallback, useMemo, useState} from 'react'
 
 import ExpandMore from '../ExpandMore'
-import {layoutPropsContext} from '../layout/useLayoutProps'
+import {editableLayout, layoutPropsContext} from '../layout/useLayoutProps'
 import ContainerItem, {Container} from './ContainerItem'
 import {AbstractContainer, LayoutItem} from './Layout'
 import useLayoutProps from './useLayoutProps'
@@ -70,6 +70,7 @@ export default function CardItem({layout}: CardItemProps) {
     expandedByDefault,
     expandTransitionTimeout,
     variant = 'standard',
+    editable,
     ...cardProps
   } = card
   const [expanded, setExpanded] = useState(
@@ -120,7 +121,9 @@ export default function CardItem({layout}: CardItemProps) {
             }}
           >
             <Box sx={{flexGrow: 1, width: '100%'}}>
-              <ContainerItem layout={collapsedLayout} />
+              <ContainerItem
+                layout={editableLayout(collapsedLayout, editable)}
+              />
             </Box>
             {!title && actions.length > 0 && (
               <Box sx={{marginLeft: 1, marginRight: -1, marginTop: -1}}>
diff --git a/src/components/layout/ContainerItem.tsx b/src/components/layout/ContainerItem.tsx
index d74d2de6e4140fae26bcc53eb0d8b3793775ee63..8683803e4b608222d1ce28e8219bf7499e6b0717 100644
--- a/src/components/layout/ContainerItem.tsx
+++ b/src/components/layout/ContainerItem.tsx
@@ -2,7 +2,7 @@ import {Box, BoxProps} from '@mui/material'
 import Grid from '@mui/material/Grid2'
 
 import {AbstractContainer, Item, Layout, LayoutItem} from './Layout'
-import useLayoutProps from './useLayoutProps'
+import useLayoutProps, {editableLayout} from './useLayoutProps'
 
 export type Container = AbstractContainer & {
   type: 'container'
@@ -11,7 +11,7 @@ export type Container = AbstractContainer & {
 
 export default function ContainerItem({layout}: {layout: LayoutItem}) {
   const container = layout as Container
-  const {type, children, variant = 'grid', ...boxProps} = container
+  const {type, children, variant = 'grid', editable, ...boxProps} = container
   const {action} = useLayoutProps()
 
   let contents
@@ -29,7 +29,7 @@ export default function ContainerItem({layout}: {layout: LayoutItem}) {
       >
         {children.map((child, index) => (
           <Box key={index} sx={{...(child.grow && {flexGrow: 1})}}>
-            <Layout layout={child} />
+            <Layout layout={editableLayout(child, editable)} />
           </Box>
         ))}
       </Box>
@@ -39,7 +39,7 @@ export default function ContainerItem({layout}: {layout: LayoutItem}) {
       <Grid container rowSpacing={2} columnSpacing={2} sx={{flexGrow: 1}}>
         {children.map((child, index) => (
           <Item layout={child} key={index}>
-            <Layout layout={child} />
+            <Layout layout={editableLayout(child, editable)} />
           </Item>
         ))}
       </Grid>
diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx
index 5e65292803f963226bdd0102afe0ffc5574274ca..c74a244b47cb0eee49019b4690c38b99be92da1d 100644
--- a/src/components/layout/Layout.tsx
+++ b/src/components/layout/Layout.tsx
@@ -8,6 +8,7 @@ import PlotEditor, {Plot} from '../editor/PlotEditor'
 import QuantityEditor, {Quantity} from '../editor/QuantityEditor'
 import RichTextEditor, {RichText} from '../editor/RichTextEditor'
 import SubSectionEditor, {SubSection} from '../editor/SubSectionEditor'
+import SubSectionNavEditor, {SubSectionNav} from '../editor/SubSectionNavEditor'
 import SubSectionTableEditor, {
   SubSectionTable,
 } from '../editor/SubSectionTableEditor'
@@ -39,6 +40,7 @@ const components = {
   element: ElementItem,
   richText: RichTextEditor,
   subSection: SubSectionEditor,
+  subSectionNav: SubSectionNavEditor,
   table: SubSectionTableEditor,
   imagePreview: ImagePreviewItem,
   plot: PlotEditor,
@@ -56,6 +58,7 @@ export type LayoutItem =
   | Element
   | RichText
   | SubSection
+  | SubSectionNav
   | SubSectionTable
   | ImagePreview
   | Plot
@@ -63,6 +66,7 @@ export type LayoutItem =
 export type AbstractItem = {
   type: string
   grow?: boolean
+  editable?: boolean
 } & RegularBreakpoints
 
 export type AbstractContainer = AbstractItem & {
diff --git a/src/components/layout/useLayoutProps.tsx b/src/components/layout/useLayoutProps.tsx
index fd8b7ea20dcfd30bf065c37844eabc6e95d043d7..b2f1cb7ae8c02521c36a941dff2023d8fc4e32e9 100644
--- a/src/components/layout/useLayoutProps.tsx
+++ b/src/components/layout/useLayoutProps.tsx
@@ -1,5 +1,21 @@
 import React from 'react'
 
+import {LayoutItem} from './Layout'
+
+export function editableLayout<Layout extends LayoutItem = LayoutItem>(
+  layout: Layout,
+  editable?: boolean,
+): Layout {
+  if (layout.editable === undefined) {
+    return {...layout, editable}
+  } else {
+    return {
+      ...layout,
+      editable: editable && layout.editable,
+    }
+  }
+}
+
 type LayoutPropsContextValue = {
   action?: React.ReactNode
 }
diff --git a/src/components/navigation/NavItem.tsx b/src/components/navigation/NavItem.tsx
index 8b88d31580092426f0709127f52eb34a9e99dbde..9fa70e81141f2fbb5f385d64d44ae38bd88359d7 100644
--- a/src/components/navigation/NavItem.tsx
+++ b/src/components/navigation/NavItem.tsx
@@ -1,5 +1,8 @@
 import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
 import {
+  Badge,
+  BadgeProps,
+  Box,
   ButtonBase,
   Collapse,
   IconButton,
@@ -20,21 +23,22 @@ const classes = generateUtilityClasses('NavItem', [
   'button',
   'icon',
   'label',
+  'badge',
   'toggleButton',
   'content',
+  'actions',
 ])
 
 const NavItemToggleButton = styled(IconButton, {
   name: 'NavItem',
   slot: 'toggleButton',
 })<{ownerState: NavItemOwnerState}>(({theme, ownerState}) => {
-  const {expandable, expanded, variant = 'menuItem'} = ownerState
+  const {expandable, expanded} = ownerState
   return {
-    marginY: -theme.spacing(1),
-    marginLeft: theme.spacing(2),
-    marginRight: theme.spacing(variant === 'treeNode' ? 1 : 0),
-    order: variant === 'menuItem' ? 1 : 0,
-    padding: 0,
+    // marginY: -theme.spacing(1),
+    // marginRight: theme.spacing(1),
+    // marginLeft: theme.spacing(0.5),
+    // padding: 0,
     color: theme.palette.action.active,
     '&.Mui-disabled': {
       color: expandable ? theme.palette.action.active : 'rgba(0, 0, 0, 0)',
@@ -52,7 +56,11 @@ const NavItemToggleButton = styled(IconButton, {
   }
 }) as OverridableComponent<IconButtonTypeMap<{ownerState: NavItemOwnerState}>>
 
-const NavItemRoot = styled('div', {name: 'NavItem', slot: 'root'})(() => ({}))
+const NavItemRoot = styled('div', {name: 'NavItem', slot: 'root'})(() => ({
+  '&:not(:hover) .NavItem-actions': {
+    display: 'none',
+  },
+}))
 
 const NavItemButton = styled(ButtonBase, {
   name: 'NavItem',
@@ -99,20 +107,23 @@ const NavItemButton = styled(ButtonBase, {
 const NavItemIcon = styled('span', {name: 'NavItem', slot: 'icon'})(
   ({theme}) => ({
     marginRight: theme.spacing(1),
+    marginLeft: theme.spacing(2),
     paddingTop: 2,
     color: theme.palette.action.active,
   }),
 )
 
+const NavItemBadge = styled(Badge, {name: 'NavItem', slot: 'badge'})({
+  maxWidth: '100%',
+})
+
 const NavItemLabel = styled(Typography, {name: 'NavItem', slot: 'label'})<{
   ownerState: NavItemOwnerState
 }>(({ownerState: {variant = 'menuItem'}}) => ({
-  flexGrow: 1,
   textAlign: 'left',
-  overflow: 'clip',
-  textOverflow: 'ellipsis',
-  width: '100%',
   whiteSpace: 'nowrap',
+  overflow: 'hidden',
+  textOverflow: 'ellipsis',
   ...(variant === 'menuItem' && {
     textTransform: 'uppercase',
     fontSize: 14,
@@ -120,6 +131,12 @@ const NavItemLabel = styled(Typography, {name: 'NavItem', slot: 'label'})<{
   }),
 }))
 
+const NavItemActions = styled('div', {name: 'NavItem', slot: 'actions'})(
+  () => ({
+    whiteSpace: 'nowrap',
+  }),
+)
+
 const NavItemContent = styled(Collapse, {name: 'NavItem', slot: 'content'})(
   ({theme}) => ({
     '& .MuiCollapse-wrapperInner': {
@@ -185,15 +202,23 @@ export type NavItemProps = {
   /**
    * The variant of the nav item. Default is `menuItem` and is used to produce
    * a top-level nav item menu. The `treeNode` variant is used to create trees.
-   * The `treeNode` variant has the expand icon button on the left, the `menuItem`
-   * on the right.
+   * The `wide` variant is used to create a navigation items outside the
+   * navigation panel.
    */
-  variant?: 'menuItem' | 'treeNode'
+  variant?: 'menuItem' | 'treeNode' | 'wide'
   /**
    * The item is disabled. The appreance is different and all actions are
    * disabled.
    */
   disabled?: boolean
+  /**
+   * Optional props to create a MUI badge on the item label.
+   */
+  badge?: BadgeProps
+  /**
+   * Optional actions to display on the right side of the nav item.
+   */
+  actions?: ReactNode
 }
 
 /**
@@ -214,7 +239,10 @@ export default function NavItem(props: NavItemProps & SxProps) {
     label,
     alignWithExpandIcons = false,
     children,
+    badge,
     sx = [],
+    variant = 'menuItem',
+    actions,
     ...buttonBaseProps
   } = props
   const handleItemClick = useCallback(() => onSelect?.(), [onSelect])
@@ -236,23 +264,50 @@ export default function NavItem(props: NavItemProps & SxProps) {
         disabled={!onSelect && !buttonBaseProps.to}
         {...buttonBaseProps}
       >
-        {((expandable && onToggle) || alignWithExpandIcons) && (
-          <NavItemToggleButton
-            data-testid='toggle'
-            className={classes.toggleButton}
-            ownerState={props}
-            size='small'
-            component='span'
-            disabled={!expandable}
-            onClick={handleExpandClick}
+        {icon && <NavItemIcon className={classes.icon}>{icon}</NavItemIcon>}
+        <Box
+          sx={{
+            flexGrow: variant === 'wide' ? 0 : 1,
+            textAlign: 'left',
+            minWidth: 0,
+          }}
+        >
+          <NavItemBadge className={classes.badge} {...badge}>
+            <NavItemLabel className={classes.label} ownerState={props}>
+              {label}
+            </NavItemLabel>
+          </NavItemBadge>
+        </Box>
+        {((expandable && onToggle) || alignWithExpandIcons || actions) && (
+          <Box
+            sx={(theme) => ({
+              marginY: -theme.spacing(1),
+              marginRight: theme.spacing(1),
+              marginLeft: theme.spacing(0.5),
+              padding: 0,
+              display: 'flex',
+              flexDirection: 'row',
+              whiteSpace: 'nowrap',
+            })}
           >
-            <ExpandMoreIcon />
-          </NavItemToggleButton>
+            {((expandable && onToggle) || alignWithExpandIcons) && (
+              <NavItemToggleButton
+                data-testid='toggle'
+                className={classes.toggleButton}
+                ownerState={props}
+                size='small'
+                component='span'
+                disabled={!expandable}
+                onClick={handleExpandClick}
+              >
+                <ExpandMoreIcon />
+              </NavItemToggleButton>
+            )}
+            <NavItemActions className={classes.actions}>
+              {actions}
+            </NavItemActions>
+          </Box>
         )}
-        {icon && <NavItemIcon className={classes.icon}>{icon}</NavItemIcon>}
-        <NavItemLabel className={classes.label} ownerState={props}>
-          {label}
-        </NavItemLabel>
       </NavItemButton>
       {expandable && children && (
         <NavItemContent
diff --git a/src/components/navigation/Select.tsx b/src/components/navigation/Select.tsx
index f8e09d5d60a3848575f5c8b342fd5014069e114a..61b5aac3004b298e1ca1ff39a87c5635e66ceda5 100644
--- a/src/components/navigation/Select.tsx
+++ b/src/components/navigation/Select.tsx
@@ -11,7 +11,7 @@ import {
 import {PropsWithChildren, useCallback, useState} from 'react'
 
 import {archiveRoute} from '../../pages/entry/entryRoute'
-import {filesRoute} from '../../pages/upload/uploadRoute'
+import {filesRoute, pathRoute} from '../../pages/upload/uploadRoute'
 import uploadsRoute from '../../pages/uploads/uploadsRoute'
 import {Section} from '../../utils/metainfo'
 import {assert} from '../../utils/utils'
@@ -237,7 +237,7 @@ export default function Select<S extends SelectOptions = SelectOptions>({
       setPath(location)
       let matchesEntity = false
       if (entity === 'file') {
-        matchesEntity = leafMatch.route.routeId === filesRoute.routeId
+        matchesEntity = leafMatch.route.routeId === pathRoute.routeId
         matchesEntity &&= leafMatch.response?.m_is === 'File'
         const {filePattern} = selectOptions as unknown as FileSelectOptions
         if (filePattern) {
@@ -260,7 +260,8 @@ export default function Select<S extends SelectOptions = SelectOptions>({
         }
       }
 
-      onChange?.(matchesEntity ? location : undefined)
+      const decodedLocation = decodeURIComponent(location)
+      onChange?.(matchesEntity ? decodedLocation : undefined)
     },
     [setPath, onChange, entity, selectOptions],
   )
diff --git a/src/components/navigation/TreeNav.tsx b/src/components/navigation/TreeNav.tsx
index e8f15134ee22a41f213f7d9b98577c121ba8e343..3423b5cc37457b6c8cf7974fbf8c4ddc94bf8151 100644
--- a/src/components/navigation/TreeNav.tsx
+++ b/src/components/navigation/TreeNav.tsx
@@ -4,16 +4,30 @@ import {useFirstMountState, usePrevious} from 'react-use'
 
 import {JSONObject} from '../../utils/types'
 import {getResponseForPath} from '../routing/loader'
-import useDataForRoute from '../routing/useDataForRoute'
+import useDataForRoute, {
+  UseDataForRouteParams,
+} from '../routing/useDataForRoute'
 import useRoute from '../routing/useRoute'
 import {useAvailableRouteData} from '../routing/useRouteData'
 import NavItem, {NavItemProps} from './NavItem'
 
 export type TreeNavProps = {
   /**
-   * The request object that is used to fetch children.
+   * The request object that is used to fetch children. Either the object
+   * itself or a function that creates the object. The function is called with
+   * the path of the child.
    */
-  request: JSONObject
+  request: JSONObject | ((path: string) => JSONObject)
+  /**
+   * An optional function that transforms the response from fetching children
+   * before it is used.
+   */
+  response?: (response: JSONObject, path: string) => JSONObject
+  /**
+   * Optional parameters passed to the useDataForRoute hook, when fetching
+   * more data with the given `request`.
+   */
+  useDataForRouteParams?: Partial<UseDataForRouteParams>
   /**
    * Determines if available route data is sufficient to render the tree item
    * or if the data has to be fetched. By default route data will always be
@@ -62,6 +76,12 @@ export type TreeNavProps = {
   depth?: number
 
   expandable?: boolean | ((data: JSONObject) => boolean)
+  /**
+   * Selectable tree items will cause a navigation to the path of the item.
+   * None selectable tree items will only expand and collapse.
+   * Default is true.
+   */
+  selectable?: boolean
 } & Partial<Omit<NavItemProps, 'expandable'>>
 
 /**
@@ -76,6 +96,8 @@ export type TreeNavProps = {
 export default function TreeNav({
   path,
   request,
+  response = (response) => response,
+  useDataForRouteParams: dataForRouteParams = {},
   dataIsSufficient = () => true,
   filterChildKeys = () => true,
   getChildProps = () => ({}),
@@ -86,6 +108,7 @@ export default function TreeNav({
   onToggle,
   defaultExpanded,
   expandable: isExpandable = false,
+  selectable = true,
   ...navItemProps
 }: TreeNavProps) {
   const expandedIsControlled = controlledExpanded !== undefined
@@ -101,14 +124,21 @@ export default function TreeNav({
   const splitPath = useMemo(() => path.split('/'), [path])
   const key = useMemo(() => splitPath.at(-1) || 'no path', [splitPath])
 
-  const useDataForRouteParams = useMemo(
-    () => ({request: {[path]: request}, noImplicitFetch: true}),
-    [request, path],
-  )
-  const dataForRouteResult = useDataForRoute(useDataForRouteParams)
-  const {fetch, loading} = dataForRouteResult
-  const fetchedData =
-    dataForRouteResult.data && getResponseForPath(path, dataForRouteResult.data)
+  const useDataForRouteParams = useMemo(() => {
+    return {
+      request:
+        typeof request === 'function' ? request(path) : {[path]: {...request}},
+      noImplicitFetch: true,
+      ...dataForRouteParams,
+    }
+  }, [request, path, dataForRouteParams])
+
+  const {
+    fetch,
+    loading,
+    data: dataForRoute,
+  } = useDataForRoute(useDataForRouteParams)
+  const fetchedData = dataForRoute && getResponseForPath(path, dataForRoute)
   const hasFetchedData = !!fetchedData
 
   const {index, fullMatch, navigate} = useRoute()
@@ -224,7 +254,7 @@ export default function TreeNav({
     isFirstMountState,
   ])
 
-  const renderData = currentData.current
+  const renderData = currentData.current && response(currentData.current, path)
   const renderExpanded = expanded || (justGotInRoute && expandable)
   const renderSelected = selected || (inRoute && (!renderExpanded || loading))
 
@@ -234,7 +264,7 @@ export default function TreeNav({
       selected={renderSelected}
       highlighted={selected}
       onToggle={handleToggle}
-      onSelect={handleSelect}
+      onSelect={selectable ? handleSelect : handleToggle}
       expandable={expandable}
       label={key}
       sx={{
@@ -279,6 +309,8 @@ export default function TreeNav({
                     path={`${path}/${key}`}
                     expandable={expandable}
                     request={request}
+                    response={response}
+                    useDataForRouteParams={dataForRouteParams}
                     dataIsSufficient={dataIsSufficient}
                     getChildProps={getChildProps}
                     orderCompareFn={orderCompareFn}
@@ -301,6 +333,8 @@ export default function TreeNav({
                     path={`${path}/${leastChildKey}`}
                     expandable={expandable}
                     request={request}
+                    response={response}
+                    useDataForRouteParams={dataForRouteParams}
                     dataIsSufficient={dataIsSufficient}
                     getChildProps={getChildProps}
                     orderCompareFn={orderCompareFn}
diff --git a/src/components/page/Page.tsx b/src/components/page/Page.tsx
index 32c6f9855dc84723fce6e5688d72ec28656259d7..9c13f57050e2a88a8b095490c007435a77b941e3 100644
--- a/src/components/page/Page.tsx
+++ b/src/components/page/Page.tsx
@@ -233,7 +233,7 @@ const PageRoot = styled('div', {
   height: '100%',
 }))
 
-interface PageTitleProps {
+export interface PageTitleProps {
   /** The subtitle of the page or part of the page, shown below the title. */
   subtitle?: string | ReactNode
   /** The title of the page or part of the page. */
diff --git a/src/components/richTable/RichTableEditor.tsx b/src/components/richTable/RichTableEditor.tsx
index fbf46b59c013c42dc6dca1b522b05f2b6f00d01f..b72ed9830b8873b64a9dc4020b65e8c284757373 100644
--- a/src/components/richTable/RichTableEditor.tsx
+++ b/src/components/richTable/RichTableEditor.tsx
@@ -54,6 +54,7 @@ export type RichtTableEditorProps = {
   // pressed escape to "abort" the edit. Parent components need to manage
   // the state and restore the old value.
   onAbort?: (columnKey: string, rowIndex: number) => void
+  editable?: boolean
 }
 
 const TableCellWithPrimitive = React.forwardRef(function TabelCellInput(
@@ -152,7 +153,10 @@ const TableCellWithPrimitive = React.forwardRef(function TabelCellInput(
           {error}
         </Typography>
       </Popover>
-      <Box ref={anchorRef}>
+      <Box
+        ref={anchorRef}
+        sx={!props.editable ? {padding: componentProps?.editable ? 0 : 2} : {}}
+      >
         <Component
           valueIndex={valueIndex}
           {...componentProps}
@@ -210,6 +214,7 @@ export default function RichTableEditor({
   onAdd,
   onDelete,
   itemLabel,
+  editable = true,
 }: RichtTableEditorProps) {
   const cellRefs = useRef<HTMLElement[]>([])
   const editorRefs = useRef<HTMLInputElement[]>([])
@@ -372,7 +377,7 @@ export default function RichTableEditor({
                 </TableCell>
               )
             })}
-            {onDelete && <TableCell />}
+            {onDelete && editable && <TableCell />}
           </TableRow>
         </TableHead>
         <TableBody sx={{backgroundColor: 'background.default'}}>
@@ -393,7 +398,13 @@ export default function RichTableEditor({
                       element as HTMLElement
                   }}
                   component={column.component}
-                  componentProps={column.props}
+                  componentProps={{
+                    ...column.props,
+                    editable:
+                      column.props?.editable === undefined
+                        ? editable
+                        : column.props.editable && editable,
+                  }}
                   value={row[column.key]}
                   onChange={(value) => onChange?.(column.key, rowIndex, value)}
                   inputRef={(element: HTMLInputElement | null) => {
@@ -402,7 +413,7 @@ export default function RichTableEditor({
                   }}
                 />
               ))}
-              {onDelete && (
+              {onDelete && editable && (
                 <TableCell sx={{width: '64px', paddingY: 0}}>
                   <IconButton onClick={() => onDelete(rowIndex)} size='small'>
                     <Delete />
@@ -413,7 +424,7 @@ export default function RichTableEditor({
           ))}
         </TableBody>
       </Table>
-      {onAdd && (
+      {onAdd && editable && (
         <>
           <Divider />
           <Box sx={{margin: 1, display: 'flex', flexDirection: 'row-reverse'}}>
diff --git a/src/components/richText/RichTextEditor.tsx b/src/components/richText/RichTextEditor.tsx
index 383bd0b7ceea9a2f8894a7d2c470a78553d05e7b..0d566930fcf3413a2f3ccd50d0402f5b75615e3d 100644
--- a/src/components/richText/RichTextEditor.tsx
+++ b/src/components/richText/RichTextEditor.tsx
@@ -98,8 +98,9 @@ function Editor({
   onChange,
   placeholder,
   initialValue,
-  readonly,
+  editable,
 }: RichTextEditorProps) {
+  const readonly = !!editable
   const [editor] = useLexicalComposerContext()
 
   const [showDev, setShowDev] = useState(false)
@@ -288,15 +289,15 @@ export type RichTextEditorProps = {
   onChange?: (html: string) => void
   placeholder?: string
   initialValue?: string
-  readonly?: boolean
+  editable?: boolean
 }
 
 export default function RichTextEditor(props: RichTextEditorProps) {
-  const {readonly} = props
+  const {editable = true} = props
   return (
     <LexicalComposer
-      initialConfig={{...editorConfig, editable: !readonly}}
-      key={`${!readonly}`}
+      initialConfig={{...editorConfig, editable: !!editable}}
+      key={`${!!editable}`}
     >
       <Editor {...props} />
     </LexicalComposer>
diff --git a/src/components/routing/Routes.tsx b/src/components/routing/Routes.tsx
index 5f85b543ee20addd7d8f28674861645d9d5546a4..84409f91f2766cacbce8903496c243d2d3c79da1 100644
--- a/src/components/routing/Routes.tsx
+++ b/src/components/routing/Routes.tsx
@@ -12,6 +12,7 @@ import {AsyncState} from 'react-use/lib/useAsyncFn'
 
 import useAsyncConditional from '../../hooks/useAsyncConditional'
 import useAuth from '../../hooks/useAuth'
+import {JSONObject} from '../../utils/types'
 import {assert} from '../../utils/utils'
 import DevToolsJsonViewer from '../devTools/DevToolsJsonViewer'
 import useDevTools from '../devTools/useDevTools'
@@ -131,32 +132,33 @@ function useLoadRouteData(
   reloadCount?: number,
 ): AsyncState<LoaderResult | undefined> {
   const {user} = useAuth()
-  const fetch = useMemo(
-    () => loader(fullMatch, user || undefined),
-    [fullMatch, loader, user],
-  )
-  const state = useAsyncConditional(fetch, [fetch, reloadCount])
-  if (state.value) {
-    state.value.routeResponses.forEach((response, index) => {
-      const match = fullMatch[index]
-      if (response && state.value?.response) {
-        match.response = response
-        try {
-          match.route.onFetch?.({
-            fullMatch,
-            match,
-            response,
-            request: state.value.routeRequests[index],
-            fullRequest: state.value?.request,
-            fullResponse: state.value?.response,
-          })
-        } catch (e) {
-          state.error = e as Error
-        }
-      }
-    })
-  }
-  return state
+  const cache = useRef<{request?: JSONObject; response?: JSONObject}>({})
+  const fetch = useMemo(() => {
+    const result = loader(fullMatch, user || undefined, cache.current)
+    if (!result) {
+      return
+    }
+    return () => {
+      return result().then((result) => {
+        result.routeResponses.forEach((response, index) => {
+          const match = fullMatch[index]
+          if (response && result?.response) {
+            match.response = response
+            match.route.onFetch?.({
+              fullMatch,
+              match,
+              response,
+              request: result.routeRequests[index],
+              fullRequest: result?.request,
+              fullResponse: result?.response,
+            })
+          }
+        })
+        return result
+      })
+    }
+  }, [fullMatch, loader, user])
+  return useAsyncConditional(fetch, [fetch, reloadCount])
 }
 
 function useRouteMatch(route: Route, {path, rawSearch}: Location) {
@@ -258,9 +260,16 @@ export default function Routes({
     value: RouteContextValue,
     component: ElementType,
   ) => {
+    let key: string | undefined = undefined
+    if (value.fullMatch[value.index].route.renderWithPathAsKey) {
+      key = value.fullMatch
+        .slice(0, value.index + 1)
+        .map((match) => match.path)
+        .join('/')
+    }
     return React.createElement(
       routeContext.Provider,
-      {value},
+      {value, key},
       React.createElement(component),
     )
   }
diff --git a/src/components/routing/loader.test.ts b/src/components/routing/loader.test.ts
index 82e55c5a76ddb10bc206826bc9e7737834a5cce4..72d56774c1b8b64c9bdb6dcde07661e43b907fb1 100644
--- a/src/components/routing/loader.test.ts
+++ b/src/components/routing/loader.test.ts
@@ -40,7 +40,7 @@ describe('getResponseForPath', () => {
   })
 })
 
-describe('getResonseForRoute', () => {
+describe('getResponseForRoute', () => {
   it('works', () => {
     const result = getResponsesForRoute(
       [{route: {requestKey: 'key', request: '*'}} as unknown as RouteMatch],
diff --git a/src/components/routing/loader.ts b/src/components/routing/loader.ts
index 1a7fd583cbeeed4bb0638c920d49d548adb8378b..bf335ae57cc43213baacdc4449396cfd495e9af4 100644
--- a/src/components/routing/loader.ts
+++ b/src/components/routing/loader.ts
@@ -1,7 +1,8 @@
+import _ from 'lodash'
 import {User} from 'oidc-client-ts'
 
 import {graphApi} from '../../utils/api'
-import {resolveAllMDefs} from '../../utils/metainfo'
+import {removeInternalRefs, resolveAllMDefs} from '../../utils/metainfo'
 import {JSONObject} from '../../utils/types'
 import {assert} from '../../utils/utils'
 import {DefaultSearch, LoaderResult, RouteMatch} from './types'
@@ -15,7 +16,7 @@ export class DoesNotExistError extends Error {
 
 /**
  * Parses the given key and returns the base key and the index if the key is
- * if the key is indexed (e.g. 'key[0]'). Otherwise, returns the key itself ans
+ * if the key is indexed (e.g. 'key[0]'). Otherwise, returns the key itself and
  * `undefined`.
  */
 export function getIndexedKey(key: string): [string, number | undefined] {
@@ -70,7 +71,17 @@ export function getResponsesForRoute(
       return undefined
     }
     const hasRequest = match[index].route.request !== undefined
-    return getResponseForPath(path, response, hasRequest)
+    const responseForPath = getResponseForPath(path, response, hasRequest)
+    if (responseForPath === undefined) {
+      return undefined
+    }
+
+    const transformResponse =
+      match[index].route.response || ((response: unknown) => response)
+    return transformResponse(responseForPath, {
+      ...match[index],
+      search: match[index].search as DefaultSearch,
+    }) as JSONObject
   })
 }
 
@@ -125,6 +136,9 @@ export function createRequestForRoute(
     if (request) {
       assert(path !== undefined, 'Request for empty paths are not supported.')
       requests[path] = request
+      if (routeRequests) {
+        routeRequests[index] = request
+      }
     }
     parentPath = path
   })
@@ -142,13 +156,16 @@ export function createRequestForRoute(
     Object.assign(currentRequest, request)
   })
 
-  routeRequests?.push(rootRequest)
   return rootRequest
 }
 
 export default function loader(
   match: RouteMatch[],
   user?: User,
+  cache: {
+    request?: JSONObject
+    response?: JSONObject
+  } = {},
 ): (() => Promise<LoaderResult>) | undefined {
   let isEmpty = true
   function getRequest(routeMatch: RouteMatch) {
@@ -174,11 +191,21 @@ export default function loader(
   }
 
   return async () => {
-    const response = (await graphApi(request, user)) as JSONObject
+    // Some route changes do not change the request, so we can reuse the last
+    // response. TODO How to implement reload buttons? Pass some reload flag.
+    let response: JSONObject
+    if (_.isEqual(request, cache.request) && cache.response) {
+      response = cache.response
+    } else {
+      response = (await graphApi(request, user)) as JSONObject
+    }
+    cache.request = request
+    cache.response = response
     // TODO We should only resolve m_defs in archive data and not in uploads,
     // entries, files, etc. Currently we apply this to all and the complete
     // responses no matter what they are.
     resolveAllMDefs(response)
+    removeInternalRefs(response)
     return {
       routeResponses: getResponsesForRoute(match, response as JSONObject),
       routeRequests: routeRequests,
diff --git a/src/components/routing/normalizeRoute.ts b/src/components/routing/normalizeRoute.ts
index ac9e7d7c7ba873de0d64e80f89036c56cf83d537..4fe9d55004c4da7689396cd94f5a70cc3e768e2e 100644
--- a/src/components/routing/normalizeRoute.ts
+++ b/src/components/routing/normalizeRoute.ts
@@ -1,6 +1,7 @@
 import {DefaultSearch, Route} from './types'
 
 const normalizedRoutes = new Map<Route, Route>()
+const routeIds = {currentId: 1}
 
 export function routesEqual<Request, Response, Search extends DefaultSearch>(
   a: Route<Request, Response, Search>,
@@ -56,6 +57,10 @@ export function routesEqual<Request, Response, Search extends DefaultSearch>(
 }
 
 export default function normalizeRoute(route: Route): Route {
+  if (route.routeId === undefined) {
+    route.routeId = routeIds.currentId++
+  }
+
   if (normalizedRoutes.has(route)) {
     return normalizedRoutes.get(route) as Route
   }
diff --git a/src/components/routing/types.ts b/src/components/routing/types.ts
index db027b48e70bcd45767c82448f34c8bd9d969591..66566d160c4f36e3f0150704a7418a6e8035c9a8 100644
--- a/src/components/routing/types.ts
+++ b/src/components/routing/types.ts
@@ -21,6 +21,10 @@ export type LoaderResult = {
 export type Loader = (
   fullMatch: RouteMatch[],
   user?: User,
+  cache?: {
+    request?: JSONObject
+    response?: JSONObject
+  },
 ) => (() => Promise<LoaderResult>) | undefined
 
 export type RouteMatch<
@@ -204,6 +208,18 @@ export type Route<
    */
   lazyComponent?: () => Promise<{default: ElementType}>
 
+  /**
+   * React determines component identities and subsequent updattes, mounts, and
+   * unmounts based on a components position in the tree. If the path of
+   * variable routes changes, the component will still be treated as the same
+   * and it will only be updated. This is not always desired, e.g. if entryId
+   * changes, you usually want to start from scratch. If `renderWithPathAsKey`
+   * is set to true, the component will be rendered with a key that is set
+   * to the path. So if the path changes, it is guaranteed that the old component
+   * gets unmounted and a new component is created.
+   */
+  renderWithPathAsKey?: boolean
+
   /**
    * If defined, a given component will only be rendered if the current location
    * matches on of the given routes. Routes can be given as `Route` objects
@@ -289,6 +305,16 @@ export type Route<
         locationData: RouteMatch<Request, Response, Search>,
       ) => DefaultToObject<Request>)
 
+  /**
+   * An optional function that transforms the response data. The transformed
+   * data will be available in the `response` property of the respective
+   * `RouteData` object, e.g. obtained via `useRoute`.
+   */
+  response?: (
+    response: DefaultToObject<unknown>,
+    locationData: RouteMatch<Request, Response, Search>,
+  ) => DefaultToObject<Response>
+
   /**
    * An optional function that is called after the data for the route has
    * been fetched. The function receives the route segment data and the full response.
diff --git a/src/components/routing/useDataForRoute.tsx b/src/components/routing/useDataForRoute.tsx
index bd541669bc62788c500ebc58f009542f337b1f50..28f1e5ca51facd9f1d98bf1587e2107c58314b3b 100644
--- a/src/components/routing/useDataForRoute.tsx
+++ b/src/components/routing/useDataForRoute.tsx
@@ -2,6 +2,7 @@ import {useMemo} from 'react'
 import {useLatest} from 'react-use'
 
 import useData, {UseDataParams, UseDataResult} from '../../hooks/useData'
+import {GraphRequest} from '../../models/graphRequestModels'
 import {GraphResponse} from '../../models/graphResponseModels'
 import {DefaultToObject, JSONObject} from '../../utils/types'
 import {createRequestForRoute, getResponsesForRoute} from './loader'
@@ -29,6 +30,7 @@ export default function useDataForRoute<
 >({
   request,
   route,
+  onBeforeFetch: onBeforeFetchForRoute,
   onFetch: onFetchForRoute,
   onError,
   reloadCount,
@@ -51,6 +53,15 @@ export default function useDataForRoute<
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [request])
 
+  const onBeforeFetch = useMemo(() => {
+    if (!onBeforeFetchForRoute) {
+      return undefined
+    }
+    return (_: JSONObject, fullRequest: GraphRequest) => {
+      return onBeforeFetchForRoute(request as Request, fullRequest)
+    }
+  }, [onBeforeFetchForRoute, request])
+
   const onFetch = useMemo(() => {
     if (!onFetchForRoute) {
       return undefined
@@ -65,6 +76,7 @@ export default function useDataForRoute<
 
   const {data, ...otherUseDataResults} = useData({
     request: fullRequest,
+    onBeforeFetch,
     onFetch,
     onError,
     ...useDataParams,
diff --git a/src/components/routing/useRoute.tsx b/src/components/routing/useRoute.tsx
index 1e8c92adad48bc3e44f0978dc8c1d049a4bc98bc..d9f297829343593d0dc53f20c625b57e4e25fcae 100644
--- a/src/components/routing/useRoute.tsx
+++ b/src/components/routing/useRoute.tsx
@@ -1,6 +1,5 @@
 import {useMemo} from 'react'
 
-import {routesEqual} from './normalizeRoute'
 import {DefaultSearch, Route, RouteData} from './types'
 import useRouteContext from './useRouteContext'
 
@@ -9,7 +8,7 @@ export default function useRoute<
   Response = unknown,
   Search extends DefaultSearch = DefaultSearch,
 >(
-  route?: Route<Request, Response, Search>,
+  ...route: Route<Request, Response, Search>[]
 ): RouteData<Request, Response, Search> {
   const routeContext = useRouteContext()
   return useMemo(() => {
@@ -17,12 +16,8 @@ export default function useRoute<
     if (route) {
       const {fullMatch} = globalRouteData
       for (let i = index; i >= 0; i--) {
-        if (
-          routesEqual(
-            route,
-            fullMatch[i].route as unknown as Route<Request, Response, Search>,
-          )
-        ) {
+        const matchRouteId = fullMatch[i].route.routeId
+        if (route.find((r) => r.routeId === matchRouteId)) {
           return createRouteData(globalRouteData, i) as unknown as RouteData<
             Request,
             Response,
@@ -36,5 +31,6 @@ export default function useRoute<
       Response,
       Search
     >
-  }, [route, routeContext])
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [...route, routeContext])
 }
diff --git a/src/components/routing/useRouteData.test.tsx b/src/components/routing/useRouteData.test.tsx
index 37ff942bd27ed379597e660379f5c2c9a0a7a6a2..c3d0b780724e406e8938a76950e2e3ee5233cb7e 100644
--- a/src/components/routing/useRouteData.test.tsx
+++ b/src/components/routing/useRouteData.test.tsx
@@ -209,6 +209,37 @@ describe('useRouteData', () => {
     expect(mockedApi).toHaveBeenCalledWith({parent: {'*': '*'}}, undefined)
   })
 
+  it('calls response', async () => {
+    const response = vi
+      .fn()
+      .mockImplementation(({dataKey: data}) => ({dataKey: data + 'changed'}))
+    const route: Route = {
+      path: '',
+      component: Outlet,
+      children: [
+        {
+          path: 'data',
+          request: {dataKey: '*'},
+          response,
+          component: function Component() {
+            const {dataKey: data} = useRouteData<unknown, {dataKey: string}>()
+            return <div>{data}</div>
+          },
+        },
+      ],
+    }
+    mockedApi.mockResolvedValue({
+      data: {
+        dataKey: 'value',
+      },
+    } as GraphResponse)
+    window.history.replaceState(null, '', '/data')
+    await act(() => render(<Router route={route} loader={loader} />))
+    expect(mockedApi).toBeCalledTimes(1)
+    expect(response).toBeCalledTimes(1)
+    expect(screen.getByText('valuechanged')).toBeInTheDocument()
+  })
+
   it('calls onFetch', async () => {
     const onFetch = vi.fn()
     const route: Route = {
diff --git a/src/components/routing/useRouteData.tsx b/src/components/routing/useRouteData.tsx
index f2059cf3a4aabf06702ba0af2f3907f529a2b7e2..a4f9300a656910ef3dd44cc7582f07342fcdb5d1 100644
--- a/src/components/routing/useRouteData.tsx
+++ b/src/components/routing/useRouteData.tsx
@@ -6,9 +6,17 @@ export function useAvailableRouteData<
   Response = unknown,
   Search extends DefaultSearch = DefaultSearch,
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
->(route?: Route<Request, Response, Search>) {
-  const {response} = useRoute<Request, Response, Search>()
-  return response as Response | undefined
+>(...route: Route<Request, Response, Search>[]) {
+  const {route: usedRoute, response} = useRoute<Request, Response, Search>(
+    ...route,
+  )
+  if (
+    (route.length > 0 && !route.find((r) => r.routeId === usedRoute.routeId)) ||
+    !response
+  ) {
+    return undefined
+  }
+  return response as Response
 }
 
 export default function useRouteData<
@@ -16,8 +24,8 @@ export default function useRouteData<
   Response = unknown,
   Search extends DefaultSearch = DefaultSearch,
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
->(route?: Route<Request, Response, Search>) {
-  const {response} = useRoute<Request, Response, Search>(route)
+>(...route: Route<Request, Response, Search>[]) {
+  const response = useAvailableRouteData(...route)
   if (!response) {
     throw new Error(
       'Route data should be available. This indicates a bug in <Routes/>.',
diff --git a/src/components/routing/useSearch.tsx b/src/components/routing/useSearch.tsx
index 66f1561e10192cecb3e8372831420680249eb4de..c7d3be3fbe141d5c6d5f73dc042c958f87a642c2 100644
--- a/src/components/routing/useSearch.tsx
+++ b/src/components/routing/useSearch.tsx
@@ -1,9 +1,13 @@
 import {DefaultSearch, Route} from './types'
 import useRoute from './useRoute'
 
-export default function useSearch<Search extends DefaultSearch = DefaultSearch>(
+export default function useSearch<
+  Request = unknown,
+  Response = unknown,
+  Search extends DefaultSearch = DefaultSearch,
+>(
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  route?: Route<unknown, unknown, Search>,
+  route?: Route<Request, Response, Search>,
 ) {
   const {search} = useRoute()
   return search
diff --git a/src/components/values/containers/ContainerControl.tsx b/src/components/values/containers/ContainerControl.tsx
index 2d690df919fb2545675a2f458e3cdb8470728b50..8c3c09bc89e15e3671b1b8fea64d4ab7fd98b104 100644
--- a/src/components/values/containers/ContainerControl.tsx
+++ b/src/components/values/containers/ContainerControl.tsx
@@ -6,7 +6,6 @@ import {
   InputLabel,
   Stack,
   styled,
-  useTheme,
 } from '@mui/material'
 import {FocusEvent, PropsWithChildren, useCallback} from 'react'
 
@@ -66,7 +65,6 @@ export function ValueFormControl({...props}: ValueFormControlProps) {
     ...formControlProps
   } = props
   const {inputId, editable} = useProps<ContainerProps>()
-  const theme = useTheme()
 
   return (
     <FormControl
@@ -83,14 +81,18 @@ export function ValueFormControl({...props}: ValueFormControlProps) {
             shrink
             id={editable ? undefined : inputId && `${inputId}-label`}
             htmlFor={editable ? inputId : undefined}
-            style={{marginLeft: editable ? theme.spacing(1.5) : 0}}
+            sx={{
+              '&.MuiInputLabel-filled': {
+                marginLeft: 1.5,
+              },
+            }}
           >
             {label}
           </StaticInputLabel>
           <LabelActionsContainer>{labelActions}</LabelActionsContainer>
         </LabelContainer>
       )}
-      <Stack direction='row' width='100%'>
+      <Stack direction='row' sx={{width: fullWidth ? '100%' : 'inherit'}}>
         {children}
       </Stack>
       {(edit || error) && helperText && (
diff --git a/src/components/values/containers/Matrix.tsx b/src/components/values/containers/Matrix.tsx
index 267525b16038cf1d2b5ba7fa5623ea96319a4e47..f651d82f04aad08cd7a41a215e2f2d5309f310bf 100644
--- a/src/components/values/containers/Matrix.tsx
+++ b/src/components/values/containers/Matrix.tsx
@@ -173,7 +173,11 @@ export default function Matrix<Value = unknown>({
       <div
         style={{...style, paddingLeft: 4, paddingRight: 4, textAlign: 'center'}}
       >
-        <Value value={matrixValue?.[rowIndex][columnIndex]} hiddenUnit>
+        <Value
+          value={matrixValue?.[rowIndex][columnIndex]}
+          hiddenUnit
+          editable={false}
+        >
           {renderValue?.({})}
         </Value>
       </div>
@@ -250,7 +254,10 @@ export default function Matrix<Value = unknown>({
 
   return (
     <ContainerControl showLabel {...containerProps}>
-      <Stack width='100%' marginTop={label ? 3 : undefined}>
+      <Stack
+        sx={{width: containerProps.fullWidth ? '100%' : 'inherit'}}
+        marginTop={label ? 3 : undefined}
+      >
         {matrixElement}
       </Stack>
     </ContainerControl>
diff --git a/src/components/values/primitives/FileReference.tsx b/src/components/values/primitives/FileReference.tsx
index d17b859ac614b765593921612c8d4a695d4e4683..94305f4de149e837b6a4e0236fbdbdb5ae30001b 100644
--- a/src/components/values/primitives/FileReference.tsx
+++ b/src/components/values/primitives/FileReference.tsx
@@ -1,6 +1,6 @@
-import entryRoute from '../../../pages/entry/entryRoute'
+import useEntryRouteData from '../../../pages/entry/useEntryRouteData'
+import {assert} from '../../../utils/utils'
 import {FileSelectOptions} from '../../navigation/useSelect'
-import useRouteData from '../../routing/useRouteData'
 import Reference, {DynamicReferenceProps, ReferenceProps} from './Reference'
 
 export type FileReferenceProps = ReferenceProps &
@@ -16,17 +16,19 @@ export default function FileReference({
   filePattern,
   ...referenceProps
 }: FileReferenceProps) {
-  const {upload_id, mainfile_path} = useRouteData(entryRoute)
+  const {upload_id, mainfile_path} = useEntryRouteData()
+  assert(mainfile_path, 'mainfile_path is required')
 
   const selectOptions = {
     entity: 'file',
     filePattern,
   } satisfies FileSelectOptions
 
-  const initialPath = `/uploads/${upload_id}/files${mainfile_path?.replace(
-    /\/[^/]+$/,
+  const directoryPath = mainfile_path.replace(/[^/]+$/, '').replace(/^\/?/, '')
+  const initialPath = `/uploads/${upload_id}/files/${directoryPath}`.replace(
+    /\/$/,
     '',
-  )}`
+  )
 
   return (
     <Reference
diff --git a/src/components/values/primitives/Reference.tsx b/src/components/values/primitives/Reference.tsx
index 544a03c1b82a20b54a0fe3eed6d4b20aa7570499..4f9866a391ab64c273d49af304ef7aa4da44cac8 100644
--- a/src/components/values/primitives/Reference.tsx
+++ b/src/components/values/primitives/Reference.tsx
@@ -78,10 +78,11 @@ export default function Reference<S extends SelectOptions = SelectOptions>({
 
   const handleOpen = useCallback(() => {
     assert(value !== undefined, 'Open should only be possible with value.')
-    if (value.startsWith('/')) {
-      navigate({path: value})
+    const normalizedValue = value.replace(/^((\.|#)\/)?/, '')
+    if (normalizedValue.startsWith('/')) {
+      navigate({path: normalizedValue})
     } else {
-      navigate({path: `${initialPath}/${value}`})
+      navigate({path: `${initialPath}/${normalizedValue}`})
     }
   }, [value, navigate, initialPath])
 
diff --git a/src/components/values/primitives/SectionReference.tsx b/src/components/values/primitives/SectionReference.tsx
index 2a49b8f7ec7817ed43cf700730449bffeb3dcf85..b552a7d6cd086216ba607d42b90474654556368f 100644
--- a/src/components/values/primitives/SectionReference.tsx
+++ b/src/components/values/primitives/SectionReference.tsx
@@ -1,6 +1,5 @@
-import entryRoute from '../../../pages/entry/entryRoute'
+import useEntryRouteData from '../../../pages/entry/useEntryRouteData'
 import {SectionSelectOptions} from '../../navigation/useSelect'
-import useRouteData from '../../routing/useRouteData'
 import Reference, {DynamicReferenceProps, ReferenceProps} from './Reference'
 
 export type SectionReferenceProps = ReferenceProps &
@@ -16,7 +15,7 @@ export default function SectionReference({
   sectionDefinition,
   ...referenceProps
 }: SectionReferenceProps) {
-  const {upload_id, entry_id} = useRouteData(entryRoute)
+  const {upload_id, entry_id} = useEntryRouteData()
 
   const selectOptions = {
     entity: 'section',
diff --git a/src/hooks/useData.tsx b/src/hooks/useData.tsx
index 31e9cd823b1eb2d03cd617108561bb4dd9902ad8..21f27ceebbe9ca3055720759d3bb374073b666e0 100644
--- a/src/hooks/useData.tsx
+++ b/src/hooks/useData.tsx
@@ -9,6 +9,7 @@ import {GraphResponse} from '../models/graphResponseModels'
 import {graphApi} from '../utils/api'
 import {resolveAllMDefs} from '../utils/metainfo'
 import {DefaultToObject, JSONObject, JSONValue} from '../utils/types'
+import {assert} from '../utils/utils'
 import useAuth from './useAuth'
 import useRender from './useRender'
 
@@ -63,6 +64,16 @@ export type UseDataParams<Request, Response> = {
    */
   noImplicitFetch?: boolean
 
+  /**
+   * An optional callback that is called before the fetch is started. If this
+   * returns a function, this function will be called when the request effect
+   * is canceled.
+   */
+  onBeforeFetch?: (
+    request: Request,
+    fullRequest: GraphRequest,
+  ) => void | (() => void)
+
   /**
    * An optional callback that is called when the data was successfully
    * received. This allows to trigger state changes now, instead of needing
@@ -100,6 +111,7 @@ export default function useData<
 >({
   request,
   noImplicitFetch = false,
+  onBeforeFetch,
   onFetch,
   onError,
 }: UseDataParams<Request, Response>): UseDataResult<Response> {
@@ -118,9 +130,17 @@ export default function useData<
       return
     }
     requestRef.current = request
+    normalizedRequestRef.current = normalizeGraph(request as JSONObject)
+    const effectDestructor = onBeforeFetch?.(
+      request,
+      normalizedRequestRef.current,
+    )
     const fetch = async () => {
-      normalizedRequestRef.current = normalizeGraph(request as JSONObject)
       try {
+        assert(
+          normalizedRequestRef.current !== undefined,
+          'request is undefined',
+        )
         const result = await graphApi(
           normalizedRequestRef.current,
           user || undefined,
@@ -145,12 +165,14 @@ export default function useData<
     fetch()
     return () => {
       requestRef.current = undefined
+      effectDestructor?.()
     }
   }, [
     requestRef,
     setData,
     normalizedRequestRef,
     request,
+    onBeforeFetch,
     onFetch,
     onError,
     user,
diff --git a/src/hooks/useViewWriteAbilities.tsx b/src/hooks/useViewWriteAbilities.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..4e08cd65d2b487126cabc5fd9a84d4764e442d24
--- /dev/null
+++ b/src/hooks/useViewWriteAbilities.tsx
@@ -0,0 +1,62 @@
+import {useAvailableRouteData} from '../components/routing/useRouteData'
+import {appEntryRoute} from '../pages/apps/appsRoute'
+import entryRoute from '../pages/entry/entryRoute'
+import uploadRoute from '../pages/upload/uploadRoute'
+import {assert} from '../utils/utils'
+import useAuth from './useAuth'
+
+/**
+ * A hook that provides information about the current user's abilities
+ * to read and write data.
+ *
+ * Considers upload authors, reviewers, and respective groups, publish, and
+ * processing status. Works in the context of upload page, entry page (
+ * within upload and search routes).
+ */
+export default function useViewWriteAbilities() {
+  const {user} = useAuth()
+
+  const uploadResponse = useAvailableRouteData(uploadRoute) || {}
+  const entryResponse = useAvailableRouteData(entryRoute) || {}
+  const appEntryResponse = useAvailableRouteData(appEntryRoute) || {
+    metadata: {},
+  }
+  const data = {
+    ...uploadResponse,
+    ...entryResponse,
+    ...appEntryResponse.metadata,
+  }
+  const {
+    viewers,
+    viewer_groups,
+    writers,
+    writer_groups,
+    process_running,
+    published,
+    with_embargo,
+  } = data
+
+  if (!(writers && writer_groups && viewers && viewer_groups)) {
+    return {
+      canRead: false,
+      canWrite: false,
+    }
+  }
+  assert(
+    published !== undefined && with_embargo !== undefined,
+    'published data missing in route data',
+  )
+  const userId = user?.profile?.sub
+
+  return {
+    canRead:
+      (published && !with_embargo) ||
+      viewers.map((u) => u.user_id).includes(userId),
+    // TODO viewer groups
+    canWrite:
+      !process_running &&
+      !published &&
+      writers.map((u) => u.user_id).includes(userId),
+    // TODO writer groups
+  }
+}
diff --git a/src/index.tsx b/src/index.tsx
index 37115408122fd502815d1a21bda83a32f70472f3..58bde89a61bede287dceb875a93292d79d1df756 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -2,7 +2,6 @@ import '@fontsource/titillium-web/400.css'
 import '@fontsource/titillium-web/700.css'
 import {LocalizationProvider} from '@mui/x-date-pickers'
 import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFnsV3'
-import React from 'react'
 import ReactDOM from 'react-dom/client'
 import {RecoilRoot} from 'recoil'
 
@@ -45,23 +44,23 @@ enableMocking().then(() => {
     document.getElementById('root') as HTMLElement,
   )
   root.render(
-    <React.StrictMode>
-      <LocalizationProvider dateAdapter={AdapterDateFns}>
-        <RecoilRoot>
-          <Theme>
-            <AuthProvider>
-              <ApiProvider>
-                <UnitProvider>
-                  <DevTools enabled>
-                    <Routes />
-                  </DevTools>
-                </UnitProvider>
-              </ApiProvider>
-            </AuthProvider>
-          </Theme>
-        </RecoilRoot>
-      </LocalizationProvider>
-    </React.StrictMode>,
+    // <React.StrictMode>
+    <LocalizationProvider dateAdapter={AdapterDateFns}>
+      <RecoilRoot>
+        <Theme>
+          <AuthProvider>
+            <ApiProvider>
+              <UnitProvider>
+                <DevTools enabled>
+                  <Routes />
+                </DevTools>
+              </UnitProvider>
+            </ApiProvider>
+          </AuthProvider>
+        </Theme>
+      </RecoilRoot>
+    </LocalizationProvider>,
+    // </React.StrictMode>,
   )
 })
 
diff --git a/src/pages/apps/AppEntryPage.tsx b/src/pages/apps/AppEntryPage.tsx
index a350cf14922bd8d3f64e42b75e82ba4b26d5e811..361296153b27e15666010c0ea6f0ef82983b5bd3 100644
--- a/src/pages/apps/AppEntryPage.tsx
+++ b/src/pages/apps/AppEntryPage.tsx
@@ -23,9 +23,9 @@ export default function EntryPage() {
       navigation={
         <Nav>
           <NavItem
-            label='projects'
+            label='search apps'
             component={Link}
-            to={url({path: '../../../../uploads'})}
+            to={url({path: '../../../../explore'})}
           />
           <Divider />
           <EntryNavItem />
diff --git a/src/pages/apps/appsRoute.tsx b/src/pages/apps/appsRoute.tsx
index a7e9243e23f37a523e56970c8145ff7486620998..3aee3808ba3382e6f650212305615eae9a84cff5 100644
--- a/src/pages/apps/appsRoute.tsx
+++ b/src/pages/apps/appsRoute.tsx
@@ -4,10 +4,10 @@ import {
   EntryRequest,
 } from '../../models/graphRequestModels'
 import {EntryResponse} from '../../models/graphResponseModels'
-import {archiveRequest, archiveRoute} from '../entry/entryRoute'
+import {EntrySearch, archiveRequest, archiveRoute} from '../entry/entryRoute'
 import AppsPage from './AppsPage'
 
-export const appEntryRoute: Route<EntryRequest, EntryResponse> = {
+export const appEntryRoute: Route<EntryRequest, EntryResponse, EntrySearch> = {
   path: 'explore/:appName/:entryId',
   requestPath: ({path}) => `entries/${path}`,
   request: {
@@ -17,16 +17,27 @@ export const appEntryRoute: Route<EntryRequest, EntryResponse> = {
     process_status: '*',
     entry_create_time: '*',
     complete_time: '*',
+    parser_name: '*',
     metadata: {
       entry_name: '*',
       references: '*',
       authors: '*',
       datasets: '*',
+      writers: '*',
+      writer_groups: '*',
+      viewers: '*',
+      viewer_groups: '*',
+      published: '*',
+      with_embargo: '*',
     } as EntryMetadataRequest,
     archive: {...archiveRequest},
   },
   lazyComponent: async () => import('./AppEntryPage'),
   breadcrumb: ({path}) => path,
+  validateSearch: ({rawSearch}) => ({
+    preview: rawSearch.preview === 'true',
+    layout: rawSearch.layout,
+  }),
   children: [
     {
       path: '',
diff --git a/src/pages/entry/EntryArchiveNav.tsx b/src/pages/entry/EntryArchiveNav.tsx
index 612f5c93fec1ceffd3ec8802c955612ad2c30c23..35e4c635937f0acdd44c4311f66e3077634f70dd 100644
--- a/src/pages/entry/EntryArchiveNav.tsx
+++ b/src/pages/entry/EntryArchiveNav.tsx
@@ -2,18 +2,25 @@ import RepeatedSubSectionIcon from '@mui/icons-material/DataArray'
 import SectionIcon from '@mui/icons-material/DataObjectOutlined'
 import QuantityIcon from '@mui/icons-material/LooksOneOutlined'
 import UnknownIcon from '@mui/icons-material/QuestionMark'
-import {useMemo} from 'react'
+import {useCallback, useEffect} from 'react'
 
+import useArchive from '../../components/archive/useArchive'
 import TreeNav, {TreeNavProps} from '../../components/navigation/TreeNav'
+import {UseDataForRouteParams} from '../../components/routing/useDataForRoute'
 import useRoute from '../../components/routing/useRoute'
+import useRender from '../../hooks/useRender'
 import {Section} from '../../utils/metainfo'
 import {JSONObject} from '../../utils/types'
 import {assert} from '../../utils/utils'
-import {archiveRequest} from './entryRoute'
+import {
+  archiveRequest,
+  mDefRequest,
+  useEntryDataForRouteParams,
+} from './entryRoute'
 
 export type EntryArchiveNavProps = Pick<
   TreeNavProps,
-  'getChildProps' | 'label' | 'expanded' | 'selected'
+  'getChildProps' | 'label' | 'expanded' | 'selected' | 'defaultExpanded'
 >
 
 function filterChildKeys(data: JSONObject, key: string) {
@@ -38,85 +45,113 @@ function expandable(data: JSONObject) {
   )
 }
 
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function getChildProps(data: JSONObject, key: string, path: string) {
-  const sectionDef = data.m_def as Section
-  const property = sectionDef.all_properties[key] || {}
-
-  const isQuantity = property.m_def === 'Quantity'
-  const isSubSection = property.m_def === 'SubSection' && !property.repeats
-  const isUnknown = property.m_def === undefined
-  const isRepeatingSubSection =
-    property.m_def === 'SubSection' && property.repeats
-
-  let icon
-  if (isQuantity) {
-    icon = <QuantityIcon />
-  } else if (isSubSection) {
-    icon = <SectionIcon />
-  } else if (isRepeatingSubSection) {
-    icon = <RepeatedSubSectionIcon />
-  } else if (isUnknown) {
-    icon = <UnknownIcon />
-  } else {
-    throw new Error('Impossible state.')
-  }
+export default function EntryArchiveNav({
+  ...treeNavProps
+}: EntryArchiveNavProps) {
+  const {fullMatch, index} = useRoute()
+  const highlighted =
+    fullMatch.length === index + 2 && fullMatch[index + 1]?.path === 'archive'
 
-  const sharedProps = {
-    variant: 'treeNode',
-    icon,
-    alignWithExpandIcons: true,
-  }
+  const archive = useArchive()
+  const rerender = useRender()
 
-  if (isQuantity || isUnknown) {
-    return {
-      ...sharedProps,
-      expandable: false,
-      disabled: isUnknown,
-    } as TreeNavProps
-  }
+  useEffect(() => {
+    return archive.registerChangeListener(rerender)
+  }, [archive, rerender])
 
-  if (isSubSection) {
-    return {
-      ...sharedProps,
-      getChildProps,
-      filterChildKeys,
-      expandable,
-    } as TreeNavProps
-  }
+  const request = useCallback((path: string) => {
+    const request: JSONObject = {m_def: mDefRequest}
+    let current = request
+    for (const key of path.split('/').slice(1)) {
+      current[key] = {m_def: mDefRequest}
+      current = current[key]
+    }
+    Object.assign(current, archiveRequest)
+    const result = {archive: request}
+    return result
+  }, [])
+
+  const response = useCallback(
+    (response: JSONObject, path: string) => {
+      path = path.replace(/^archive\/?/, '')
+      return archive.getValue(path) as JSONObject
+    },
+    [archive],
+  )
+
+  const useDataForRouteParams = useEntryDataForRouteParams((error) => {
+    // eslint-disable-next-line no-console
+    console.error('Error while fetching nav data :', error)
+  }) as Partial<UseDataForRouteParams>
+
+  const getChildProps = useCallback(
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    (data: JSONObject, key: string, path: string) => {
+      const sectionDef = data.m_def as Section
+      const property = sectionDef.all_properties[key] || {}
 
-  if (isRepeatingSubSection) {
-    return {
-      ...sharedProps,
-      expandable: true,
-      getChildProps: (data: JSONObject, key: string, path: string) =>
-        ({
+      const isQuantity = property.m_def === 'Quantity'
+      const isSubSection = property.m_def === 'SubSection' && !property.repeats
+      const isUnknown = property.m_def === undefined
+      const isRepeatingSubSection =
+        property.m_def === 'SubSection' && property.repeats
+
+      let icon
+      if (isQuantity) {
+        icon = <QuantityIcon />
+      } else if (isSubSection) {
+        icon = <SectionIcon />
+      } else if (isRepeatingSubSection) {
+        icon = <RepeatedSubSectionIcon />
+      } else if (isUnknown) {
+        icon = <UnknownIcon />
+      } else {
+        throw new Error('Impossible state.')
+      }
+
+      const sharedProps = {
+        variant: 'treeNode',
+        icon,
+        alignWithExpandIcons: true,
+      }
+
+      if (isQuantity || isUnknown) {
+        return {
+          ...sharedProps,
+          expandable: false,
+          disabled: isUnknown,
+        } as TreeNavProps
+      }
+
+      if (isSubSection) {
+        return {
           ...sharedProps,
           getChildProps,
           filterChildKeys,
           expandable,
-          icon: <SectionIcon />,
-          label: key,
-          path: `${path}[${key}]`,
-        } as TreeNavProps),
-    } as TreeNavProps
-  }
-
-  throw new Error('Impossible state.')
-}
+        } as TreeNavProps
+      }
 
-export default function EntryArchiveNav({
-  ...treeNavProps
-}: EntryArchiveNavProps) {
-  const {fullMatch, index} = useRoute()
-  const highlighted =
-    fullMatch.length === index + 2 && fullMatch[index + 1]?.path === 'archive'
+      if (isRepeatingSubSection) {
+        return {
+          ...sharedProps,
+          expandable: true,
+          selectable: false,
+          getChildProps: (data: JSONObject, key: string, path: string) =>
+            ({
+              ...sharedProps,
+              getChildProps,
+              filterChildKeys,
+              expandable,
+              icon: <SectionIcon />,
+              label: key,
+              path: `${path}[${key}]`,
+            } as TreeNavProps),
+        } as TreeNavProps
+      }
 
-  const request = useMemo(
-    () =>
-      ({
-        ...archiveRequest,
-      } as JSONObject),
+      throw new Error('Impossible state.')
+    },
     [],
   )
 
@@ -127,6 +162,8 @@ export default function EntryArchiveNav({
       variant='menuItem'
       icon={undefined}
       request={request}
+      response={response}
+      useDataForRouteParams={useDataForRouteParams}
       expandable={expandable}
       getChildProps={getChildProps}
       filterChildKeys={filterChildKeys}
diff --git a/src/pages/entry/EntryDataEditor.test.tsx b/src/pages/entry/EntryDataEditor.test.tsx
index e54c05be6ab32f234bc02439a33aa7300c4f02d3..3d13e51f4f50ad5e3cfeb1bc8a7b96e5b3508805 100644
--- a/src/pages/entry/EntryDataEditor.test.tsx
+++ b/src/pages/entry/EntryDataEditor.test.tsx
@@ -11,11 +11,11 @@ import EntryDataEditor from './EntryDataEditor'
 describe('EntryDataEditor', async () => {
   const layout: LayoutItem = {
     type: 'container',
+    editable: true,
     children: [
       {
         type: 'quantity',
         property: 'test_quantity1',
-        editable: true,
       },
       {
         type: 'subSection',
@@ -26,7 +26,6 @@ describe('EntryDataEditor', async () => {
             {
               type: 'quantity',
               property: 'test_quantity2',
-              editable: true,
             },
           ],
         },
diff --git a/src/pages/entry/EntryMetadataEditor.tsx b/src/pages/entry/EntryMetadataEditor.tsx
index 376d5d53ed362b92a36017df00dae689411b169a..a1d43144c7c27f694af4c8006da057c2d3952ce5 100644
--- a/src/pages/entry/EntryMetadataEditor.tsx
+++ b/src/pages/entry/EntryMetadataEditor.tsx
@@ -2,12 +2,12 @@ import {useMemo} from 'react'
 
 import ProcessStatus from '../../components/ProcessStatus'
 import {Layout, LayoutItem} from '../../components/layout/Layout'
-import useRouteData from '../../components/routing/useRouteData'
+import {editableLayout} from '../../components/layout/useLayoutProps'
 import List from '../../components/values/containers/List'
 import Text from '../../components/values/primitives/Text'
 import {EntryResponse} from '../../models/graphResponseModels'
 import {assert} from '../../utils/utils'
-import entryRoute from './entryRoute'
+import useEntryRouteData from './useEntryRouteData'
 
 function DatasetList({data}: {data: EntryResponse}) {
   // TODO We should remove the "|| []" at some point. This is only there,
@@ -39,7 +39,7 @@ export default function EntryMetadataEditor({
   editable = false,
   expandedByDefault = false,
 }: EntryMetadataEditorProps) {
-  const data = useRouteData(entryRoute) as EntryResponse
+  const data = useEntryRouteData()
   const layout = useMemo(
     () =>
       ({
@@ -58,6 +58,7 @@ export default function EntryMetadataEditor({
               {
                 type: 'value',
                 label: 'mainfile',
+                editable: false,
                 grow: true,
                 value: data.mainfile_path,
                 component: {
@@ -68,6 +69,7 @@ export default function EntryMetadataEditor({
               },
               {
                 type: 'value',
+                editable: false,
                 component: {
                   Id: {
                     abbreviated: true,
@@ -91,7 +93,6 @@ export default function EntryMetadataEditor({
             children: [
               {
                 type: 'quantity',
-                editable,
                 grow: true,
                 label: 'entry name',
                 property: 'metadata/entry_name',
@@ -106,6 +107,7 @@ export default function EntryMetadataEditor({
                 type: 'value',
                 label: 'created at',
                 value: data.entry_create_time,
+                editable: false,
                 component: {
                   Datetime: {
                     variant: 'datetime',
@@ -116,6 +118,7 @@ export default function EntryMetadataEditor({
                 type: 'value',
                 label: 'last change',
                 value: data.complete_time,
+                editable: false,
                 component: {
                   Datetime: {
                     variant: 'datetime',
@@ -126,7 +129,6 @@ export default function EntryMetadataEditor({
           },
           {
             md: 6,
-            editable: true,
             type: 'quantity',
             label: 'references',
             placeholder: 'no references',
@@ -149,8 +151,8 @@ export default function EntryMetadataEditor({
           },
         ],
       } as LayoutItem),
-    [editable, expandedByDefault, data],
+    [expandedByDefault, data],
   )
 
-  return <Layout layout={layout} />
+  return <Layout layout={editableLayout(layout, editable)} />
 }
diff --git a/src/pages/entry/EntryNavAbout.tsx b/src/pages/entry/EntryNavAbout.tsx
index 9eb9bb3131fb5ba8472eb786350c0aa04d2e9aee..f807be2f4e4d25af6cd0593bfc06a20d7abac7d0 100644
--- a/src/pages/entry/EntryNavAbout.tsx
+++ b/src/pages/entry/EntryNavAbout.tsx
@@ -1,14 +1,12 @@
 import ProcessStatus from '../../components/ProcessStatus'
 import NavAbout from '../../components/navigation/NavAbout'
-import useRouteData from '../../components/routing/useRouteData'
 import CopyToClipboard from '../../components/values/actions/CopyToClipboard'
 import Value from '../../components/values/containers/Value'
 import Id from '../../components/values/primitives/Id'
-import {EntryRequest} from '../../models/graphRequestModels'
-import {EntryResponse} from '../../models/graphResponseModels'
+import useEntryRouteData from './useEntryRouteData'
 
 export default function EntryNavAbout() {
-  const entry = useRouteData<EntryRequest, EntryResponse>()
+  const entry = useEntryRouteData()
   const {mainfile_path, entry_id} = entry
   return (
     <NavAbout label='entry' title={mainfile_path as string}>
diff --git a/src/pages/entry/EntryOverview.tsx b/src/pages/entry/EntryOverview.tsx
index 71b424053358916266ed677a10649191df7c6076..10c0474f2028348c575774e30761e192b37b3c66 100644
--- a/src/pages/entry/EntryOverview.tsx
+++ b/src/pages/entry/EntryOverview.tsx
@@ -1,60 +1,41 @@
-import GoToIcon from '@mui/icons-material/ChevronRight'
-import {Box, Button} from '@mui/material'
+import {Box, Tab, Tabs, Typography} from '@mui/material'
 import {useCallback, useMemo, useState} from 'react'
+import {usePrevious} from 'react-use'
 
+import ErrorBoundary from '../../components/ErrorBoundary'
 import ErrorMessage from '../../components/app/ErrorMessage'
-import EditStatus from '../../components/archive/EditStatus'
+import Section from '../../components/archive/Section'
 import useArchive from '../../components/archive/useArchive'
 import {calculateRequestFromLayout} from '../../components/editor/utils'
 import {LayoutItem} from '../../components/layout/Layout'
+import {editableLayout} from '../../components/layout/useLayoutProps'
 import useSelect from '../../components/navigation/useSelect'
-import {PageTitle} from '../../components/page/Page'
-import usePage from '../../components/page/usePage'
-import Link from '../../components/routing/Link'
-import useDataForRoute from '../../components/routing/useDataForRoute'
 import useRoute from '../../components/routing/useRoute'
-import useRouteData from '../../components/routing/useRouteData'
+import useSearch from '../../components/routing/useSearch'
+import useViewWriteAbilities from '../../hooks/useViewWriteAbilities'
 import {EntryRequest, MSectionRequest} from '../../models/graphRequestModels'
-import {
-  EntryResponse,
-  GraphResponse,
-  MSectionResponse,
-} from '../../models/graphResponseModels'
-import {Section} from '../../utils/metainfo'
+import {MSectionResponse} from '../../models/graphResponseModels'
+import {Section as SectionDefinition} from '../../utils/metainfo'
 import {assert} from '../../utils/utils'
 import UploadMetadataEditor from '../upload/UploadMetadataEditor'
 import EntryDataEditor from './EntryDataEditor'
 import EntryMetadataEditor from './EntryMetadataEditor'
-import EntrySubSectionTable from './EntrySubSectionTable'
-import entryRoute, {archiveRequest} from './entryRoute'
+import EntryPageTitle from './EntryPageTitle'
+import EntrySection from './EntrySection'
+import entryRoute, {archiveRequest, useEntryDataForRoute} from './entryRoute'
+import useEntryRouteData from './useEntryRouteData'
 
-function EntryOverviewEditor() {
-  const {archive: archiveData} = useRouteData(entryRoute)
+function EntryOverviewEditor({
+  layout,
+  editable,
+}: {
+  layout: LayoutItem
+  editable?: boolean
+}) {
+  const {reloadCount} = useRoute()
   const [error, setError] = useState<Error | undefined>()
-  const schema = (archiveData?.data as MSectionResponse)?.m_def as Section
   const {isPage} = useSelect()
 
-  const layout = useMemo(() => {
-    let layout: LayoutItem
-    const layouts = schema?.m_annotations?.layout as unknown as
-      | LayoutItem
-      | LayoutItem[]
-      | undefined
-    if (Array.isArray(layouts)) {
-      layout = layouts[0]
-    } else if (layouts !== undefined) {
-      layout = layouts
-    } else {
-      return undefined
-    }
-
-    return {
-      type: 'subSection',
-      property: 'data',
-      layout,
-    } satisfies LayoutItem
-  }, [schema])
-
   const request = useMemo(() => {
     const request = {
       archive: {
@@ -69,26 +50,26 @@ function EntryOverviewEditor() {
       calculateRequestFromLayout(layout, request.archive)
     }
     return request as EntryRequest
-  }, [layout])
+    // Depending on the reloadCount is important to for a new request and
+    // therefore a new fetch.
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [layout, reloadCount])
 
+  // Ideally we would call this in the onBeforeFetch callback, but
+  // this will be too late because the effect is called after the render.
+  // When rendering the EntryOverviewEditor and the
+  // archive was loaded before, the render will think the archive
+  // is already loaded and updated, even though the update has not even started.
+  // While this works for now, it will be a problem if the startUpdate function
+  // will cause state updates in the future as those are not allowed during
+  // render.
+  const requestHasChanged = request !== usePrevious(request)
   const archive = useArchive()
+  if (requestHasChanged && archive.currentUpdateRequests === undefined) {
+    archive.startUpdate(request.archive as MSectionRequest, true)
+  }
 
-  const onFetch = useCallback(
-    (data: EntryResponse, fullResponse: GraphResponse) => {
-      archive.updateArchive(
-        request.archive as MSectionRequest,
-        data?.archive as MSectionResponse,
-        fullResponse,
-      )
-    },
-    [archive, request],
-  )
-
-  useDataForRoute<EntryRequest, EntryResponse>({
-    request,
-    onFetch,
-    onError: setError,
-  })
+  useEntryDataForRoute(request, setError)
 
   let content: React.ReactNode = ''
   if (error) {
@@ -97,60 +78,60 @@ function EntryOverviewEditor() {
     content = <ErrorMessage error={error} />
   } else {
     if (isPage) {
-      if (layout) {
-        content = <EntryDataEditor layout={layout} />
-      } else {
-        content = <ErrorMessage error={new Error('No layout defined')} />
-      }
+      content = <EntryDataEditor layout={editableLayout(layout, editable)} />
     }
   }
 
-  return (
-    <>
-      <Box sx={{marginBottom: 2}}>
-        <UploadMetadataEditor />
-      </Box>
-      <Box sx={{marginBottom: 4}}>
-        <EntryMetadataEditor editable={isPage} expandedByDefault={isPage} />
-      </Box>
-      {content}
-    </>
-  )
+  return <ErrorBoundary>{content}</ErrorBoundary>
 }
 
 export default function EntryOverview() {
-  const {url} = useRoute()
-  const {
-    upload_id,
-    mainfile_path,
-    archive: rootSectionData,
-  } = useRouteData(entryRoute)
+  const {archive: rootSectionData} = useEntryRouteData()
+  const {canWrite} = useViewWriteAbilities()
+  const {preview} = useSearch(entryRoute)
+  const {navigate} = useRoute()
+
   assert(
     rootSectionData !== undefined,
     'An entry should always have a root section',
   )
 
   const {isPage, isSelect} = useSelect()
-  const {isScrolled} = usePage()
+  const layout = useMemo(() => {
+    const schema = (rootSectionData?.data as MSectionResponse)
+      ?.m_def as SectionDefinition
+    let layout: LayoutItem
+    const layouts = schema?.m_annotations?.layout as unknown as
+      | LayoutItem
+      | LayoutItem[]
+      | undefined
+    if (Array.isArray(layouts)) {
+      layout = layouts[0]
+    } else if (layouts !== undefined) {
+      layout = layouts
+    } else {
+      return undefined
+    }
 
-  const actions = (
-    <Box display='flex' alignItems='center' flexDirection='row' gap={1}>
-      <EditStatus />
-      <Button
-        variant='contained'
-        component={Link}
-        to={url({
-          path: `/uploads/${upload_id}/files/${mainfile_path}`,
-        })}
-        endIcon={<GoToIcon />}
-      >
-        Go to File
-      </Button>
-    </Box>
+    return {
+      type: 'subSection',
+      property: 'data',
+      layout,
+    } satisfies LayoutItem
+  }, [rootSectionData])
+
+  const {layout: layoutTab = layout ? 'layout' : 'data'} = useSearch(entryRoute)
+  const handleLayoutTabChange = useCallback(
+    (_: React.SyntheticEvent, newValue: 'layout' | 'data') => {
+      navigate({searchUpdates: {layout: newValue}})
+    },
+    [navigate],
   )
 
+  const editable = canWrite && isPage && !preview
+
   // This memo is an optimization to avoid re-rendering the entire
-  // EntryOverviewEditor after usePage causes a srcoll event triggered
+  // EntryOverviewEditor after usePage causes a scroll event triggered
   // rerender that only effects the page title.
   const pageContent = useMemo(
     () => (
@@ -160,37 +141,40 @@ export default function EntryOverview() {
             marginTop: -1,
           }}
         >
-          <EntryOverviewEditor />
+          <Box sx={{marginBottom: 2}}>
+            <UploadMetadataEditor />
+          </Box>
+          <Box sx={{marginBottom: 4}}>
+            <EntryMetadataEditor
+              editable={editable}
+              expandedByDefault={isPage}
+            />
+          </Box>
+          <Tabs value={layoutTab} onChange={handleLayoutTabChange} sx={{mb: 2}}>
+            <Tab label='Layout' value='layout' />
+            <Tab label='Data' value='data' />
+          </Tabs>
+          {layoutTab === 'layout' &&
+            (layout ? (
+              <EntryOverviewEditor layout={layout} editable={editable} />
+            ) : (
+              <Typography>
+                This entry has no custom layout defined in it&apos;s schema.
+              </Typography>
+            ))}
+          {layoutTab === 'data' && (
+            <Section path={'data'} editable={editable} />
+          )}
         </Box>
-        {isSelect && <EntrySubSectionTable data={rootSectionData} />}
+        {isSelect && <EntrySection />}
       </>
     ),
-    [isSelect, rootSectionData],
+    [editable, handleLayoutTabChange, isPage, isSelect, layout, layoutTab],
   )
 
   return (
     <>
-      {isPage && (
-        <PageTitle
-          sx={{
-            position: 'sticky',
-            top: 0,
-            marginTop: -1,
-            marginX: -2,
-            paddingX: 2,
-            paddingY: 1,
-            background: (theme) => theme.palette.background.default,
-            zIndex: (theme) => theme.zIndex.appBar,
-            ...(isScrolled
-              ? {
-                  borderBottom: '1px solid',
-                  borderColor: (theme) => theme.palette.divider,
-                }
-              : {}),
-          }}
-          actions={actions}
-        />
-      )}
+      {isPage && <EntryPageTitle />}
       {pageContent}
     </>
   )
diff --git a/src/pages/entry/EntryPage.test.tsx b/src/pages/entry/EntryPage.test.tsx
index 9201f47b0782042d8344d780bbc553c4dd388842..094e494f4f4b6ed6e0781e71d40132ac7890f468 100644
--- a/src/pages/entry/EntryPage.test.tsx
+++ b/src/pages/entry/EntryPage.test.tsx
@@ -3,20 +3,22 @@ import {expect, it, vi} from 'vitest'
 
 import {addDefinitions} from '../../components/archive/archive.helper'
 import {getArchive} from '../../components/archive/useArchive'
-import {GraphResponse} from '../../models/graphResponseModels'
+import {Route} from '../../components/routing/types'
 import * as api from '../../utils/api'
 import {
+  createMatchMedia,
   importLazyComponents,
   renderWithRouteData,
 } from '../../utils/test.helper'
-import entryRoute from './entryRoute'
+import uploadsRoute from '../uploads/uploadsRoute'
 
-await importLazyComponents(entryRoute)
+await importLazyComponents(uploadsRoute)
 
 describe('EntryPage', () => {
   it('loads and initially renders', async () => {
     const mockedApi = vi.spyOn(api, 'graphApi')
-    window.history.replaceState(null, '', '/entryId')
+    vi.spyOn(window, 'matchMedia').mockImplementation(createMatchMedia(500))
+    window.history.replaceState(null, '', 'uploads/uploadId/entries/entryId')
 
     const metadata = {
       entry_name: 'entry-name',
@@ -24,22 +26,29 @@ describe('EntryPage', () => {
     }
 
     mockedApi.mockResolvedValue({
-      entryId: {
-        entry_id: 'entryId',
-        mainfile_path: 'entry.archive.json',
-        metadata: {
-          ...metadata,
-          datasets: [],
-        },
-        archive: addDefinitions({
-          metadata,
-          material: {
-            name: 'gold',
+      uploads: {
+        uploadId: {
+          upload_id: 'uploadId',
+          entries: {
+            entryId: {
+              entry_id: 'entryId',
+              mainfile_path: 'entry.archive.json',
+              metadata: {
+                ...metadata,
+                datasets: [],
+              },
+              archive: addDefinitions({
+                metadata,
+                data: {
+                  name: 'gold',
+                },
+              }),
+            },
           },
-        }),
+        },
       },
-    } as GraphResponse)
-    await renderWithRouteData(entryRoute)
+    })
+    await renderWithRouteData(uploadsRoute as unknown as Route)
     await waitFor(() =>
       expect(screen.getAllByText(/entry.archive.json/)).toHaveLength(3),
     )
diff --git a/src/pages/entry/EntryPage.tsx b/src/pages/entry/EntryPage.tsx
index 56ea8ee9106288493e54644e98dc0af506ea802e..cb25ed957269ba80a531a99881873d1ec78955ac 100644
--- a/src/pages/entry/EntryPage.tsx
+++ b/src/pages/entry/EntryPage.tsx
@@ -18,13 +18,13 @@ import UploadNavAbout from '../upload/UploadNavAbout'
 import uploadRoute from '../upload/uploadRoute'
 import EntryArchiveNav from './EntryArchiveNav'
 import EntryNavItem from './EntryNavAbout'
-import entryRoute from './entryRoute'
+import useEntryRouteData from './useEntryRouteData'
 
 export default function EntryPage() {
   const {url, fullMatch, index} = useRoute()
   const nextPath = fullMatch[index + 1]?.path
   const tab = nextPath === '' ? 'overview' : nextPath
-  const {entry_id, mainfile_path} = useRouteData(entryRoute)
+  const {entry_id, mainfile_path} = useEntryRouteData()
   const {upload_id} = useRouteData(uploadRoute)
   const {isPage, pageVariant} = useSelect()
 
@@ -80,7 +80,7 @@ export default function EntryPage() {
           )}
           <EntryArchiveNav
             label='data'
-            expanded={tab !== 'archive' ? false : undefined}
+            defaultExpanded={tab !== 'archive' ? false : undefined}
             selected={tab === 'archive'}
           />
         </Nav>
diff --git a/src/pages/entry/EntryPageTitle.tsx b/src/pages/entry/EntryPageTitle.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..5dd2512f81df41e9915a79dfee36f0a3333774d0
--- /dev/null
+++ b/src/pages/entry/EntryPageTitle.tsx
@@ -0,0 +1,88 @@
+import GoToIcon from '@mui/icons-material/ChevronRight'
+import {Box, Button, Checkbox, FormControlLabel, FormGroup} from '@mui/material'
+import {useCallback} from 'react'
+
+import EditStatus from '../../components/archive/EditStatus'
+import useSelect from '../../components/navigation/useSelect'
+import {PageTitle, PageTitleProps} from '../../components/page/Page'
+import usePage from '../../components/page/usePage'
+import Link from '../../components/routing/Link'
+import useRoute from '../../components/routing/useRoute'
+import useSearch from '../../components/routing/useSearch'
+import useViewWriteAbilities from '../../hooks/useViewWriteAbilities'
+import {assert} from '../../utils/utils'
+import entryRoute from './entryRoute'
+import useEntryRouteData from './useEntryRouteData'
+
+export default function EntryPageTitle(props: PageTitleProps) {
+  const {isScrolled} = usePage()
+  const {url, navigate} = useRoute()
+  const {isPage} = useSelect()
+  const {canWrite} = useViewWriteAbilities()
+
+  const {
+    upload_id,
+    mainfile_path,
+    archive: rootSectionData,
+  } = useEntryRouteData()
+  const {preview} = useSearch(entryRoute)
+  assert(
+    rootSectionData !== undefined,
+    'An entry should always have a root section',
+  )
+
+  const handlePreviewChange = useCallback(() => {
+    navigate({searchUpdates: {preview: preview ? undefined : true}})
+  }, [navigate, preview])
+
+  const editable = canWrite && isPage
+
+  const actions = (
+    <Box display='flex' alignItems='center' flexDirection='row' gap={1}>
+      {editable && (
+        <FormGroup>
+          <FormControlLabel
+            control={
+              <Checkbox checked={!!preview} onChange={handlePreviewChange} />
+            }
+            label='Preview'
+          />
+        </FormGroup>
+      )}
+      {editable && <EditStatus />}
+      <Button
+        variant='contained'
+        component={Link}
+        to={url({
+          path: `/uploads/${upload_id}/files/${mainfile_path}`,
+        })}
+        endIcon={<GoToIcon />}
+      >
+        Go to File
+      </Button>
+    </Box>
+  )
+
+  return (
+    <PageTitle
+      sx={{
+        position: 'sticky',
+        top: 0,
+        marginTop: -1,
+        marginX: -2,
+        paddingX: 2,
+        paddingY: 1,
+        background: (theme) => theme.palette.background.default,
+        zIndex: (theme) => theme.zIndex.appBar,
+        ...(isScrolled
+          ? {
+              borderBottom: '1px solid',
+              borderColor: (theme) => theme.palette.divider,
+            }
+          : {}),
+      }}
+      actions={actions}
+      {...props}
+    />
+  )
+}
diff --git a/src/pages/entry/EntrySection.tsx b/src/pages/entry/EntrySection.tsx
index 0332a176ea61fd6b6c47e6a1167d9ae0f46dd37a..af54b782075be580a0ec33fe5b6b0aaca4c48908 100644
--- a/src/pages/entry/EntrySection.tsx
+++ b/src/pages/entry/EntrySection.tsx
@@ -1,82 +1,61 @@
-import {Box, Card, CardContent, CardHeader} from '@mui/material'
 import {useMemo} from 'react'
 
-import ErrorBoundary from '../../components/ErrorBoundary'
-import QuantityValue from '../../components/archive/QuantityValue'
-import JsonViewer from '../../components/fileviewer/JsonViewer'
-import {PageTitle} from '../../components/page/Page'
+import Section from '../../components/archive/Section'
+import useSelect from '../../components/navigation/useSelect'
 import Outlet from '../../components/routing/Outlet'
 import useRoute from '../../components/routing/useRoute'
-import useRouteData from '../../components/routing/useRouteData'
-import {MSectionRequest} from '../../models/graphRequestModels'
-import {MSectionResponse} from '../../models/graphResponseModels'
-import {Section as SectionDefinition} from '../../utils/metainfo'
-import {JSONObject, JSONValue} from '../../utils/types'
-import EntrySubSectionTable from './EntrySubSectionTable'
+import useSearch from '../../components/routing/useSearch'
+import useViewWriteAbilities from '../../hooks/useViewWriteAbilities'
+import {assert} from '../../utils/utils'
+import EntryPageTitle from './EntryPageTitle'
+import entryRoute from './entryRoute'
+import useEntryRouteData from './useEntryRouteData'
 
-const sortRawDataKeys = (a: string, b: string) => {
-  if (a.startsWith('m_') === b.startsWith('m_')) {
-    return a.localeCompare(b)
-  }
-  if (a.startsWith('m_')) {
-    return -1
-  }
-  return 1
-}
-
-function Section() {
-  const data = useRouteData<MSectionRequest, MSectionResponse>()
-
-  const definition = data.m_def as SectionDefinition
-  const quantities = useMemo(() => {
-    return Object.keys(definition.all_quantities)
-      .filter((key) => data[key] !== undefined)
-      .map((key) => definition.all_quantities[key])
-    //.toSorted((a, b) => a.name.localeCompare(b.name))
-  }, [data, definition])
-
-  return (
-    <>
-      <EntrySubSectionTable data={data} />
-      <Card>
-        <CardHeader title='Quantities' />
-        <CardContent sx={{display: 'flex', flexDirection: 'column', gap: 2}}>
-          {quantities.map((quantity) => (
-            <ErrorBoundary key={quantity.name}>
-              <QuantityValue
-                quantityDef={quantity}
-                value={data[quantity.name] as JSONValue | undefined}
-              />
-            </ErrorBoundary>
-          ))}
-        </CardContent>
-      </Card>
-    </>
-  )
-}
+const nonEditableSections = ['results', 'metadata']
 
 export default function EntrySection() {
   const {isLeaf, fullMatch} = useRoute()
-  const data = useRouteData<MSectionRequest, MSectionResponse>()
+  const {parser_name} = useEntryRouteData()
+  const {canWrite} = useViewWriteAbilities()
+  const {isPage} = useSelect()
+  const {preview} = useSearch(entryRoute)
+
+  const startIndex = useMemo(() => {
+    const index = fullMatch.findIndex((match) => match.route.path === 'archive')
+    assert(index !== -1, 'not an archive route')
+    return index
+  }, [fullMatch])
+  const sectionPath = useMemo(() => {
+    if (!isLeaf) {
+      return ''
+    }
+    return fullMatch
+      .slice(startIndex + 1)
+      .map((match) => match.path)
+      .join('/')
+  }, [fullMatch, isLeaf, startIndex])
+
   if (!isLeaf) {
     return <Outlet />
   }
+
+  const editable =
+    canWrite &&
+    isPage &&
+    sectionPath !== '' &&
+    !nonEditableSections.find((s) => sectionPath.startsWith(s)) &&
+    parser_name === 'parsers/archive' &&
+    !preview
+
+  const title =
+    fullMatch.length === startIndex + 1
+      ? 'Entry Data'
+      : `Section ${fullMatch[fullMatch.length - 1].path}`
+
   return (
     <>
-      <PageTitle title={fullMatch[fullMatch.length - 1].path} />
-      <Box sx={{display: 'flex', flexDirection: 'column', gap: 2}}>
-        {data.m_def && <Section />}
-        <Card>
-          <CardHeader title='Raw data' />
-          <CardContent>
-            <JsonViewer
-              value={data as JSONObject}
-              defaultInspectDepth={1}
-              objectSortKeys={sortRawDataKeys}
-            />
-          </CardContent>
-        </Card>
-      </Box>
+      <EntryPageTitle title={title} />
+      <Section path={sectionPath} editable={editable} />
     </>
   )
 }
diff --git a/src/pages/entry/EntrySubSectionTable.tsx b/src/pages/entry/EntrySubSectionTable.tsx
deleted file mode 100644
index 3f183afd5bebc85c3f32914bec4d06210b533c5c..0000000000000000000000000000000000000000
--- a/src/pages/entry/EntrySubSectionTable.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import {useMemo} from 'react'
-
-import useRoute from '../../components/routing/useRoute'
-import PlainDataTable from '../../components/table/PlainDataTable'
-import {MSectionResponse} from '../../models/graphResponseModels'
-import {
-  Section as SectionDefinition,
-  SubSection as SubSectionDefinition,
-} from '../../utils/metainfo'
-
-const subSectionColumns = [
-  {
-    enableSorting: true,
-    accessorKey: 'name',
-    header: 'Name',
-    grow: 1,
-  },
-]
-
-export type EntrySubSectionTableProps = {
-  data: MSectionResponse
-}
-
-export default function EntrySubSectionTable({
-  data,
-}: EntrySubSectionTableProps) {
-  const {navigate} = useRoute()
-
-  const definition = data.m_def as SectionDefinition
-  const subSections = useMemo(() => {
-    return Object.keys(definition.all_sub_sections)
-      .filter((key) => data[key] !== undefined)
-      .map((key) => definition.all_sub_sections[key])
-      .toSorted((a, b) => a.name.localeCompare(b.name))
-  }, [data, definition])
-
-  if (subSections.length === 0) {
-    return null
-  }
-
-  return (
-    <PlainDataTable
-      onRowClick={(data: SubSectionDefinition) => {
-        navigate({
-          path: data.name,
-        })
-      }}
-      columns={subSectionColumns}
-      data={subSections}
-    />
-  )
-}
diff --git a/src/pages/entry/UnsavedChangesNav.tsx b/src/pages/entry/UnsavedChangesNav.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..4af527cf738e128fbe9e270a3aeddeb8152c66d1
--- /dev/null
+++ b/src/pages/entry/UnsavedChangesNav.tsx
@@ -0,0 +1,62 @@
+import {useMemo} from 'react'
+
+import {useChangedArchives} from '../../components/archive/useArchive'
+import NavItem from '../../components/navigation/NavItem'
+import useSelect from '../../components/navigation/useSelect'
+import Link from '../../components/routing/Link'
+import useRoute from '../../components/routing/useRoute'
+
+type UnsavedChangesNavProps = {
+  uploadId?: string
+}
+
+export default function UnsavedChangesNav({uploadId}: UnsavedChangesNavProps) {
+  const {isPage} = useSelect()
+  const changedArchives = useChangedArchives()
+  const {url} = useRoute()
+  const relevantChangedArchives = useMemo(() => {
+    if (!uploadId) {
+      return changedArchives
+    }
+    return changedArchives.filter((archive) => {
+      return archive.entry.upload_id === uploadId
+    })
+  }, [uploadId, changedArchives])
+
+  if (!isPage) {
+    return ''
+  }
+
+  if (relevantChangedArchives.length === 0) {
+    return ''
+  }
+
+  return (
+    <NavItem
+      expandable
+      expanded
+      label={'Entries with unsaved changes'}
+      badge={{badgeContent: relevantChangedArchives.length, color: 'error'}}
+    >
+      {relevantChangedArchives
+        .filter((archive) => {
+          return archive.entry.entry_id && archive.entry.upload_id
+        })
+        .map((archive, index) => (
+          <NavItem
+            key={archive.entry.entry_id || index}
+            variant='treeNode'
+            label={
+              archive.entry.mainfile_path ||
+              archive.entry.entry_id ||
+              'Unknown name'
+            }
+            component={Link}
+            to={url({
+              path: `/uploads/${archive.entry.upload_id}/entries/${archive.entry.entry_id}`,
+            })}
+          />
+        ))}
+    </NavItem>
+  )
+}
diff --git a/src/pages/entry/entryRoute.tsx b/src/pages/entry/entryRoute.tsx
index 424efebd4f1a5b6b5485bb6a915da33228f8a908..35db6f601077fe6e18f551b50bbee79862a18c09 100644
--- a/src/pages/entry/entryRoute.tsx
+++ b/src/pages/entry/entryRoute.tsx
@@ -1,7 +1,12 @@
 import path from 'path-browserify'
+import {useCallback, useMemo} from 'react'
 
-import {getArchive} from '../../components/archive/useArchive'
+import useArchive, {getArchive} from '../../components/archive/useArchive'
+import {getIndexedKey} from '../../components/routing/loader'
 import {Route} from '../../components/routing/types'
+import useDataForRoute, {
+  UseDataForRouteParams,
+} from '../../components/routing/useDataForRoute'
 import {
   EntryMetadataRequest,
   EntryRequest,
@@ -13,7 +18,7 @@ import {
   MSectionResponse,
 } from '../../models/graphResponseModels'
 
-export const mDefRquest = {
+export const mDefRequest = {
   m_request: {
     directive: 'plain',
   },
@@ -23,26 +28,113 @@ export const archiveRequest = {
   m_request: {
     directive: 'plain',
     include_definition: 'both',
+    depth: 2,
   },
-  m_def: mDefRquest,
+  m_def: mDefRequest,
 } as MSectionRequest
 
 export const archiveRoute: Route<MSectionRequest, MSectionResponse> = {
   path: ':name',
-  request: {...archiveRequest},
+  requestKey: ({path}) => getIndexedKey(path)[0],
+  request: ({path}) => {
+    const index = getIndexedKey(path)[1]
+    if (index !== undefined) {
+      return {
+        ...archiveRequest,
+        [index]: {...archiveRequest},
+      }
+    } else {
+      return {...archiveRequest}
+    }
+  },
+  response: (response, {path}) => {
+    const index = getIndexedKey(path)[1]
+    if (index !== undefined) {
+      return response[index] as MSectionResponse
+    } else {
+      return response
+    }
+  },
   lazyComponent: async () => import('./EntrySection'),
+  renderWithPathAsKey: true,
 }
 archiveRoute.children = [archiveRoute]
 
-const entryRoute: Route<EntryRequest, EntryResponse> = {
+/**
+ * Provides parameters for the `useDataForRoute` hook that will make the
+ * hook also update the archive data.
+ */
+export function useEntryDataForRouteParams(
+  setError?: (error: Error) => void,
+): Pick<
+  UseDataForRouteParams<EntryRequest, EntryResponse>,
+  'onBeforeFetch' | 'onFetch' | 'onError'
+> {
+  const archive = useArchive()
+
+  const onBeforeFetch = useCallback(
+    (request: EntryRequest) => {
+      if (!archive.loading) {
+        archive.startUpdate(request.archive as MSectionRequest, true)
+      }
+      return () => {
+        archive.abortUpdate()
+      }
+    },
+    [archive],
+  )
+
+  const onFetch = useCallback(
+    (data: EntryResponse, fullResponse: GraphResponse) => {
+      archive.commitUpdate(data?.archive as MSectionResponse, fullResponse)
+    },
+    [archive],
+  )
+
+  const onError = useCallback(
+    (error: Error) => {
+      archive.abortUpdate()
+      setError?.(error)
+    },
+    [archive, setError],
+  )
+
+  return useMemo(
+    () => ({onBeforeFetch, onFetch, onError}),
+    [onBeforeFetch, onFetch, onError],
+  )
+}
+
+/**
+ * A specific variant of `useEntryDataForRoute` that updates the
+ * archive data for the entry.
+ */
+export function useEntryDataForRoute(
+  request: EntryRequest,
+  setError?: (error: Error) => void,
+) {
+  return useDataForRoute<EntryRequest, EntryResponse>({
+    request,
+    ...useEntryDataForRouteParams(setError),
+  })
+}
+
+export type EntrySearch = {
+  preview?: boolean
+}
+
+const entryRoute: Route<EntryRequest, EntryResponse, EntrySearch> = {
   path: ':entryId',
-  request: {
+  // TODO The function should not be necessary, but some buggy thing is modifying the
+  // request. With the function we force to recreate the request object every time.
+  request: () => ({
     mainfile_path: '*',
     entry_id: '*',
     upload_id: '*',
     process_status: '*',
     entry_create_time: '*',
     complete_time: '*',
+    parser_name: '*',
     metadata: {
       entry_name: '*',
       references: '*',
@@ -50,9 +142,14 @@ const entryRoute: Route<EntryRequest, EntryResponse> = {
       datasets: '*',
     } as EntryMetadataRequest,
     archive: {...archiveRequest},
-  },
+  }),
   lazyComponent: async () => import('./EntryPage'),
+  renderWithPathAsKey: true,
   breadcrumb: ({response}) => path.basename(response?.mainfile_path as string),
+  validateSearch: ({rawSearch}) => ({
+    preview: rawSearch.preview === 'true',
+    layout: rawSearch.layout,
+  }),
   children: [
     {
       path: '',
@@ -71,12 +168,8 @@ const entryRoute: Route<EntryRequest, EntryResponse> = {
     }
     const entryId = match.path
     const archive = getArchive(entryId)
-
-    archive.updateArchive(
-      request.archive,
-      response.archive,
-      fullResponse as GraphResponse,
-    )
+    archive.startUpdate(request.archive, true)
+    archive.commitUpdate(response.archive, fullResponse as GraphResponse)
   },
 }
 
diff --git a/src/pages/entry/useEntryRouteData.tsx b/src/pages/entry/useEntryRouteData.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..73e764233191668189140dc6b0317aa5d5a72887
--- /dev/null
+++ b/src/pages/entry/useEntryRouteData.tsx
@@ -0,0 +1,7 @@
+import useRouteData from '../../components/routing/useRouteData'
+import {appEntryRoute} from '../apps/appsRoute'
+import entryRoute from './entryRoute'
+
+export default function useEntryRouteData() {
+  return useRouteData(entryRoute, appEntryRoute)
+}
diff --git a/src/pages/groups/GroupsTable.test.tsx b/src/pages/groups/GroupsTable.test.tsx
index e1432ef6a565ccc859d91659129129658b525c8a..799dbbd6cd6a0c8f1bde06da251ed151ef0695bf 100644
--- a/src/pages/groups/GroupsTable.test.tsx
+++ b/src/pages/groups/GroupsTable.test.tsx
@@ -2,6 +2,7 @@ import {render, screen, within} from '@testing-library/react'
 import {describe, expect, it, vi} from 'vitest'
 
 import GroupsTable from './GroupsTable'
+import groupsRoute from './groupsRoute'
 
 const setPaginate = vi.fn()
 const navigate = vi.fn()
@@ -22,6 +23,7 @@ vi.mock('../../components/routing/usePagination', () => ({
 vi.mock('../../components/routing/useRoute', () => ({
   default: () => ({
     navigate,
+    route: groupsRoute,
     search: {},
     url: () => '/',
     response: Array.from({length: 12}, (_, index) => ({
diff --git a/src/pages/upload/UploadMetadataEditor.test.tsx b/src/pages/upload/UploadMetadataEditor.test.tsx
index 50d99e1568b115507b86a6540c9c23a8ce05e959..8ba93cd291e7323c26a3ad511dadbbb71ac7f7e6 100644
--- a/src/pages/upload/UploadMetadataEditor.test.tsx
+++ b/src/pages/upload/UploadMetadataEditor.test.tsx
@@ -2,19 +2,20 @@ import {render, screen} from '@testing-library/react'
 import userEvent from '@testing-library/user-event'
 import {vi} from 'vitest'
 
+import * as useRouteData from '../../components/routing/useRouteData'
 import {UploadResponse} from '../../models/graphResponseModels'
 import UploadMetadataEditor from './UploadMetadataEditor'
 
 describe('UploadMetadataEditor', () => {
+  const useAvailableRouteData = vi.spyOn(useRouteData, 'useAvailableRouteData')
+
   it('renders with name and id', async () => {
-    vi.mock('../../components/routing/useRouteData', () => ({
-      default: vi.fn().mockReturnValue({
-        upload_id: 'test-id',
-        upload_name: 'test-name',
-        main_author: {name: 'test-main-author'},
-        coauthors: [{name: 'test-coauthor'}],
-      } as UploadResponse),
-    }))
+    useAvailableRouteData.mockReturnValue({
+      upload_id: 'test-id',
+      upload_name: 'test-name',
+      main_author: {name: 'test-main-author'},
+      coauthors: [{name: 'test-coauthor'}],
+    } as UploadResponse)
 
     render(<UploadMetadataEditor />)
 
@@ -24,4 +25,11 @@ describe('UploadMetadataEditor', () => {
     expect(screen.getByText(/test-main-author/)).toBeInTheDocument()
     expect(screen.getByText(/test-coauthor/)).toBeInTheDocument()
   })
+
+  it('renders nothing if no upload data is available', () => {
+    useAvailableRouteData.mockReturnValue(undefined)
+    render(<UploadMetadataEditor />)
+
+    expect(screen.queryByText('test-name')).not.toBeInTheDocument()
+  })
 })
diff --git a/src/pages/upload/UploadMetadataEditor.tsx b/src/pages/upload/UploadMetadataEditor.tsx
index 67e72700899751812c2fbd239e5842104c220614..7aa80cc2e9f45cc15697ed421c7f96a71c503751 100644
--- a/src/pages/upload/UploadMetadataEditor.tsx
+++ b/src/pages/upload/UploadMetadataEditor.tsx
@@ -3,7 +3,8 @@ import {useMemo} from 'react'
 import ProcessStatus from '../../components/ProcessStatus'
 import Visibility from '../../components/Visibility'
 import {Layout, LayoutItem} from '../../components/layout/Layout'
-import useRouteData from '../../components/routing/useRouteData'
+import {editableLayout} from '../../components/layout/useLayoutProps'
+import {useAvailableRouteData} from '../../components/routing/useRouteData'
 import List from '../../components/values/containers/List'
 import Text from '../../components/values/primitives/Text'
 import {UploadResponse} from '../../models/graphResponseModels'
@@ -44,7 +45,8 @@ export default function UploadMetadataEditor({
   main = false,
 }: UploadMetadataEditorProps) {
   expandedByDefault = main ? true : expandedByDefault
-  const data = useRouteData(uploadRoute) as UploadResponse
+  const availableData = useAvailableRouteData(uploadRoute)
+  const data = useMemo(() => availableData || {}, [availableData])
 
   const layout = useMemo(
     () =>
@@ -65,7 +67,6 @@ export default function UploadMetadataEditor({
                 grow: true,
                 type: 'value',
                 label: 'project name',
-                editable: editable,
                 value: data.upload_name,
                 component: {
                   Text: {
@@ -82,6 +83,7 @@ export default function UploadMetadataEditor({
               {
                 xs: 5,
                 type: 'value',
+                editable: false,
                 component: {
                   Id: {
                     abbreviated: true,
@@ -108,6 +110,7 @@ export default function UploadMetadataEditor({
               {
                 type: 'value',
                 label: 'created at',
+                editable: false,
                 component: {
                   Datetime: {
                     variant: 'datetime',
@@ -118,6 +121,7 @@ export default function UploadMetadataEditor({
               {
                 type: 'value',
                 label: 'last change',
+                editable: false,
                 component: {
                   Datetime: {
                     variant: 'datetime',
@@ -129,8 +133,12 @@ export default function UploadMetadataEditor({
           },
         ],
       } as LayoutItem),
-    [editable, expandedByDefault, main, data],
+    [expandedByDefault, main, data],
   )
 
-  return <Layout layout={layout} />
+  if (availableData === undefined) {
+    return ''
+  }
+
+  return <Layout layout={editableLayout(layout, editable)} />
 }
diff --git a/src/pages/upload/UploadOverview.tsx b/src/pages/upload/UploadOverview.tsx
index d579c453ff80fab9f8c8e8e4d91e8a7a99685f4d..8b35baecfe5c54c1c23d33e855aebb2d782b74c8 100644
--- a/src/pages/upload/UploadOverview.tsx
+++ b/src/pages/upload/UploadOverview.tsx
@@ -2,25 +2,32 @@ import {Box} from '@mui/material'
 
 import {PageTitle} from '../../components/page/Page'
 import useRouteData from '../../components/routing/useRouteData'
+import useViewWriteAbilities from '../../hooks/useViewWriteAbilities'
+import {DirectoryResponse} from '../../models/graphResponseModels'
 import UploadActions from './UploadActions'
 import {UploadFilePreview} from './UploadFiles'
 import UploadFilesDownload from './UploadFilesDownload'
 import UploadFilesTable from './UploadFilesTable'
 import UploadMetadataEditor from './UploadMetadataEditor'
-import {filesRoute} from './uploadRoute'
+import {uploadOverviewRoute} from './uploadRoute'
 
 export default function UploadOverview() {
-  const data = useRouteData(filesRoute)
+  const data = useRouteData(uploadOverviewRoute)
   const hasReadme = Object.keys(data).includes('README.md')
+  const {canWrite} = useViewWriteAbilities()
+  const editable = canWrite
 
   return (
     <>
       <PageTitle actions={<UploadFilesDownload />} />
       <Box sx={{mb: 4}}>
-        <UploadMetadataEditor main editable />
+        <UploadMetadataEditor main editable={editable} />
       </Box>
       <UploadActions />
-      <UploadFilesTable data={data} navigatePath={(path) => ['files', path]} />
+      <UploadFilesTable
+        data={data as DirectoryResponse}
+        navigatePath={(path) => ['files', path]}
+      />
       {hasReadme && <UploadFilePreview file='README.md' sx={{mt: 4}} />}
     </>
   )
diff --git a/src/pages/upload/UploadPage.test.tsx b/src/pages/upload/UploadPage.test.tsx
index 4c3af3584f298a906b6657062b6e789465d5279a..0249e4e5355a2dc0a6555071d024f6273598b288 100644
--- a/src/pages/upload/UploadPage.test.tsx
+++ b/src/pages/upload/UploadPage.test.tsx
@@ -1,6 +1,7 @@
 import {screen, waitFor} from '@testing-library/react'
 import {expect, it, vi} from 'vitest'
 
+import * as useViewWriteAbilities from '../../hooks/useViewWriteAbilities'
 import {GraphResponse} from '../../models/graphResponseModels'
 import * as api from '../../utils/api'
 import {
@@ -14,6 +15,10 @@ await importLazyComponents(uploadRoute)
 describe('UploadPage', () => {
   it('loads and initially renders the overview', async () => {
     const mockedApi = vi.spyOn(api, 'graphApi')
+    vi.spyOn(useViewWriteAbilities, 'default').mockReturnValue({
+      canWrite: true,
+      canRead: true,
+    })
     window.history.replaceState(null, '', '/project')
     mockedApi.mockResolvedValue({
       project: {
diff --git a/src/pages/upload/UploadPage.tsx b/src/pages/upload/UploadPage.tsx
index 862ebdda8a3d7fae722ba31cdba5d0b7644f1a14..a5625c656b75b326531ddd52b734bf3419929f3c 100644
--- a/src/pages/upload/UploadPage.tsx
+++ b/src/pages/upload/UploadPage.tsx
@@ -12,6 +12,7 @@ import useRoute from '../../components/routing/useRoute'
 import useRouteData from '../../components/routing/useRouteData'
 import useRecent from '../../hooks/useRecent'
 import {JSONObject} from '../../utils/types'
+import UnsavedChangesNav from '../entry/UnsavedChangesNav'
 import UploadFilesNav from './UploadFilesNav'
 import UploadNavAbout from './UploadNavAbout'
 import uploadRoute from './uploadRoute'
@@ -99,6 +100,8 @@ export default function UploadPage() {
               />
             </>
           )}
+          <Divider />
+          <UnsavedChangesNav uploadId={upload_id} />
         </Nav>
       }
     >
diff --git a/src/pages/upload/uploadRoute.tsx b/src/pages/upload/uploadRoute.tsx
index ed18029c79889860169dc6cabf474e77f275dc06..fb15bbdacf1a20a95de422b5f6681e9e09bb9c9c 100644
--- a/src/pages/upload/uploadRoute.tsx
+++ b/src/pages/upload/uploadRoute.tsx
@@ -58,27 +58,44 @@ const entriesRoute: Route<
 > = {
   path: 'entries',
   breadcrumb: <b>entries</b>,
-  request: ({search}) => ({
-    m_request: {
-      pagination: createPaginationRequest(search),
-    },
-    '*': {
-      entry_id: '*',
-      mainfile_path: '*',
-      entry_create_time: '*',
-      complete_time: '*',
-      process_status: '*',
-      metadata: {
-        entry_type: '*',
+  request: ({search, isLeaf}) => {
+    if (!isLeaf) {
+      return {} as EntriesRequest
+    }
+    return {
+      m_request: {
+        pagination: createPaginationRequest(search),
       },
-    },
-  }),
+      '*': {
+        entry_id: '*',
+        mainfile_path: '*',
+        entry_create_time: '*',
+        complete_time: '*',
+        process_status: '*',
+        metadata: {
+          entry_type: '*',
+        },
+      },
+    }
+  },
   lazyComponent: async () => import('./Entries'),
   validateSearch: validatePaginationSearch,
   onlyRender: '',
   children: [entryRoute],
 }
 
+export const uploadOverviewRoute: Route<
+  DirectoryRequest,
+  DirectoryResponse,
+  Required<PageBasedPagination>
+> = {
+  ...pathRoute,
+  path: '',
+  breadcrumb: <b>overview</b>,
+  lazyComponent: async () => import('./UploadOverview'),
+  requestKey: 'files',
+}
+
 const uploadRoute: Route<UploadRequest, UploadResponse> = {
   path: ':uploadId',
   request: {
@@ -91,6 +108,11 @@ const uploadRoute: Route<UploadRequest, UploadResponse> = {
     complete_time: '*',
     main_author: {name: '*'},
     coauthors: '*',
+    writers: '*',
+    writer_groups: '*',
+    viewers: '*',
+    viewer_groups: '*',
+    process_running: '*',
   },
   lazyComponent: async () => import('./UploadPage'),
   breadcrumb: ({response}) =>
@@ -103,13 +125,7 @@ const uploadRoute: Route<UploadRequest, UploadResponse> = {
     ),
   onlyRender: ['', 'files/*', 'entries', 'settings'],
   children: [
-    {
-      ...pathRoute,
-      path: '',
-      breadcrumb: <b>overview</b>,
-      lazyComponent: async () => import('./UploadOverview'),
-      requestKey: 'files',
-    },
+    uploadOverviewRoute,
     filesRoute,
     entriesRoute,
     {
diff --git a/src/pages/uploads/UploadsPage.tsx b/src/pages/uploads/UploadsPage.tsx
index 69d79424c475d939daaecc6c224251878018a6fc..01545cc7b748cddb110a1e3230537d8f67c7d848 100644
--- a/src/pages/uploads/UploadsPage.tsx
+++ b/src/pages/uploads/UploadsPage.tsx
@@ -1,14 +1,41 @@
-import {Divider, TextField} from '@mui/material'
+import {BadgeProps, Divider, TextField} from '@mui/material'
 
+import {MainMenuItem, MainMenuItemProps} from '../../components/app/MainMenu'
+import {useChangedArchives} from '../../components/archive/useArchive'
+import {Manage} from '../../components/icons'
 import Nav from '../../components/navigation/Nav'
 import NavItem from '../../components/navigation/NavItem'
 import RecentNav from '../../components/navigation/RecentNav'
 import useSelect from '../../components/navigation/useSelect'
 import Page, {PageActions, PageTitle} from '../../components/page/Page'
+import useRoute from '../../components/routing/useRoute'
+import UnsavedChangesNav from '../entry/UnsavedChangesNav'
 import UploadsActions from './UploadsActions'
 import UploadsTable from './UploadsTable'
 import UploadsTableFilterMenu from './UploadsTableFilterMenu'
 
+export function UploadsMainMenuItem(
+  mainMenuProps: Omit<MainMenuItemProps, 'label'>,
+) {
+  const {matches} = useRoute()
+  const changedArchives = useChangedArchives()
+  const badge = {
+    badgeContent: changedArchives.length,
+    color: 'error',
+  } satisfies BadgeProps
+
+  return (
+    <MainMenuItem
+      {...mainMenuProps}
+      label='Manage'
+      to='/uploads'
+      icon={<Manage />}
+      active={matches('/uploads')}
+      badge={badge}
+    />
+  )
+}
+
 export default function UploadsPage() {
   const {isPage, pageVariant} = useSelect()
 
@@ -24,6 +51,8 @@ export default function UploadsPage() {
             scope='global'
             storageKey='uploads'
           />
+          <Divider />
+          <UnsavedChangesNav />
         </Nav>
       }
     >
diff --git a/src/pages/uploads/UploadsTable.test.tsx b/src/pages/uploads/UploadsTable.test.tsx
index 97f1c65177078f4800fbb729253eba532d439eb7..bdb71e35cf39c443b07b3e8f5d81ca77bb88a6a1 100644
--- a/src/pages/uploads/UploadsTable.test.tsx
+++ b/src/pages/uploads/UploadsTable.test.tsx
@@ -2,6 +2,7 @@ import {act, fireEvent, render, screen} from '@testing-library/react'
 import {describe, expect, it, vi} from 'vitest'
 
 import UploadsTable from './UploadsTable'
+import uploadsRoute from './uploadsRoute'
 
 const setPaginate = vi.fn()
 const navigate = vi.fn()
@@ -24,6 +25,7 @@ vi.mock('../../components/routing/useRoute', () => ({
     navigate,
     search: {},
     url: () => '/',
+    route: uploadsRoute,
     response: Array.from({length: 12}, (_, index) => ({
       upload_id: `${index + 1}`,
       upload_name: `Upload ${index + 1}`,
diff --git a/src/utils/metainfo.test.ts b/src/utils/metainfo.test.ts
index 4d5d146a6d67231511a35f2ae4c7ce854b40345d..66dbe5fcdef99dfce3078d0b3547259e1808c557 100644
--- a/src/utils/metainfo.test.ts
+++ b/src/utils/metainfo.test.ts
@@ -1,6 +1,6 @@
 import {vi} from 'vitest'
 
-import {Metainfo, resolveAllMDefs} from './metainfo'
+import {Metainfo, removeInternalRefs, resolveAllMDefs} from './metainfo'
 import {JSONObject} from './types'
 
 describe('resolveSectionDef', () => {
@@ -173,6 +173,53 @@ describe('resolveSectionDef', () => {
   })
 })
 
+describe('removeInternalRefs', () => {
+  it('removes internal refs in a JSON object', () => {
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    const data: any = {
+      m_def: {
+        all_sub_sections: {
+          child_with_m_def: {
+            sub_section: 'm_def',
+          },
+          child_repeats_with_m_def: {
+            sub_section: 'm_def',
+            repeats: true,
+          },
+          child_list_with_m_def: {
+            sub_section: 'm_def',
+            repeats: true,
+          },
+        },
+      },
+      value: '__INTERNAL__:',
+      child: {
+        value: '__INTERNAL__:',
+      },
+      child_list: ['__INTERNAL__:', 'not internal'],
+      recursive: {
+        child: {
+          child: '__INTERNAL__:',
+        },
+      },
+      child_full_list: ['__INTERNAL__:', '__INTERNAL__:'],
+      child_with_m_def: '__INTERNAL__:',
+      child_repeats_with_m_def: '__INTERNAL__:',
+      child_list_with_m_def: ['__INTERNAL__:'],
+    }
+    removeInternalRefs(data)
+
+    expect(data.value).toBeUndefined()
+    expect(data.child.value).toBeUndefined()
+    expect(data.child_list).toEqual([null, 'not internal'])
+    expect(data.recursive.child.child).toBeUndefined()
+    expect(data.child_full_list).toEqual([])
+    expect(data.child_with_m_def).toEqual({m_def: 'm_def'})
+    expect(data.child_repeats_with_m_def).toEqual([])
+    expect(data.child_list_with_m_def).toEqual([{m_def: 'm_def'}])
+  })
+})
+
 describe('resolveAllMDefs', () => {
   it('resolves m_defs in a JSON object', () => {
     function createMDef(m_def: string) {
diff --git a/src/utils/metainfo.ts b/src/utils/metainfo.ts
index ddcbef72c25bc34637e828004486c053e4b3a4fa..3bcf45e8d46a694fc48a41464ea1270d06909339 100644
--- a/src/utils/metainfo.ts
+++ b/src/utils/metainfo.ts
@@ -252,6 +252,60 @@ export class Metainfo {
   }
 }
 
+/**
+ * Recursively traverses through the given data object and
+ * removes all internal references that where added by the API.
+ * If there is not m_def available the internal reference are simply removed.
+ * If there are m_defs and we can figure out the type of the internal
+ * reference, they are replaces with empty sections or arrays.
+ */
+export function removeInternalRefs(data: JSONObject) {
+  const isInternalRef = (value: JSONValue) =>
+    typeof value === 'string' && value.startsWith('__INTERNAL__:')
+
+  const m_def = data?.m_def as Section | undefined
+
+  for (const key in data) {
+    if (key.startsWith('m_')) {
+      continue
+    }
+    const value = data[key]
+    const subSection = m_def?.all_sub_sections?.[key]
+    if (isInternalRef(value)) {
+      if (subSection) {
+        if (subSection.repeats) {
+          data[key] = []
+        } else {
+          data[key] = {
+            m_def: subSection.sub_section,
+          } as JSONObject
+        }
+      } else {
+        delete data[key]
+      }
+    } else if (Array.isArray(value)) {
+      value.forEach((item, index) => {
+        if (isInternalRef(item)) {
+          if (subSection) {
+            value[index] = {
+              m_def: subSection.sub_section,
+            } as JSONObject
+          } else {
+            value[index] = null
+          }
+        } else if (typeof item === 'object') {
+          removeInternalRefs(item as JSONObject)
+        }
+      })
+      if (value.every((item) => item === null)) {
+        data[key] = []
+      }
+    } else if (typeof value === 'object') {
+      removeInternalRefs(value as JSONObject)
+    }
+  }
+}
+
 /**
  * Recursively traverses through the given data object and
  * resolves all m_def references it can find.