Skip to content

Commit

Permalink
Make editable fields easier to edit and group provenance as one block.
Browse files Browse the repository at this point in the history
  • Loading branch information
uittenbroekrobbert committed Feb 3, 2025
1 parent 3a11427 commit 8e4d792
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 67 deletions.
3 changes: 2 additions & 1 deletion amt/api/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
41 changes: 28 additions & 13 deletions amt/api/editable.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions amt/api/routes/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,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)
Expand Down Expand Up @@ -479,6 +480,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)
Expand Down
8 changes: 4 additions & 4 deletions amt/locale/base.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand Down Expand Up @@ -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 ""
Expand Down
Binary file modified amt/locale/en_US/LC_MESSAGES/messages.mo
Binary file not shown.
8 changes: 4 additions & 4 deletions amt/locale/en_US/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand Down Expand Up @@ -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 ""
Expand Down
Binary file modified amt/locale/nl_NL/LC_MESSAGES/messages.mo
Binary file not shown.
10 changes: 5 additions & 5 deletions amt/locale/nl_NL/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -912,5 +912,5 @@ msgstr "Resultaten voor"

#: amt/site/templates/parts/tasks_search.html.j2:50
msgid "Assignee"
msgstr "Verantwoordelijke"
msgstr "Toegewezen aan"

10 changes: 9 additions & 1 deletion amt/site/static/scss/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 */
12 changes: 12 additions & 0 deletions amt/site/static/ts/amt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ function initPage() {
"<h1>Placeholder: Error while connecting to server</h1";
});

/* we register the click on the body to avoid having to dynamically add it to each element, especially after a htmlx swap event */
document.querySelector("body")!.addEventListener("click", (e) => {
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<HTMLDivElement>;
Expand Down
27 changes: 14 additions & 13 deletions amt/site/templates/macros/cards.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,20 @@
<div class="{% if depth == 1 %}margin-bottom-large{% endif %}">
{% 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 %}
<strong>{{ render_attribute(subkey) }}</strong>:
{% 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 %}<br />{% endif %}
{% endfor %}
{% for subkey, subvalue in value %}
<strong>{{ render_attribute(subkey) }}</strong>:
{% 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 %}<br />{% endif %}
{% endfor %}
{% endif %}
</div>
{% elif isinstance(value, 'list') %}
{% if key == "assessments" %}
Expand Down Expand Up @@ -61,7 +62,7 @@
{% endif %}
{% else %}
{% if is_editable_resource(full_resource_path, editables) %}
{{ editable(algorithm, relative_resource_path, full_resource_path) }}
<div class="amt-editable-block">{{ editable(algorithm, relative_resource_path, full_resource_path) }}</div>
{% else %}
{{ value }}
{% endif %}
Expand Down
53 changes: 27 additions & 26 deletions amt/site/templates/macros/editable.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
<div hx-target="this">
<div hx-target="this" class="amt-editable-block">
{% if editable_object.children is not none and editable_object.children | length > 0 %}
{% for child_editable in editable_object.children %}
<strong>{{ render_attribute(child_editable.last_path_item() ) }}</strong>:
{{ 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 %}<br />{% endif %}
{% endfor %}
{% else %}
Expand All @@ -21,7 +19,7 @@
{{ edit_link(base_href, full_resource_path) }}
</div>
{% else %}
<span hx-target="this">
<div hx-target="this" class="amt-editable-block">
{% if editable_object is not none %}
{% set value = editable_object.value %}
{% else %}
Expand All @@ -36,30 +34,33 @@
</span>
{{ edit_link(base_href, full_resource_path) }}
{% else %}
{% if key == "uri" or key == "link" or key == "upl" %}
<a class="rvo-link rvo-link--normal" href="{{ value }}">{{ value }}</a>
{% elif key == "oin" %}
<a class="rvo-link rvo-link--normal"
href="https://oinregister.logius.nl/oin-register/{{ value }}">{{ value }}</a>
{% elif key == "email" %}
<a class="rvo-link rvo-link--normal" href="mailto:{{ value }}">{{ value }}</a>
{% elif key == "urn" %}
<a class="rvo-link rvo-link--normal"
href="https://task-registry.apps.digilab.network/urns/?version=latest&urn={{ value }}">{{ value }}</a>
{% elif value is string and value.startswith('http') %}
<a href="{{ value }}" target="_blank" rel="noopener noreferrer">{{ value }}</a>
{% else %}
{{ value }}
{% endif %}
{{ display_value(key, value) }}
{{ edit_link(base_href, full_resource_path) }}
{% endif %}
</span>
</div>
{% endif %}
{% endmacro %}
{% macro display_value(key, value) %}
{% if key == "uri" or key == "link" or key == "upl" %}
<a class="rvo-link rvo-link--normal" href="{{ value }}">{{ value }}</a>
{% elif key == "oin" %}
<a class="rvo-link rvo-link--normal"
href="https://oinregister.logius.nl/oin-register/{{ value }}">{{ value }}</a>
{% elif key == "email" %}
<a class="rvo-link rvo-link--normal" href="mailto:{{ value }}">{{ value }}</a>
{% elif key == "urn" %}
<a class="rvo-link rvo-link--normal"
href="https://task-registry.apps.digilab.network/urns/?version=latest&urn={{ value }}">{{ value }}</a>
{% elif value is string and value.startswith('http') %}
<a href="{{ value }}" target="_blank" rel="noopener noreferrer">{{ value }}</a>
{% else %}
{{ value }}
{% endif %}
{% endmacro %}
{% macro edit_link(base_href, full_resource_path) %}
<span class="rvo-link rvo-link--hover rvo-link--with-icon"
<span class="rvo-link rvo-link--hover rvo-link--with-icon amt-edit-link"
hx-get="{{ base_href }}/edit?full_resource_path={{ full_resource_path }}"
hx-swap="innerHTML"
hx-swap="outerHTML"
style="cursor: pointer;
float:right">
<span class="utrecht-icon rvo-icon rvo-icon-bewerken rvo-icon--md rvo-icon--hemelblauw"
Expand All @@ -77,7 +78,7 @@
<form hx-put="{{ base_href }}/update?full_resource_path={{ editable_object.full_resource_path }}"
hx-ext="json-enc"
hx-target-error="#errorContainer"
hx-swap="innerHTML"
hx-swap="outerHTML"
method="post"
hx-headers='{"X-CSRF-Token": "{{ csrftoken }}"}'
hx-swap="outerHTML"
Expand All @@ -89,7 +90,7 @@
<div>
<div id="error-{{ child_editable.safe_html_path() }}"
class="htmx-error-oob margin-top-middle"></div>
{{ render_attribute(child_editable.last_path_item() ) }}:
<strong>{{ render_attribute(child_editable.last_path_item() ) }}</strong>:
<br />
{{ inline_editor_form_field(child_editable) }}
</div>
Expand Down

0 comments on commit 8e4d792

Please sign in to comment.