diff --git a/amt/api/deps.py b/amt/api/deps.py index 879029c9..733cabf8 100644 --- a/amt/api/deps.py +++ b/amt/api/deps.py @@ -12,7 +12,7 @@ from starlette.background import BackgroundTask from starlette.templating import _TemplateResponse # pyright: ignore [reportPrivateUsage] -from amt.api.editable import is_editable_resource +from amt.api.editable import is_editable_resource, is_parent_editable from amt.api.editable_util import replace_digits_in_brackets, resolve_resource_list_path from amt.api.http_browser_caching import url_for_cache from amt.api.localizable import LocalizableEnum @@ -168,6 +168,7 @@ def hasattr_jinja(obj: object, attributes: str) -> bool: templates.env.globals.update(permission=permission) # pyright: ignore [reportUnknownMemberType] templates.env.globals.update(hasattr=hasattr_jinja) # pyright: ignore [reportUnknownMemberType] templates.env.globals.update(is_path_with_list=is_path_with_list) # pyright: ignore [reportUnknownMemberType] +templates.env.globals.update(is_parent_editable=is_parent_editable) # pyright: ignore [reportUnknownMemberType] templates.env.globals.update(resolve_resource_list_path=resolve_resource_list_path) # pyright: ignore [reportUnknownMemberType] templates.env.tests["permission"] = permission # pyright: ignore [reportUnknownMemberType] templates.env.add_extension("jinja2_base64_filters.Base64Filters") # pyright: ignore [reportUnknownMemberType] diff --git a/amt/api/editable.py b/amt/api/editable.py index c73c1da6..af08af2c 100644 --- a/amt/api/editable.py +++ b/amt/api/editable.py @@ -42,11 +42,6 @@ class Editables: validator=EditableValidatorMinMaxLength(min_length=3, max_length=100), ) - ALGORITHM_EDITABLE_AUTHOR = Editable( - full_resource_path="algorithm/{algorithm_id}/system_card/provenance/author", - implementation_type=WebFormFieldImplementationType.TEXT, - ) - ALGORITHM_EDITABLE_SYSTEMCARD_OWNERS = Editable( full_resource_path="algorithm/{algorithm_id}/system_card/owners[*]", implementation_type=WebFormFieldImplementationType.PARENT, @@ -145,14 +140,23 @@ class Editables: ) ALGORITHM_EDITABLE_LIFECYCLE.add_bidirectional_couple(ALGORITHM_EDITABLE_SYSTEMCARD_STATUS) - ALGORITHM_EDITABLE_PROVENANCE_GIT_COMMIT_HASH = Editable( - full_resource_path="algorithm/{algorithm_id}/system_card/provenance/git_commit_hash", - implementation_type=WebFormFieldImplementationType.TEXT, - ) - - ALGORITHM_EDITABLE_PROVENANCE_URI = Editable( - full_resource_path="algorithm/{algorithm_id}/system_card/provenance/uri", - implementation_type=WebFormFieldImplementationType.TEXT, + ALGORITHM_EDITABLE_PROVENANCE = Editable( + full_resource_path="algorithm/{algorithm_id}/system_card/provenance", + implementation_type=WebFormFieldImplementationType.PARENT, + children=[ + Editable( + full_resource_path="algorithm/{algorithm_id}/system_card/provenance/author", + implementation_type=WebFormFieldImplementationType.TEXT, + ), + Editable( + full_resource_path="algorithm/{algorithm_id}/system_card/provenance/git_commit_hash", + implementation_type=WebFormFieldImplementationType.TEXT, + ), + Editable( + full_resource_path="algorithm/{algorithm_id}/system_card/provenance/uri", + implementation_type=WebFormFieldImplementationType.TEXT, + ), + ], ) ALGORITHM_EDITABLE_VERSION = Editable( @@ -546,3 +550,14 @@ def set_path(obj: dict[str, Any] | object, path: str, value: typing.Any) -> None def is_editable_resource(full_resource_path: str, editables: dict[str, ResolvedEditable]) -> bool: return editables.get(replace_digits_in_brackets(full_resource_path), None) is not None + + +def is_parent_editable(editables: dict[str, ResolvedEditable], full_resource_path: str) -> bool: + full_resource_path = replace_digits_in_brackets(full_resource_path) + editable = editables.get(full_resource_path) + if editable is None: + print(full_resource_path + " : " + "false, no match") + return False + result = editable.implementation_type == WebFormFieldImplementationType.PARENT + print(full_resource_path + " : " + str(result)) + return result diff --git a/amt/api/routes/algorithm.py b/amt/api/routes/algorithm.py index d92756b8..047966e3 100644 --- a/amt/api/routes/algorithm.py +++ b/amt/api/routes/algorithm.py @@ -357,8 +357,13 @@ async def get_algorithm_details( request, ) - context["breadcrumbs"] = breadcrumbs - context["base_href"] = f"/algorithm/{algorithm_id}" + context.update( + { + "breadcrumbs": breadcrumbs, + "base_href": f"/algorithm/{algorithm_id}", + "editables": get_resolved_editables(context_variables={"algorithm_id": algorithm_id}), + } + ) return templates.TemplateResponse(request, "algorithms/details_info.html.j2", context) @@ -429,6 +434,7 @@ async def get_algorithm_cancel( "resource_object": editable.resource_object, "full_resource_path": full_resource_path, "editable_object": editable, + "editables": get_resolved_editables(context_variables={"algorithm_id": algorithm_id}), } return templates.TemplateResponse(request, "parts/view_cell.html.j2", context) @@ -479,6 +485,7 @@ async def get_algorithm_update( "resource_object": editable.resource_object, "full_resource_path": full_resource_path, "editable_object": editable, + "editables": get_resolved_editables(context_variables={"algorithm_id": algorithm_id}), } return templates.TemplateResponse(request, "parts/view_cell.html.j2", context) diff --git a/amt/api/routes/organizations.py b/amt/api/routes/organizations.py index 7ac64b61..9acaffe5 100644 --- a/amt/api/routes/organizations.py +++ b/amt/api/routes/organizations.py @@ -10,6 +10,7 @@ from amt.api.editable import ( Editables, get_enriched_resolved_editable, + get_resolved_editables, save_editable, ) from amt.api.editable_classes import EditModes, ResolvedEditable @@ -186,6 +187,7 @@ async def get_by_slug( "organization_id": organization.id, "tab_items": tab_items, "breadcrumbs": breadcrumbs, + "editables": get_resolved_editables(context_variables={"organization_id": organization.id}), } return templates.TemplateResponse(request, "organizations/home.html.j2", context) @@ -267,6 +269,7 @@ async def get_organization_cancel( "resource_object": None, # TODO: this should become an optional parameter in the Jinja template "full_resource_path": full_resource_path, "editable_object": editable, + "editables": get_resolved_editables(context_variables={"organization_id": organization.id}), } return templates.TemplateResponse(request, "parts/view_cell.html.j2", context) @@ -319,6 +322,7 @@ async def get_organization_update( "resource_object": None, "full_resource_path": full_resource_path, "editable_object": editable, + "editables": get_resolved_editables(context_variables={"organization_id": organization.id}), } # TODO: add a 'next action' to editable for f.e. redirect options, THIS IS A HACK @@ -455,6 +459,8 @@ async def get_members( ) filters["organization-id"] = str(organization.id) + if "name" not in sort_by: + sort_by["name"] = "ascending" members = await users_service.find_all(search=search, sort=sort_by, filters=filters) context: dict[str, Any] = { diff --git a/amt/locale/base.pot b/amt/locale/base.pot index 724da9f8..917f1f63 100644 --- a/amt/locale/base.pot +++ b/amt/locale/base.pot @@ -414,8 +414,8 @@ msgid "measure executed" msgstr "" #: amt/site/templates/algorithms/details_compliance.html.j2:69 -#: amt/site/templates/macros/editable.html.j2:67 -#: amt/site/templates/macros/editable.html.j2:72 +#: amt/site/templates/macros/editable.html.j2:68 +#: amt/site/templates/macros/editable.html.j2:73 #: amt/site/templates/macros/tasks.html.j2:82 msgid "Edit" msgstr "" @@ -464,12 +464,12 @@ msgid "Read more on the algoritmekader" msgstr "" #: amt/site/templates/algorithms/details_measure_modal.html.j2:64 -#: amt/site/templates/macros/editable.html.j2:174 +#: amt/site/templates/macros/editable.html.j2:175 msgid "Save" msgstr "" #: amt/site/templates/algorithms/details_measure_modal.html.j2:68 -#: amt/site/templates/macros/editable.html.j2:179 +#: amt/site/templates/macros/editable.html.j2:180 #: amt/site/templates/organizations/parts/add_members_modal.html.j2:26 msgid "Cancel" msgstr "" @@ -689,10 +689,6 @@ msgstr "" msgid "Search" msgstr "" -#: amt/site/templates/organizations/parts/members_results.html.j2:37 -msgid "Find member..." -msgstr "" - #: amt/site/templates/organizations/parts/members_results.html.j2:66 #, python-format msgid "" diff --git a/amt/locale/en_US/LC_MESSAGES/messages.mo b/amt/locale/en_US/LC_MESSAGES/messages.mo index 738f59d7..8977e2a9 100644 Binary files a/amt/locale/en_US/LC_MESSAGES/messages.mo and b/amt/locale/en_US/LC_MESSAGES/messages.mo differ diff --git a/amt/locale/en_US/LC_MESSAGES/messages.po b/amt/locale/en_US/LC_MESSAGES/messages.po index 071e3fd6..18880c3b 100644 --- a/amt/locale/en_US/LC_MESSAGES/messages.po +++ b/amt/locale/en_US/LC_MESSAGES/messages.po @@ -415,8 +415,8 @@ msgid "measure executed" msgstr "" #: amt/site/templates/algorithms/details_compliance.html.j2:69 -#: amt/site/templates/macros/editable.html.j2:67 -#: amt/site/templates/macros/editable.html.j2:72 +#: amt/site/templates/macros/editable.html.j2:68 +#: amt/site/templates/macros/editable.html.j2:73 #: amt/site/templates/macros/tasks.html.j2:82 msgid "Edit" msgstr "" @@ -465,12 +465,12 @@ msgid "Read more on the algoritmekader" msgstr "" #: amt/site/templates/algorithms/details_measure_modal.html.j2:64 -#: amt/site/templates/macros/editable.html.j2:174 +#: amt/site/templates/macros/editable.html.j2:175 msgid "Save" msgstr "" #: amt/site/templates/algorithms/details_measure_modal.html.j2:68 -#: amt/site/templates/macros/editable.html.j2:179 +#: amt/site/templates/macros/editable.html.j2:180 #: amt/site/templates/organizations/parts/add_members_modal.html.j2:26 msgid "Cancel" msgstr "" @@ -690,12 +690,8 @@ msgstr "" msgid "Search" msgstr "" -#: amt/site/templates/organizations/parts/members_results.html.j2:37 -msgid "Find member..." -msgstr "" - #: amt/site/templates/organizations/parts/members_results.html.j2:66 -#, fuzzy, python-format +#, python-format msgid "" "%(members_length)s result\n" " " @@ -724,7 +720,7 @@ msgid "Organisation Type" msgstr "" #: amt/site/templates/organizations/parts/overview_results.html.j2:80 -#, fuzzy, python-format +#, python-format msgid "" "%(organizations_length)s result\n" " " diff --git a/amt/locale/nl_NL/LC_MESSAGES/messages.mo b/amt/locale/nl_NL/LC_MESSAGES/messages.mo index 3ebf3e40..41209d2b 100644 Binary files a/amt/locale/nl_NL/LC_MESSAGES/messages.mo and b/amt/locale/nl_NL/LC_MESSAGES/messages.mo differ diff --git a/amt/locale/nl_NL/LC_MESSAGES/messages.po b/amt/locale/nl_NL/LC_MESSAGES/messages.po index 19094a46..444d8c77 100644 --- a/amt/locale/nl_NL/LC_MESSAGES/messages.po +++ b/amt/locale/nl_NL/LC_MESSAGES/messages.po @@ -434,8 +434,8 @@ msgid "measure executed" msgstr "maatregelen uitgevoerd" #: amt/site/templates/algorithms/details_compliance.html.j2:69 -#: amt/site/templates/macros/editable.html.j2:67 -#: amt/site/templates/macros/editable.html.j2:72 +#: amt/site/templates/macros/editable.html.j2:68 +#: amt/site/templates/macros/editable.html.j2:73 #: amt/site/templates/macros/tasks.html.j2:82 msgid "Edit" msgstr "Bewerk" @@ -484,12 +484,12 @@ msgid "Read more on the algoritmekader" msgstr "Lees meer op het algoritmekader" #: amt/site/templates/algorithms/details_measure_modal.html.j2:64 -#: amt/site/templates/macros/editable.html.j2:174 +#: amt/site/templates/macros/editable.html.j2:175 msgid "Save" msgstr "Opslaan" #: amt/site/templates/algorithms/details_measure_modal.html.j2:68 -#: amt/site/templates/macros/editable.html.j2:179 +#: amt/site/templates/macros/editable.html.j2:180 #: amt/site/templates/organizations/parts/add_members_modal.html.j2:26 msgid "Cancel" msgstr "Annuleren" @@ -712,10 +712,6 @@ msgstr "Voeg personen toe" msgid "Search" msgstr "Zoek" -#: amt/site/templates/organizations/parts/members_results.html.j2:37 -msgid "Find member..." -msgstr "Voeg personen toe" - #: amt/site/templates/organizations/parts/members_results.html.j2:66 #, python-format msgid "" @@ -912,5 +908,5 @@ msgstr "Resultaten voor" #: amt/site/templates/parts/tasks_search.html.j2:50 msgid "Assignee" -msgstr "Verantwoordelijke" +msgstr "Toegewezen aan" diff --git a/amt/site/static/scss/layout.scss b/amt/site/static/scss/layout.scss index 99fced4f..042b1556 100644 --- a/amt/site/static/scss/layout.scss +++ b/amt/site/static/scss/layout.scss @@ -64,7 +64,7 @@ main { background-color: var(--rvo-color-lichtblauw-150); border-radius: 10px; height: calc(100% - 30px); /* todo (robbert): this is a display hack */ - padding: 0.01px; /* this is an avoid margin collapse hack */ + padding-top: 5px; } .progress-card-container { @@ -492,4 +492,12 @@ main { } } +.amt-editable-block:not(:has(form)) { + &:hover { + background-color: var(--rvo-color-grijs-100); + box-shadow: 0 0 5px 5px var(--rvo-color-grijs-100); + cursor: pointer; + } +} + /* stylelint-enable */ diff --git a/amt/site/static/ts/amt.ts b/amt/site/static/ts/amt.ts index 44a7bfde..d23129d1 100644 --- a/amt/site/static/ts/amt.ts +++ b/amt/site/static/ts/amt.ts @@ -53,6 +53,18 @@ function initPage() { "

Placeholder: Error while connecting to server { + if ((e.target as HTMLElement).classList.contains("amt-editable-block")) { + const linkEl = (e.target as HTMLElement)!.querySelectorAll( + ".amt-edit-link", + )[0]; + if (linkEl) { + (linkEl as HTMLElement).click(); + } + } + }); + const columns = document.getElementsByClassName( "progress-cards-container", ) as HTMLCollectionOf; diff --git a/amt/site/templates/macros/cards.html.j2 b/amt/site/templates/macros/cards.html.j2 index 7cd0ce0c..e9f150d2 100644 --- a/amt/site/templates/macros/cards.html.j2 +++ b/amt/site/templates/macros/cards.html.j2 @@ -16,19 +16,20 @@
{% if is_editable_resource(full_resource_path, editables) %} {{ editable(algorithm, relative_resource_path, full_resource_path) }} - {% endif %} - {% if value.__class__.__name__ == 'dict' %} - {% set value = value.items() %} - {% endif %} - {% for subkey, subvalue in value %} - {{ render_attribute(subkey) }}: - {% if is_editable_resource(full_resource_path + "/" + subkey, editables) %} - {{ editable(algorithm, relative_resource_path + "/" + subkey, full_resource_path + "/" + subkey) }} - {% else %} - {{ render_value(subkey, subvalue, depth+1, base_resource_path, path) }} + {% else %} + {% if value.__class__.__name__ == 'dict' %} + {% set value = value.items() %} {% endif %} - {% if not loop.last %}
{% endif %} - {% endfor %} + {% for subkey, subvalue in value %} + {{ render_attribute(subkey) }}: + {% if is_editable_resource(full_resource_path + "/" + subkey, editables) %} + {{ editable(algorithm, relative_resource_path + "/" + subkey, full_resource_path + "/" + subkey) }} + {% else %} + {{ render_value(subkey, subvalue, depth+1, base_resource_path, path) }} + {% endif %} + {% if not loop.last %}
{% endif %} + {% endfor %} + {% endif %}
{% elif isinstance(value, 'list') %} {% if key == "assessments" %} @@ -61,7 +62,7 @@ {% endif %} {% else %} {% if is_editable_resource(full_resource_path, editables) %} - {{ editable(algorithm, relative_resource_path, full_resource_path) }} +
{{ editable(algorithm, relative_resource_path, full_resource_path) }}
{% else %} {{ value }} {% endif %} diff --git a/amt/site/templates/macros/editable.html.j2 b/amt/site/templates/macros/editable.html.j2 index b1d5c376..c825346a 100644 --- a/amt/site/templates/macros/editable.html.j2 +++ b/amt/site/templates/macros/editable.html.j2 @@ -2,17 +2,15 @@ {{ attribute.capitalize().replace("_", " ") }} {%- endmacro %} {% macro editable(obj, relative_resource_path, full_resource_path, editable_object = None) %} - {# TODO: maybe editable self should contain the type of container?#} - {% if is_path_with_list(full_resource_path) %} - {# we know it is a list, but not what is in the list.. this now only works for editables with children #} + {% if is_parent_editable(editables, full_resource_path) %} {% if editable_object is none %} {% set editable_object = editables[replace_digits_in_brackets(full_resource_path)] %} {% endif %} -
+
{% if editable_object.children is not none and editable_object.children | length > 0 %} {% for child_editable in editable_object.children %} {{ render_attribute(child_editable.last_path_item() ) }}: - {{ nested_value(obj, resolve_resource_list_path(full_resource_path, child_editable.relative_resource_path) ) }} + {{ display_value(child_editable.last_path_item() , nested_value(obj, resolve_resource_list_path(full_resource_path, child_editable.relative_resource_path))) }} {% if not loop.last %}
{% endif %} {% endfor %} {% else %} @@ -21,7 +19,7 @@ {{ edit_link(base_href, full_resource_path) }}
{% else %} - +
{% if editable_object is not none %} {% set value = editable_object.value %} {% else %} @@ -36,30 +34,33 @@ {{ edit_link(base_href, full_resource_path) }} {% else %} - {% if key == "uri" or key == "link" or key == "upl" %} - {{ value }} - {% elif key == "oin" %} - {{ value }} - {% elif key == "email" %} - {{ value }} - {% elif key == "urn" %} - {{ value }} - {% elif value is string and value.startswith('http') %} - {{ value }} - {% else %} - {{ value }} - {% endif %} + {{ display_value(key, value) }} {{ edit_link(base_href, full_resource_path) }} {% endif %} - +
+ {% endif %} +{% endmacro %} +{% macro display_value(key, value) %} + {% if key == "uri" or key == "link" or key == "upl" %} + {{ value }} + {% elif key == "oin" %} + {{ value }} + {% elif key == "email" %} + {{ value }} + {% elif key == "urn" %} + {{ value }} + {% elif value is string and value.startswith('http') %} + {{ value }} + {% else %} + {{ value }} {% endif %} {% endmacro %} {% macro edit_link(base_href, full_resource_path) %} -
- {{ render_attribute(child_editable.last_path_item() ) }}: + {{ render_attribute(child_editable.last_path_item() ) }}:
{{ inline_editor_form_field(child_editable) }}
diff --git a/amt/site/templates/organizations/parts/members_results.html.j2 b/amt/site/templates/organizations/parts/members_results.html.j2 index fae7cda5..ba43e6e5 100644 --- a/amt/site/templates/organizations/parts/members_results.html.j2 +++ b/amt/site/templates/organizations/parts/members_results.html.j2 @@ -34,7 +34,7 @@ class="utrecht-textbox utrecht-textbox--html-input form-input-search" dir="auto" value="{{ search }}" - placeholder="{% trans %}Find member...{% endtrans %}" + placeholder="" name="search" hx-get="/organizations/{{ slug }}/members?skip=0" hx-trigger="input changed delay:500ms, search"