diff --git a/amt/api/forms/measure.py b/amt/api/forms/measure.py
index 8d9418f1..c4868627 100644
--- a/amt/api/forms/measure.py
+++ b/amt/api/forms/measure.py
@@ -1,10 +1,19 @@
from collections.abc import Sequence
+from enum import StrEnum
from gettext import NullTranslations
from amt.models import User
from amt.schema.webform import WebForm, WebFormField, WebFormFieldType, WebFormOption, WebFormTextCloneableField
+class MeasureStatusOptions(StrEnum):
+ TODO = "to do"
+ IN_PROGRESS = "in progress"
+ IN_REVIEW = "in review"
+ DONE = "done"
+ NOT_IMPLEMENTED = "not implemented"
+
+
async def get_measure_form(
id: str,
current_values: dict[str, str | list[str] | list[tuple[str, str]]],
@@ -47,11 +56,11 @@ async def get_measure_form(
name="measure_state",
label=_("Status"),
options=[
- WebFormOption(value="to do", display_value="to do"),
- WebFormOption(value="in progress", display_value="in progress"),
- WebFormOption(value="in review", display_value="in review"),
- WebFormOption(value="done", display_value="done"),
- WebFormOption(value="not implemented", display_value="not implemented"),
+ WebFormOption(value=MeasureStatusOptions.TODO, display_value="to do"),
+ WebFormOption(value=MeasureStatusOptions.IN_PROGRESS, display_value="in progress"),
+ WebFormOption(value=MeasureStatusOptions.IN_REVIEW, display_value="in review"),
+ WebFormOption(value=MeasureStatusOptions.DONE, display_value="done"),
+ WebFormOption(value=MeasureStatusOptions.NOT_IMPLEMENTED, display_value="not implemented"),
],
default_value=current_values.get("measure_state"),
group="1",
diff --git a/amt/api/routes/algorithm.py b/amt/api/routes/algorithm.py
index ee627d75..5d2d2c6e 100644
--- a/amt/api/routes/algorithm.py
+++ b/amt/api/routes/algorithm.py
@@ -1,13 +1,14 @@
import asyncio
import datetime
import logging
+import urllib.parse
from collections import defaultdict
from collections.abc import Sequence
from typing import Annotated, Any
import yaml
from fastapi import APIRouter, Depends, File, Form, Query, Request, Response, UploadFile
-from fastapi.responses import FileResponse, HTMLResponse
+from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
from ulid import ULID
from amt.api.decorators import permission
@@ -19,7 +20,7 @@
get_resolved_editables,
save_editable,
)
-from amt.api.forms.measure import get_measure_form
+from amt.api.forms.measure import MeasureStatusOptions, get_measure_form
from amt.api.navigation import (
BaseNavigationItem,
Navigation,
@@ -42,10 +43,10 @@
from amt.schema.task import MovedTask
from amt.services.algorithms import AlgorithmsService
from amt.services.instruments_and_requirements_state import InstrumentStateService, RequirementsStateService
-from amt.services.measures import MeasuresService, create_measures_service
+from amt.services.measures import measures_service
from amt.services.object_storage import ObjectStorageService, create_object_storage_service
from amt.services.organizations import OrganizationsService
-from amt.services.requirements import RequirementsService, create_requirements_service
+from amt.services.requirements import requirements_service
from amt.services.tasks import TasksService
router = APIRouter()
@@ -63,7 +64,6 @@ async def get_instrument_state(system_card: SystemCard) -> dict[str, Any]:
async def get_requirements_state(system_card: SystemCard) -> dict[str, Any]:
- requirements_service = create_requirements_service()
requirements = await requirements_service.fetch_requirements(
[requirement.urn for requirement in system_card.requirements]
)
@@ -411,8 +411,6 @@ async def get_system_card_requirements(
organizations_repository: Annotated[OrganizationsRepository, Depends(OrganizationsRepository)],
users_repository: Annotated[UsersRepository, Depends(UsersRepository)],
algorithms_service: Annotated[AlgorithmsService, Depends(AlgorithmsService)],
- requirements_service: Annotated[RequirementsService, Depends(create_requirements_service)],
- measures_service: Annotated[MeasuresService, Depends(create_measures_service)],
) -> HTMLResponse:
algorithm = await get_algorithm_or_error(algorithm_id, algorithms_service, request)
instrument_state = await get_instrument_state(algorithm.system_card)
@@ -497,7 +495,7 @@ async def get_measure_task_functions(
measure_task_functions: dict[str, list[User]] = defaultdict(list)
for measure_task in measure_tasks:
- person_types = ["accountable_persons", "reviewer_persons", "responsible_persons"]
+ person_types = ["responsible_persons", "reviewer_persons", "accountable_persons"]
for person_type in person_types:
person_list = getattr(measure_task, person_type)
if person_list:
@@ -527,8 +525,6 @@ async def find_requirement_tasks_by_measure_urn(system_card: SystemCard, measure
requirement_mapper[requirement_task.urn] = requirement_task
requirement_tasks: list[RequirementTask] = []
- measures_service = create_measures_service()
- requirements_service = create_requirements_service()
measure = await measures_service.fetch_measures(measure_urn)
for requirement_urn in measure[0].links:
# TODO: This is because measure are linked to too many requirement not applicable in our use case
@@ -561,9 +557,9 @@ async def get_measure(
algorithm_id: int,
measure_urn: str,
algorithms_service: Annotated[AlgorithmsService, Depends(AlgorithmsService)],
- measures_service: Annotated[MeasuresService, Depends(create_measures_service)],
object_storage_service: Annotated[ObjectStorageService, Depends(create_object_storage_service)],
search: str = Query(""),
+ requirement_urn: str = "",
) -> HTMLResponse:
filters, _, _, sort_by = get_filters_and_sort_by(request)
algorithm = await get_algorithm_or_error(algorithm_id, algorithms_service, request)
@@ -598,7 +594,12 @@ async def get_measure(
translations=get_current_translation(request),
)
- context = {"measure": measure[0], "algorithm_id": algorithm_id, "form": measure_form}
+ context = {
+ "measure": measure[0],
+ "algorithm_id": algorithm_id,
+ "form": measure_form,
+ "requirement_urn": requirement_urn,
+ }
return templates.TemplateResponse(request, "algorithms/details_measure_modal.html.j2", context)
@@ -633,7 +634,6 @@ async def update_measure_value(
organizations_repository: Annotated[OrganizationsRepository, Depends(OrganizationsRepository)],
users_repository: Annotated[UsersRepository, Depends(UsersRepository)],
algorithms_service: Annotated[AlgorithmsService, Depends(AlgorithmsService)],
- requirements_service: Annotated[RequirementsService, Depends(create_requirements_service)],
object_storage_service: Annotated[ObjectStorageService, Depends(create_object_storage_service)],
measure_state: Annotated[str, Form()],
measure_responsible: Annotated[str | None, Form()] = None,
@@ -642,6 +642,7 @@ async def update_measure_value(
measure_value: Annotated[str | None, Form()] = None,
measure_links: Annotated[list[str] | None, Form()] = None,
measure_files: Annotated[list[UploadFile] | None, File()] = None,
+ requirement_urn: str = "",
) -> HTMLResponse:
filters, _, _, sort_by = get_filters_and_sort_by(request)
algorithm = await get_algorithm_or_error(algorithm_id, algorithms_service, request)
@@ -670,24 +671,51 @@ async def update_measure_value(
requirement_urns = [requirement_task.urn for requirement_task in requirement_tasks]
requirements = await requirements_service.fetch_requirements(requirement_urns)
+ state_order_list = set(MeasureStatusOptions)
for requirement in requirements:
- count_completed = 0
+ state_count: dict[str, int] = {}
for link_measure_urn in requirement.links:
link_measure_task = find_measure_task(algorithm.system_card, link_measure_urn)
- if link_measure_task: # noqa: SIM102
- if link_measure_task.state == "done":
- count_completed += 1
+ if link_measure_task:
+ state_count[link_measure_task.state] = state_count.get(link_measure_task.state, 0) + 1
requirement_task = find_requirement_task(algorithm.system_card, requirement.urn)
- if count_completed == len(requirement.links):
- requirement_task.state = "done" # pyright: ignore [reportOptionalMemberAccess]
- elif count_completed == 0 and len(requirement.links) > 0:
- requirement_task.state = "to do" # pyright: ignore [reportOptionalMemberAccess]
- else:
- requirement_task.state = "in progress" # pyright: ignore [reportOptionalMemberAccess]
+ full_match = False
+ for state in state_order_list:
+ # if all measures are in the same state, the requirement is set to that state
+ if requirement_task and state_count.get(state, 0) == len(requirement.links):
+ requirement_task.state = state
+ full_match = True
+ break
+ # a requirement is considered 'in progress' if any measure is of any state other than todo
+ if requirement_task and not full_match:
+ if len([key for key in state_count if key != MeasureStatusOptions.TODO]) > 0:
+ requirement_task.state = MeasureStatusOptions.IN_PROGRESS
+ else:
+ requirement_task.state = MeasureStatusOptions.TODO
await algorithms_service.update(algorithm)
- # TODO: FIX THIS!! The page now reloads at the top, which is annoying
- return templates.Redirect(request, f"/algorithm/{algorithm_id}/details/system_card/compliance")
+
+ # the redirect 'to same page' does not trigger a javascript reload, so we let us redirect by a different server URL
+ encoded_url = urllib.parse.quote_plus(
+ f"/algorithm/{algorithm_id}/details/system_card/compliance#{requirement_urn.replace(":","_")}"
+ )
+ return templates.Redirect(
+ request,
+ f"/algorithm/{algorithm_id}/redirect?to={encoded_url}",
+ )
+
+
+@router.get("/{algorithm_id}/redirect")
+@permission({AuthorizationResource.ALGORITHM: [AuthorizationVerb.READ]})
+async def redirect_to(request: Request, algorithm_id: str, to: str) -> RedirectResponse:
+ """
+ Redirects to the requested URL. We only have and use this because HTMX and javascript redirects do
+ not work when redirecting to the same URL, even if query params are changed.
+ """
+ return RedirectResponse(
+ status_code=302,
+ url=to,
+ )
@router.get("/{algorithm_id}/members")
diff --git a/amt/api/routes/algorithms.py b/amt/api/routes/algorithms.py
index e2d6e3de..22754d71 100644
--- a/amt/api/routes/algorithms.py
+++ b/amt/api/routes/algorithms.py
@@ -22,7 +22,6 @@
from amt.schema.algorithm import AlgorithmNew
from amt.schema.webform import WebForm
from amt.services.algorithms import AlgorithmsService, get_template_files
-from amt.services.instruments import InstrumentsService, create_instrument_service
from amt.services.organizations import OrganizationsService
router = APIRouter()
@@ -128,7 +127,6 @@ async def get_algorithms(
@permission({AuthorizationResource.ALGORITHMS: [AuthorizationVerb.CREATE]})
async def get_new(
request: Request,
- instrument_service: Annotated[InstrumentsService, Depends(create_instrument_service)],
organizations_service: Annotated[OrganizationsService, Depends(OrganizationsService)],
organization_id: int = Query(None),
) -> HTMLResponse:
@@ -151,10 +149,8 @@ async def get_new(
template_files = get_template_files()
- instruments = await instrument_service.fetch_instruments()
-
context: dict[str, Any] = {
- "instruments": instruments,
+ "instruments": [],
"ai_act_profile": ai_act_profile,
"breadcrumbs": breadcrumbs,
"sub_menu_items": {}, # sub_menu_items disabled for now,
diff --git a/amt/api/routes/organizations.py b/amt/api/routes/organizations.py
index 55418a26..3f8dbd34 100644
--- a/amt/api/routes/organizations.py
+++ b/amt/api/routes/organizations.py
@@ -112,6 +112,11 @@ async def root(
search=search, sort=sort_by, filters=filters, user_id=user["sub"] if user else None
)
+ # we only can show organization you belong to, so the all organizations option is disabled
+ organization_filters = [
+ f for f in get_localized_organization_filters(request) if f and f.value != OrganizationFilterOptions.ALL.value
+ ]
+
context: dict[str, Any] = {
"breadcrumbs": breadcrumbs,
"organizations": organizations,
@@ -123,7 +128,7 @@ async def root(
"organizations_length": len(organizations),
"filters": localized_filters,
"include_filters": False,
- "organization_filters": get_localized_organization_filters(request),
+ "organization_filters": organization_filters,
}
if request.state.htmx:
diff --git a/amt/cli/check_state.py b/amt/cli/check_state.py
index 1415f510..3c7fb889 100644
--- a/amt/cli/check_state.py
+++ b/amt/cli/check_state.py
@@ -8,7 +8,7 @@
from amt.schema.instrument import Instrument
from amt.schema.system_card import SystemCard
-from amt.services.instruments import create_instrument_service
+from amt.services.instruments import instruments_service
from amt.services.instruments_and_requirements_state import all_lifecycles, get_all_next_tasks
from amt.services.storage import StorageFactory
@@ -30,7 +30,6 @@ def get_requested_instruments(all_instruments: list[Instrument], urns: list[str]
def get_tasks_by_priority(urns: list[str], system_card_path: Path) -> None:
try:
system_card = get_system_card(system_card_path)
- instruments_service = create_instrument_service()
all_instruments = asyncio.run(instruments_service.fetch_instruments())
instruments = get_requested_instruments(all_instruments, urns)
next_tasks = get_all_next_tasks(instruments, system_card)
diff --git a/amt/locale/base.pot b/amt/locale/base.pot
index bd333727..8ccc24ca 100644
--- a/amt/locale/base.pot
+++ b/amt/locale/base.pot
@@ -46,7 +46,7 @@ msgid "Role"
msgstr ""
#: amt/api/group_by_category.py:15
-#: amt/site/templates/algorithms/details_info.html.j2:96
+#: amt/site/templates/algorithms/details_info.html.j2:101
#: amt/site/templates/algorithms/new.html.j2:41
#: amt/site/templates/parts/algorithm_search.html.j2:48
#: amt/site/templates/parts/filter_list.html.j2:71
@@ -145,7 +145,7 @@ msgstr ""
msgid "Model"
msgstr ""
-#: amt/api/navigation.py:62 amt/site/templates/algorithms/new.html.j2:170
+#: amt/api/navigation.py:62
msgid "Instruments"
msgstr ""
@@ -164,11 +164,7 @@ msgstr ""
msgid "Compliance"
msgstr ""
-#: amt/api/organization_filter_options.py:17
-msgid "All organizations"
-msgstr ""
-
-#: amt/api/organization_filter_options.py:17
+#: amt/api/organization_filter_options.py:16
msgid "My organizations"
msgstr ""
@@ -197,54 +193,54 @@ msgid "Select organization"
msgstr ""
#: amt/api/forms/algorithm.py:42
-#: amt/site/templates/algorithms/details_info.html.j2:74
+#: amt/site/templates/algorithms/details_info.html.j2:79
msgid "Organization"
msgstr ""
-#: amt/api/forms/measure.py:24
+#: amt/api/forms/measure.py:33
msgid "Responsible"
msgstr ""
-#: amt/api/forms/measure.py:32
+#: amt/api/forms/measure.py:41
msgid "Reviewer"
msgstr ""
-#: amt/api/forms/measure.py:40
+#: amt/api/forms/measure.py:49
msgid "Accountable"
msgstr ""
-#: amt/api/forms/measure.py:48
+#: amt/api/forms/measure.py:57
msgid "Status"
msgstr ""
-#: amt/api/forms/measure.py:63
+#: amt/api/forms/measure.py:72
msgid "Information on how this measure is implemented"
msgstr ""
-#: amt/api/forms/measure.py:70
+#: amt/api/forms/measure.py:79
msgid ""
"Select one or more to upload. The files will be saved once you confirm "
"changes by pressing the save button."
msgstr ""
-#: amt/api/forms/measure.py:75
+#: amt/api/forms/measure.py:84
msgid "Add files"
msgstr ""
-#: amt/api/forms/measure.py:76
+#: amt/api/forms/measure.py:85
msgid "No files selected."
msgstr ""
-#: amt/api/forms/measure.py:80
+#: amt/api/forms/measure.py:89
msgid "Add URI"
msgstr ""
-#: amt/api/forms/measure.py:83
+#: amt/api/forms/measure.py:92
msgid "Add links to documents"
msgstr ""
#: amt/api/forms/organization.py:23
-#: amt/site/templates/algorithms/details_info.html.j2:70
+#: amt/site/templates/algorithms/details_info.html.j2:75
#: amt/site/templates/auth/profile.html.j2:34
#: amt/site/templates/organizations/home.html.j2:13
#: amt/site/templates/organizations/parts/members_results.html.j2:118
@@ -381,11 +377,11 @@ msgstr ""
msgid "Download as YAML"
msgstr ""
-#: amt/site/templates/algorithms/details_compliance.html.j2:34
+#: amt/site/templates/algorithms/details_compliance.html.j2:36
msgid "measure executed"
msgstr ""
-#: amt/site/templates/algorithms/details_compliance.html.j2:67
+#: amt/site/templates/algorithms/details_compliance.html.j2:69
#: amt/site/templates/macros/editable.html.j2:28
#: amt/site/templates/macros/editable.html.j2:33
msgid "Edit"
@@ -396,37 +392,37 @@ msgid "Does the algorithm meet the requirements?"
msgstr ""
#: amt/site/templates/algorithms/details_info.html.j2:20
-#: amt/site/templates/algorithms/details_info.html.j2:46
+#: amt/site/templates/algorithms/details_info.html.j2:48
#: amt/site/templates/macros/tasks.html.j2:32
msgid "Done"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:42
+#: amt/site/templates/algorithms/details_info.html.j2:44
msgid "To do"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:44
+#: amt/site/templates/algorithms/details_info.html.j2:46
msgid "In progress"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:60
+#: amt/site/templates/algorithms/details_info.html.j2:65
msgid "Go to all requirements"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:80
+#: amt/site/templates/algorithms/details_info.html.j2:85
#: amt/site/templates/algorithms/details_measure_modal.html.j2:27
msgid "Description"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:86
+#: amt/site/templates/algorithms/details_info.html.j2:91
msgid "Repository"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:92
+#: amt/site/templates/algorithms/details_info.html.j2:97
msgid "Algorithm code"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:102
+#: amt/site/templates/algorithms/details_info.html.j2:107
#: amt/site/templates/organizations/parts/overview_results.html.j2:134
#: amt/site/templates/pages/assessment_card.html.j2:7
#: amt/site/templates/pages/model_card.html.j2:6
@@ -436,11 +432,11 @@ msgstr ""
msgid "Last updated"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:106
+#: amt/site/templates/algorithms/details_info.html.j2:111
msgid "Labels"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:114
+#: amt/site/templates/algorithms/details_info.html.j2:119
msgid "References"
msgstr ""
@@ -509,21 +505,11 @@ msgstr ""
msgid "Select Option"
msgstr ""
-#: amt/site/templates/algorithms/new.html.j2:172
-msgid ""
-"Overview of instruments for the responsible development, deployment, "
-"assessment, and monitoring of algorithms and AI-systems."
-msgstr ""
-
-#: amt/site/templates/algorithms/new.html.j2:180
-msgid "Choose one or more instruments"
-msgstr ""
-
-#: amt/site/templates/algorithms/new.html.j2:204
+#: amt/site/templates/algorithms/new.html.j2:176
msgid "Create Algorithm"
msgstr ""
-#: amt/site/templates/algorithms/new.html.j2:221
+#: amt/site/templates/algorithms/new.html.j2:193
msgid "Copy results and close"
msgstr ""
diff --git a/amt/locale/en_US/LC_MESSAGES/messages.mo b/amt/locale/en_US/LC_MESSAGES/messages.mo
index 738f59d7..22706da2 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 e56c0c42..69f89757 100644
--- a/amt/locale/en_US/LC_MESSAGES/messages.po
+++ b/amt/locale/en_US/LC_MESSAGES/messages.po
@@ -47,7 +47,7 @@ msgid "Role"
msgstr ""
#: amt/api/group_by_category.py:15
-#: amt/site/templates/algorithms/details_info.html.j2:96
+#: amt/site/templates/algorithms/details_info.html.j2:101
#: amt/site/templates/algorithms/new.html.j2:41
#: amt/site/templates/parts/algorithm_search.html.j2:48
#: amt/site/templates/parts/filter_list.html.j2:71
@@ -146,7 +146,7 @@ msgstr ""
msgid "Model"
msgstr ""
-#: amt/api/navigation.py:62 amt/site/templates/algorithms/new.html.j2:170
+#: amt/api/navigation.py:62
msgid "Instruments"
msgstr ""
@@ -165,11 +165,7 @@ msgstr ""
msgid "Compliance"
msgstr ""
-#: amt/api/organization_filter_options.py:17
-msgid "All organizations"
-msgstr ""
-
-#: amt/api/organization_filter_options.py:17
+#: amt/api/organization_filter_options.py:16
msgid "My organizations"
msgstr ""
@@ -198,54 +194,54 @@ msgid "Select organization"
msgstr ""
#: amt/api/forms/algorithm.py:42
-#: amt/site/templates/algorithms/details_info.html.j2:74
+#: amt/site/templates/algorithms/details_info.html.j2:79
msgid "Organization"
msgstr ""
-#: amt/api/forms/measure.py:24
+#: amt/api/forms/measure.py:33
msgid "Responsible"
msgstr ""
-#: amt/api/forms/measure.py:32
+#: amt/api/forms/measure.py:41
msgid "Reviewer"
msgstr ""
-#: amt/api/forms/measure.py:40
+#: amt/api/forms/measure.py:49
msgid "Accountable"
msgstr ""
-#: amt/api/forms/measure.py:48
+#: amt/api/forms/measure.py:57
msgid "Status"
msgstr ""
-#: amt/api/forms/measure.py:63
+#: amt/api/forms/measure.py:72
msgid "Information on how this measure is implemented"
msgstr ""
-#: amt/api/forms/measure.py:70
+#: amt/api/forms/measure.py:79
msgid ""
"Select one or more to upload. The files will be saved once you confirm "
"changes by pressing the save button."
msgstr ""
-#: amt/api/forms/measure.py:75
+#: amt/api/forms/measure.py:84
msgid "Add files"
msgstr ""
-#: amt/api/forms/measure.py:76
+#: amt/api/forms/measure.py:85
msgid "No files selected."
msgstr ""
-#: amt/api/forms/measure.py:80
+#: amt/api/forms/measure.py:89
msgid "Add URI"
msgstr ""
-#: amt/api/forms/measure.py:83
+#: amt/api/forms/measure.py:92
msgid "Add links to documents"
msgstr ""
#: amt/api/forms/organization.py:23
-#: amt/site/templates/algorithms/details_info.html.j2:70
+#: amt/site/templates/algorithms/details_info.html.j2:75
#: amt/site/templates/auth/profile.html.j2:34
#: amt/site/templates/organizations/home.html.j2:13
#: amt/site/templates/organizations/parts/members_results.html.j2:118
@@ -382,11 +378,11 @@ msgstr ""
msgid "Download as YAML"
msgstr ""
-#: amt/site/templates/algorithms/details_compliance.html.j2:34
+#: amt/site/templates/algorithms/details_compliance.html.j2:36
msgid "measure executed"
msgstr ""
-#: amt/site/templates/algorithms/details_compliance.html.j2:67
+#: amt/site/templates/algorithms/details_compliance.html.j2:69
#: amt/site/templates/macros/editable.html.j2:28
#: amt/site/templates/macros/editable.html.j2:33
msgid "Edit"
@@ -397,37 +393,37 @@ msgid "Does the algorithm meet the requirements?"
msgstr ""
#: amt/site/templates/algorithms/details_info.html.j2:20
-#: amt/site/templates/algorithms/details_info.html.j2:46
+#: amt/site/templates/algorithms/details_info.html.j2:48
#: amt/site/templates/macros/tasks.html.j2:32
msgid "Done"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:42
+#: amt/site/templates/algorithms/details_info.html.j2:44
msgid "To do"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:44
+#: amt/site/templates/algorithms/details_info.html.j2:46
msgid "In progress"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:60
+#: amt/site/templates/algorithms/details_info.html.j2:65
msgid "Go to all requirements"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:80
+#: amt/site/templates/algorithms/details_info.html.j2:85
#: amt/site/templates/algorithms/details_measure_modal.html.j2:27
msgid "Description"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:86
+#: amt/site/templates/algorithms/details_info.html.j2:91
msgid "Repository"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:92
+#: amt/site/templates/algorithms/details_info.html.j2:97
msgid "Algorithm code"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:102
+#: amt/site/templates/algorithms/details_info.html.j2:107
#: amt/site/templates/organizations/parts/overview_results.html.j2:134
#: amt/site/templates/pages/assessment_card.html.j2:7
#: amt/site/templates/pages/model_card.html.j2:6
@@ -437,11 +433,11 @@ msgstr ""
msgid "Last updated"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:106
+#: amt/site/templates/algorithms/details_info.html.j2:111
msgid "Labels"
msgstr ""
-#: amt/site/templates/algorithms/details_info.html.j2:114
+#: amt/site/templates/algorithms/details_info.html.j2:119
msgid "References"
msgstr ""
@@ -510,21 +506,11 @@ msgstr ""
msgid "Select Option"
msgstr ""
-#: amt/site/templates/algorithms/new.html.j2:172
-msgid ""
-"Overview of instruments for the responsible development, deployment, "
-"assessment, and monitoring of algorithms and AI-systems."
-msgstr ""
-
-#: amt/site/templates/algorithms/new.html.j2:180
-msgid "Choose one or more instruments"
-msgstr ""
-
-#: amt/site/templates/algorithms/new.html.j2:204
+#: amt/site/templates/algorithms/new.html.j2:176
msgid "Create Algorithm"
msgstr ""
-#: amt/site/templates/algorithms/new.html.j2:221
+#: amt/site/templates/algorithms/new.html.j2:193
msgid "Copy results and close"
msgstr ""
diff --git a/amt/locale/nl_NL/LC_MESSAGES/messages.mo b/amt/locale/nl_NL/LC_MESSAGES/messages.mo
index 38eee241..d7cd0f6b 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 a7a6defa..b72544c1 100644
--- a/amt/locale/nl_NL/LC_MESSAGES/messages.po
+++ b/amt/locale/nl_NL/LC_MESSAGES/messages.po
@@ -49,7 +49,7 @@ msgid "Role"
msgstr "Rol"
#: amt/api/group_by_category.py:15
-#: amt/site/templates/algorithms/details_info.html.j2:96
+#: amt/site/templates/algorithms/details_info.html.j2:101
#: amt/site/templates/algorithms/new.html.j2:41
#: amt/site/templates/parts/algorithm_search.html.j2:48
#: amt/site/templates/parts/filter_list.html.j2:71
@@ -148,7 +148,7 @@ msgstr "Data"
msgid "Model"
msgstr "Model"
-#: amt/api/navigation.py:62 amt/site/templates/algorithms/new.html.j2:170
+#: amt/api/navigation.py:62
msgid "Instruments"
msgstr "Instrumenten"
@@ -167,11 +167,7 @@ msgstr "Leden"
msgid "Compliance"
msgstr "Voldoen aan wetten en regels"
-#: amt/api/organization_filter_options.py:17
-msgid "All organizations"
-msgstr "Alle organisaties"
-
-#: amt/api/organization_filter_options.py:17
+#: amt/api/organization_filter_options.py:16
msgid "My organizations"
msgstr "Mijn organisaties"
@@ -200,31 +196,31 @@ msgid "Select organization"
msgstr "Selecteer organisatie"
#: amt/api/forms/algorithm.py:42
-#: amt/site/templates/algorithms/details_info.html.j2:74
+#: amt/site/templates/algorithms/details_info.html.j2:79
msgid "Organization"
msgstr "Organisatie"
-#: amt/api/forms/measure.py:24
+#: amt/api/forms/measure.py:33
msgid "Responsible"
msgstr "Uitvoerende"
-#: amt/api/forms/measure.py:32
+#: amt/api/forms/measure.py:41
msgid "Reviewer"
msgstr "Controlerende"
-#: amt/api/forms/measure.py:40
+#: amt/api/forms/measure.py:49
msgid "Accountable"
msgstr "Verantwoordelijke"
-#: amt/api/forms/measure.py:48
+#: amt/api/forms/measure.py:57
msgid "Status"
msgstr "Status"
-#: amt/api/forms/measure.py:63
+#: amt/api/forms/measure.py:72
msgid "Information on how this measure is implemented"
msgstr "Informatie over hoe deze maatregel is geïmplementeerd"
-#: amt/api/forms/measure.py:70
+#: amt/api/forms/measure.py:79
msgid ""
"Select one or more to upload. The files will be saved once you confirm "
"changes by pressing the save button."
@@ -232,24 +228,24 @@ msgstr ""
"Selecteer één of meer bestanden om te uploaden. De bestanden zullen "
"worden opgeslagen wanneer de Opslaan knop wordt ingedrukt."
-#: amt/api/forms/measure.py:75
+#: amt/api/forms/measure.py:84
msgid "Add files"
msgstr "Bestanden toevoegen"
-#: amt/api/forms/measure.py:76
+#: amt/api/forms/measure.py:85
msgid "No files selected."
msgstr "Geen bestanden geselecteerd."
-#: amt/api/forms/measure.py:80
+#: amt/api/forms/measure.py:89
msgid "Add URI"
msgstr "Voeg URI toe"
-#: amt/api/forms/measure.py:83
+#: amt/api/forms/measure.py:92
msgid "Add links to documents"
msgstr "Voeg link naar bestanden toe"
#: amt/api/forms/organization.py:23
-#: amt/site/templates/algorithms/details_info.html.j2:70
+#: amt/site/templates/algorithms/details_info.html.j2:75
#: amt/site/templates/auth/profile.html.j2:34
#: amt/site/templates/organizations/home.html.j2:13
#: amt/site/templates/organizations/parts/members_results.html.j2:118
@@ -401,11 +397,11 @@ msgstr "Nee"
msgid "Download as YAML"
msgstr "Download naar YAML"
-#: amt/site/templates/algorithms/details_compliance.html.j2:34
+#: amt/site/templates/algorithms/details_compliance.html.j2:36
msgid "measure executed"
msgstr "maatregelen uitgevoerd"
-#: amt/site/templates/algorithms/details_compliance.html.j2:67
+#: amt/site/templates/algorithms/details_compliance.html.j2:69
#: amt/site/templates/macros/editable.html.j2:28
#: amt/site/templates/macros/editable.html.j2:33
msgid "Edit"
@@ -416,37 +412,37 @@ msgid "Does the algorithm meet the requirements?"
msgstr "Voldoet het algoritme aan de vereisten?"
#: amt/site/templates/algorithms/details_info.html.j2:20
-#: amt/site/templates/algorithms/details_info.html.j2:46
+#: amt/site/templates/algorithms/details_info.html.j2:48
#: amt/site/templates/macros/tasks.html.j2:32
msgid "Done"
msgstr "Afgerond"
-#: amt/site/templates/algorithms/details_info.html.j2:42
+#: amt/site/templates/algorithms/details_info.html.j2:44
msgid "To do"
msgstr "Te doen"
-#: amt/site/templates/algorithms/details_info.html.j2:44
+#: amt/site/templates/algorithms/details_info.html.j2:46
msgid "In progress"
msgstr "Onderhanden"
-#: amt/site/templates/algorithms/details_info.html.j2:60
+#: amt/site/templates/algorithms/details_info.html.j2:65
msgid "Go to all requirements"
msgstr "Ga naar alle Vereisten"
-#: amt/site/templates/algorithms/details_info.html.j2:80
+#: amt/site/templates/algorithms/details_info.html.j2:85
#: amt/site/templates/algorithms/details_measure_modal.html.j2:27
msgid "Description"
msgstr "Omschrijving"
-#: amt/site/templates/algorithms/details_info.html.j2:86
+#: amt/site/templates/algorithms/details_info.html.j2:91
msgid "Repository"
msgstr "Repository"
-#: amt/site/templates/algorithms/details_info.html.j2:92
+#: amt/site/templates/algorithms/details_info.html.j2:97
msgid "Algorithm code"
msgstr "Algoritme code"
-#: amt/site/templates/algorithms/details_info.html.j2:102
+#: amt/site/templates/algorithms/details_info.html.j2:107
#: amt/site/templates/organizations/parts/overview_results.html.j2:134
#: amt/site/templates/pages/assessment_card.html.j2:7
#: amt/site/templates/pages/model_card.html.j2:6
@@ -456,11 +452,11 @@ msgstr "Algoritme code"
msgid "Last updated"
msgstr "Laatst bijgewerkt"
-#: amt/site/templates/algorithms/details_info.html.j2:106
+#: amt/site/templates/algorithms/details_info.html.j2:111
msgid "Labels"
msgstr "Labels"
-#: amt/site/templates/algorithms/details_info.html.j2:114
+#: amt/site/templates/algorithms/details_info.html.j2:119
msgid "References"
msgstr "Referenties"
@@ -532,23 +528,11 @@ msgstr "Vind uw AI Act profiel"
msgid "Select Option"
msgstr "Selecteer optie"
-#: amt/site/templates/algorithms/new.html.j2:172
-msgid ""
-"Overview of instruments for the responsible development, deployment, "
-"assessment, and monitoring of algorithms and AI-systems."
-msgstr ""
-"Overzicht van aanbevolen instrument voor het verantwoord ontwikkelen, "
-"gebruiken, beoordelen en monitoren van algoritmes en AI-systemen."
-
-#: amt/site/templates/algorithms/new.html.j2:180
-msgid "Choose one or more instruments"
-msgstr "Kies één of meerdere instrumenten"
-
-#: amt/site/templates/algorithms/new.html.j2:204
+#: amt/site/templates/algorithms/new.html.j2:176
msgid "Create Algorithm"
msgstr "Creëer algoritme"
-#: amt/site/templates/algorithms/new.html.j2:221
+#: amt/site/templates/algorithms/new.html.j2:193
msgid "Copy results and close"
msgstr "Resultaten overnemen en sluiten"
diff --git a/amt/repositories/task_registry.py b/amt/repositories/task_registry.py
index a972a6a3..0ec2f73c 100644
--- a/amt/repositories/task_registry.py
+++ b/amt/repositories/task_registry.py
@@ -67,3 +67,6 @@ async def _fetch_tasks_by_urns(self, task_type: TaskType, urns: Sequence[str]) -
logger.warning("Cannot find all tasks")
return tasks
+
+
+task_registry_repository = TaskRegistryRepository(client=TaskRegistryAPIClient())
diff --git a/amt/services/algorithms.py b/amt/services/algorithms.py
index 7df306c8..a2010efc 100644
--- a/amt/services/algorithms.py
+++ b/amt/services/algorithms.py
@@ -18,7 +18,6 @@
from amt.schema.algorithm import AlgorithmNew
from amt.schema.instrument import InstrumentBase
from amt.schema.system_card import AiActProfile, Owner, SystemCard
-from amt.services.instruments import InstrumentsService, create_instrument_service
from amt.services.task_registry import get_requirements_and_measures
logger = logging.getLogger(__name__)
@@ -30,11 +29,9 @@ class AlgorithmsService:
def __init__(
self,
repository: Annotated[AlgorithmsRepository, Depends(AlgorithmsRepository)],
- instrument_service: Annotated[InstrumentsService, Depends(create_instrument_service)],
organizations_repository: Annotated[OrganizationsRepository, Depends(OrganizationsRepository)],
) -> None:
self.repository = repository
- self.instrument_service = instrument_service
self.organizations_repository = organizations_repository
async def get(self, algorithm_id: int) -> Algorithm:
diff --git a/amt/services/instruments.py b/amt/services/instruments.py
index 4ee19ffc..b90f83b9 100644
--- a/amt/services/instruments.py
+++ b/amt/services/instruments.py
@@ -1,8 +1,8 @@
import logging
from collections.abc import Sequence
-from amt.clients.clients import TaskType, task_registry_api_client
-from amt.repositories.task_registry import TaskRegistryRepository
+from amt.clients.clients import TaskType
+from amt.repositories.task_registry import TaskRegistryRepository, task_registry_repository
from amt.schema.instrument import Instrument
logger = logging.getLogger(__name__)
@@ -23,6 +23,4 @@ async def fetch_instruments(self, urns: str | Sequence[str] | None = None) -> li
return [Instrument(**data) for data in task_data]
-def create_instrument_service() -> InstrumentsService:
- repository = TaskRegistryRepository(task_registry_api_client)
- return InstrumentsService(repository)
+instruments_service = InstrumentsService(task_registry_repository)
diff --git a/amt/services/instruments_and_requirements_state.py b/amt/services/instruments_and_requirements_state.py
index 5d50c99c..e34161e1 100644
--- a/amt/services/instruments_and_requirements_state.py
+++ b/amt/services/instruments_and_requirements_state.py
@@ -8,7 +8,7 @@
from amt.schema.instrument import Instrument, InstrumentTask
from amt.schema.requirement import Requirement
from amt.schema.system_card import SystemCard
-from amt.services.instruments import create_instrument_service
+from amt.services.instruments import instruments_service
logger = logging.getLogger(__name__)
@@ -108,8 +108,9 @@ def get_requirements_state(self, requirements: list[Requirement]) -> list[dict[s
saved_requirements = self.system_card.requirements
for requirement in saved_requirements:
- urn = requirement.urn
- self.requirements_state.append({"name": requirements_mapping[urn], "state": requirement.state})
+ self.requirements_state.append(
+ {"name": requirements_mapping[requirement.urn], "state": requirement.state, "urn": requirement.urn}
+ )
return self.requirements_state
def get_amount_total_requirements(self) -> int:
@@ -134,7 +135,6 @@ async def get_state_per_instrument(self) -> list[dict[str, int]]:
# Otherwise the instrument is completed as there are not any tasks left.
urns = [instrument.urn for instrument in self.system_card.instruments]
- instruments_service = create_instrument_service()
instruments = await instruments_service.fetch_instruments(urns)
# TODO: refactor this data structure in 3 lines below (also change in get_all_next_tasks + check_state.py)
instruments_dict = {}
diff --git a/amt/services/measures.py b/amt/services/measures.py
index a26c0c2f..0f73f3ba 100644
--- a/amt/services/measures.py
+++ b/amt/services/measures.py
@@ -1,8 +1,8 @@
import logging
from collections.abc import Sequence
-from amt.clients.clients import TaskType, task_registry_api_client
-from amt.repositories.task_registry import TaskRegistryRepository
+from amt.clients.clients import TaskType
+from amt.repositories.task_registry import TaskRegistryRepository, task_registry_repository
from amt.schema.measure import Measure
logger = logging.getLogger(__name__)
@@ -23,6 +23,4 @@ async def fetch_measures(self, urns: str | Sequence[str] | None = None) -> list[
return [Measure(**data) for data in task_data]
-def create_measures_service() -> MeasuresService:
- repository = TaskRegistryRepository(task_registry_api_client)
- return MeasuresService(repository)
+measures_service = MeasuresService(task_registry_repository)
diff --git a/amt/services/requirements.py b/amt/services/requirements.py
index 675aa426..7549bc85 100644
--- a/amt/services/requirements.py
+++ b/amt/services/requirements.py
@@ -1,8 +1,8 @@
import logging
from collections.abc import Sequence
-from amt.clients.clients import TaskType, task_registry_api_client
-from amt.repositories.task_registry import TaskRegistryRepository
+from amt.clients.clients import TaskType
+from amt.repositories.task_registry import TaskRegistryRepository, task_registry_repository
from amt.schema.requirement import Requirement
logger = logging.getLogger(__name__)
@@ -23,6 +23,4 @@ async def fetch_requirements(self, urns: str | Sequence[str] | None = None) -> l
return [Requirement(**data) for data in task_data]
-def create_requirements_service() -> RequirementsService:
- repository = TaskRegistryRepository(task_registry_api_client)
- return RequirementsService(repository)
+requirements_service = RequirementsService(task_registry_repository)
diff --git a/amt/services/task_registry.py b/amt/services/task_registry.py
index 71e16ee0..102ba4be 100644
--- a/amt/services/task_registry.py
+++ b/amt/services/task_registry.py
@@ -3,8 +3,8 @@
from amt.schema.measure import MeasureTask
from amt.schema.requirement import Requirement, RequirementTask
from amt.schema.system_card import AiActProfile
-from amt.services.measures import create_measures_service
-from amt.services.requirements import create_requirements_service
+from amt.services.measures import measures_service
+from amt.services.requirements import requirements_service
logger = logging.getLogger(__name__)
@@ -53,8 +53,6 @@ def is_requirement_applicable(requirement: Requirement, ai_act_profile: AiActPro
async def get_requirements_and_measures(
ai_act_profile: AiActProfile,
) -> tuple[list[RequirementTask], list[MeasureTask]]:
- requirements_service = create_requirements_service()
- measure_service = create_measures_service()
all_requirements = await requirements_service.fetch_requirements()
applicable_requirements: list[RequirementTask] = []
@@ -67,7 +65,7 @@ async def get_requirements_and_measures(
for measure_urn in requirement.links:
if measure_urn not in measure_urns:
- measure = await measure_service.fetch_measures(measure_urn)
+ measure = await measures_service.fetch_measures(measure_urn)
applicable_measures.append(
MeasureTask(urn=measure_urn, state="to do", version=measure[0].schema_version)
)
diff --git a/amt/site/static/ts/amt.ts b/amt/site/static/ts/amt.ts
index c6fa62be..3ed28b8b 100644
--- a/amt/site/static/ts/amt.ts
+++ b/amt/site/static/ts/amt.ts
@@ -43,7 +43,7 @@ document.addEventListener("DOMContentLoaded", function () {
new Sortable(column, { //NOSONAR
group: "shared", // set both lists to same group
animation: 150,
- onEnd: function(evt) {
+ onEnd: function (evt) {
if (evt.oldIndex !== evt.newIndex || evt.from !== evt.to) {
const previousSiblingId = evt.item.previousElementSibling
? evt.item.previousElementSibling.getAttribute("data-id")
@@ -427,4 +427,32 @@ export function getFiles(element: HTMLInputElement, target_id: string) {
}
}
+function getAnchor() {
+ const currentUrl = document.URL,
+ urlParts = currentUrl.split("#");
+ return urlParts.length > 1 ? urlParts[1] : null;
+}
+
+function scrollElementIntoViewClickAndBlur(id: string | null) {
+ if (!id) {
+ return;
+ }
+ const element = document.getElementById(id);
+ if (element) {
+ element.scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ inline: "start",
+ });
+ element.click();
+ element.blur();
+ }
+}
+
+export function showRequirementDetails() {
+ document.addEventListener("DOMContentLoaded", function () {
+ scrollElementIntoViewClickAndBlur(getAnchor());
+ });
+}
+
// for debugging htmx use -> htmx.logAll();
diff --git a/amt/site/templates/algorithms/details_compliance.html.j2 b/amt/site/templates/algorithms/details_compliance.html.j2
index 6c869028..0ff30eb2 100644
--- a/amt/site/templates/algorithms/details_compliance.html.j2
+++ b/amt/site/templates/algorithms/details_compliance.html.j2
@@ -11,7 +11,9 @@
{% for (requirement, completed_measures_count, measures) in requirements_and_measures %}
+