diff --git a/backend/capellacollab/core/database/__init__.py b/backend/capellacollab/core/database/__init__.py index 12fdc4be6d..294a7b73c9 100644 --- a/backend/capellacollab/core/database/__init__.py +++ b/backend/capellacollab/core/database/__init__.py @@ -21,6 +21,8 @@ class Base(orm.DeclarativeBase): type_annotation_map = { dict[str, str]: postgresql.JSONB, dict[str, t.Any]: postgresql.JSONB, + dict[t.Any, t.Any]: postgresql.JSONB, + dict[str, bool]: postgresql.JSONB, } diff --git a/backend/capellacollab/core/database/migration.py b/backend/capellacollab/core/database/migration.py index 66ddbc1491..5c6bcd8312 100644 --- a/backend/capellacollab/core/database/migration.py +++ b/backend/capellacollab/core/database/migration.py @@ -36,8 +36,6 @@ ) from capellacollab.tools import crud as tools_crud from capellacollab.tools import models as tools_models -from capellacollab.tools.integrations import crud as integrations_crud -from capellacollab.tools.integrations import models as integrations_models from capellacollab.users import crud as users_crud from capellacollab.users import models as users_models @@ -151,14 +149,9 @@ def create_tools(db): jupyter = tools_models.DatabaseTool( name="Jupyter", - docker_image_template=f"{registry}/jupyter-notebook:$version", + integrations=tools_models.ToolIntegrations(jupyter=True), ) tools_crud.create_tool(db, jupyter) - integrations_crud.update_integrations( - db, - jupyter.integrations, - integrations_models.PatchToolIntegrations(jupyter=True), - ) default_version = tools_crud.create_version(db, capella.id, "6.0.0", True) tools_crud.create_version(db, capella.id, "5.2.0") diff --git a/backend/capellacollab/core/database/models.py b/backend/capellacollab/core/database/models.py index 84bd3650c3..6ad2c6a72a 100644 --- a/backend/capellacollab/core/database/models.py +++ b/backend/capellacollab/core/database/models.py @@ -19,7 +19,6 @@ import capellacollab.settings.integrations.purevariants.models import capellacollab.settings.modelsources.git.models import capellacollab.settings.modelsources.t4c.models -import capellacollab.tools.integrations.models import capellacollab.tools.models import capellacollab.users.models import capellacollab.users.tokens.models diff --git a/backend/capellacollab/projects/toolmodels/restrictions/routes.py b/backend/capellacollab/projects/toolmodels/restrictions/routes.py index 9819b93274..60984dba4f 100644 --- a/backend/capellacollab/projects/toolmodels/restrictions/routes.py +++ b/backend/capellacollab/projects/toolmodels/restrictions/routes.py @@ -46,7 +46,10 @@ def update_restrictions( ), db: orm.Session = fastapi.Depends(database.get_db), ) -> models.DatabaseToolModelRestrictions: - if body.allow_pure_variants and not model.tool.integrations.pure_variants: + if ( + body.allow_pure_variants + and not model.tool.integrations["pure_variants"] + ): raise fastapi.HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail={ diff --git a/backend/capellacollab/projects/toolmodels/routes.py b/backend/capellacollab/projects/toolmodels/routes.py index 9c5942c77a..2e60efa37b 100644 --- a/backend/capellacollab/projects/toolmodels/routes.py +++ b/backend/capellacollab/projects/toolmodels/routes.py @@ -86,7 +86,7 @@ def create_new_tool_model( ) configuration = {} - if tool.integrations.jupyter: + if tool.integrations["jupyter"]: configuration["workspace"] = str(uuid.uuid4()) try: @@ -102,7 +102,7 @@ def create_new_tool_model( }, ) - if tool.integrations.jupyter: + if tool.integrations["jupyter"]: workspace.create_shared_workspace( configuration["workspace"], project, model, "2Gi" ) @@ -230,7 +230,7 @@ def delete_tool_model( ) if ( - model.tool.integrations.jupyter + model.tool.integrations["jupyter"] and model.configuration and "workspace" in model.configuration ): diff --git a/backend/capellacollab/settings/modelsources/t4c/repositories/models.py b/backend/capellacollab/settings/modelsources/t4c/repositories/models.py index 2786d71f15..061355f083 100644 --- a/backend/capellacollab/settings/modelsources/t4c/repositories/models.py +++ b/backend/capellacollab/settings/modelsources/t4c/repositories/models.py @@ -45,7 +45,7 @@ class DatabaseT4CRepository(database.Base): class CreateT4CRepository(pydantic.BaseModel): name: str = pydantic.Field( - pattern="^[-a-zA-Z0-9_]+$", examples=["testrepo"] + pattern=r"^[-a-zA-Z0-9_]+$", examples=["testrepo"] ) diff --git a/backend/capellacollab/tools/crud.py b/backend/capellacollab/tools/crud.py index 9692e9b8ec..9fd0c6189e 100644 --- a/backend/capellacollab/tools/crud.py +++ b/backend/capellacollab/tools/crud.py @@ -7,7 +7,7 @@ from sqlalchemy import exc, orm from capellacollab.core import database -from capellacollab.tools.integrations import models as integrations_models +from capellacollab.tools import models as tools_models from . import exceptions, models @@ -37,7 +37,7 @@ def get_tool_by_name( def create_tool( db: orm.Session, tool: models.DatabaseTool ) -> models.DatabaseTool: - tool.integrations = integrations_models.DatabaseToolIntegrations( + tool.integrations = tools_models.ToolIntegrations( pure_variants=False, t4c=False, jupyter=False ) db.add(tool) @@ -61,21 +61,6 @@ def update_tool_name( return tool -def update_tool_dockerimages( - db: orm.Session, - tool: models.DatabaseTool, - patch_tool: models.PatchToolDockerimage, -) -> models.DatabaseTool: - if patch_tool.persistent: - tool.docker_image_template = patch_tool.persistent - if patch_tool.readonly: - tool.readonly_docker_image_template = patch_tool.readonly - if patch_tool.backup: - tool.docker_image_backup_template = patch_tool.backup - db.commit() - return tool - - def delete_tool(db: orm.Session, tool: models.DatabaseTool) -> None: db.delete(tool) db.commit() @@ -261,7 +246,7 @@ def get_backup_image_for_tool_version(db: orm.Session, version_id: int) -> str: if not (version := get_version_by_id(db, version_id)): raise exceptions.ToolVersionNotFoundError(version_id) - backup_image_template = version.tool.docker_image_backup_template + backup_image_template = version.config[""] if not backup_image_template: raise exceptions.ToolImageNotFoundError( diff --git a/backend/capellacollab/tools/integrations/__init__.py b/backend/capellacollab/tools/integrations/__init__.py deleted file mode 100644 index 04412280d8..0000000000 --- a/backend/capellacollab/tools/integrations/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors -# SPDX-License-Identifier: Apache-2.0 diff --git a/backend/capellacollab/tools/integrations/crud.py b/backend/capellacollab/tools/integrations/crud.py deleted file mode 100644 index c8ee370877..0000000000 --- a/backend/capellacollab/tools/integrations/crud.py +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors -# SPDX-License-Identifier: Apache-2.0 - -from sqlalchemy import orm - -from capellacollab.core import database - -from . import models - - -def update_integrations( - db: orm.Session, - integrations: models.DatabaseToolIntegrations, - patch_integrations: models.PatchToolIntegrations, -) -> models.DatabaseToolIntegrations: - database.patch_database_with_pydantic_object( - integrations, patch_integrations - ) - - db.commit() - return integrations diff --git a/backend/capellacollab/tools/integrations/models.py b/backend/capellacollab/tools/integrations/models.py deleted file mode 100644 index 9615d5663b..0000000000 --- a/backend/capellacollab/tools/integrations/models.py +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors -# SPDX-License-Identifier: Apache-2.0 - -from __future__ import annotations - -import typing as t - -import pydantic -import sqlalchemy as sa -from sqlalchemy import orm - -from capellacollab.core import database - -if t.TYPE_CHECKING: - from capellacollab.tools.models import DatabaseTool - - -class ToolIntegrations(pydantic.BaseModel): - model_config = pydantic.ConfigDict(from_attributes=True) - - t4c: bool - pure_variants: bool - jupyter: bool - - -class PatchToolIntegrations(pydantic.BaseModel): - t4c: bool | None = None - pure_variants: bool | None = None - jupyter: bool | None = None - - -class DatabaseToolIntegrations(database.Base): - __tablename__ = "tool_integrations" - - id: orm.Mapped[int] = orm.mapped_column(primary_key=True) - - tool_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("tools.id")) - tool: orm.Mapped[DatabaseTool] = orm.relationship( - back_populates="integrations" - ) - - t4c: orm.Mapped[bool] = orm.mapped_column(default=False) - pure_variants: orm.Mapped[bool] = orm.mapped_column(default=False) - jupyter: orm.Mapped[bool] = orm.mapped_column(default=False) diff --git a/backend/capellacollab/tools/integrations/routes.py b/backend/capellacollab/tools/integrations/routes.py deleted file mode 100644 index a5953e333e..0000000000 --- a/backend/capellacollab/tools/integrations/routes.py +++ /dev/null @@ -1,34 +0,0 @@ -# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors -# SPDX-License-Identifier: Apache-2.0 - -import fastapi -from sqlalchemy import orm - -from capellacollab.core import database -from capellacollab.core.authentication import injectables as auth_injectables -from capellacollab.users import models as users_models - -from .. import injectables as tools_injectables -from .. import models as tools_models -from . import crud, models - -router = fastapi.APIRouter( - dependencies=[ - fastapi.Depends( - auth_injectables.RoleVerification( - required_role=users_models.Role.ADMIN - ) - ) - ] -) - - -@router.put("", response_model=models.ToolIntegrations) -def update_integrations( - body: models.PatchToolIntegrations, - tool: tools_models.DatabaseTool = fastapi.Depends( - tools_injectables.get_existing_tool - ), - db: orm.Session = fastapi.Depends(database.get_db), -) -> models.DatabaseToolIntegrations: - return crud.update_integrations(db, tool.integrations, body) diff --git a/backend/capellacollab/tools/models.py b/backend/capellacollab/tools/models.py index ec682ad095..7e583e65f6 100644 --- a/backend/capellacollab/tools/models.py +++ b/backend/capellacollab/tools/models.py @@ -9,12 +9,19 @@ import pydantic import sqlalchemy as sa from sqlalchemy import orm +from sqlalchemy.dialects import postgresql from capellacollab.core import database -from capellacollab.tools.integrations import models as integrations_models -if t.TYPE_CHECKING: - from .integrations.models import DatabaseToolIntegrations +DOCKER_IMAGE_PATTERN = r"^[a-zA-Z0-9][a-zA-Z0-9_\-/.:$]*$" + + +class ToolIntegrations(pydantic.BaseModel): + model_config = pydantic.ConfigDict(from_attributes=True) + + t4c: bool + pure_variants: bool + jupyter: bool class DatabaseTool(database.Base): @@ -23,9 +30,6 @@ class DatabaseTool(database.Base): id: orm.Mapped[int] = orm.mapped_column(primary_key=True) name: orm.Mapped[str] - docker_image_template: orm.Mapped[str] - docker_image_backup_template: orm.Mapped[str | None] - readonly_docker_image_template: orm.Mapped[str | None] versions: orm.Mapped[list[DatabaseVersion]] = orm.relationship( back_populates="tool" @@ -34,8 +38,8 @@ class DatabaseTool(database.Base): back_populates="tool" ) - integrations: orm.Mapped[DatabaseToolIntegrations] = orm.relationship( - back_populates="tool", uselist=False + integrations: orm.Mapped[ToolIntegrations] = orm.mapped_column( + postgresql.JSONB ) @@ -45,9 +49,7 @@ class DatabaseVersion(database.Base): id: orm.Mapped[int] = orm.mapped_column(primary_key=True) - name: orm.Mapped[str] - is_recommended: orm.Mapped[bool] - is_deprecated: orm.Mapped[bool] + config: dict[t.Any, t.Any] # TODO: Add type annotation tool_id: orm.Mapped[int | None] = orm.mapped_column( sa.ForeignKey("tools.id") @@ -75,27 +77,31 @@ class ToolBase(pydantic.BaseModel): id: int name: str - integrations: integrations_models.ToolIntegrations + integrations: ToolIntegrations -class ToolDockerimage(pydantic.BaseModel): +class ToolConfiguration(pydantic.BaseModel): model_config = pydantic.ConfigDict(from_attributes=True) - persistent: str = pydantic.Field( - ..., validation_alias="docker_image_template" - ) - readonly: str | None = pydantic.Field( - None, validation_alias="readonly_docker_image_template" - ) - backup: str | None = pydantic.Field( - None, validation_alias="docker_image_backup_template" - ) + name: str + + versions: list[ToolVersionBase] + natures: list[ToolNatureBase] + integrations: ToolIntegrations -class PatchToolDockerimage(pydantic.BaseModel): - persistent: str | None = None - readonly: str | None = None - backup: str | None = None + sessions: None + backups: None + + +class ToolBackupConfiguration(pydantic.BaseModel): + image: str = pydantic.Field( + pattern=DOCKER_IMAGE_PATTERN, + examples=[ + "docker.io/hello-world:latest", + "ghcr.io/dsd-dbs/capella-dockerimages/capella/remote:main", + ], + ) class CreateToolVersion(pydantic.BaseModel): diff --git a/backend/capellacollab/tools/routes.py b/backend/capellacollab/tools/routes.py index 0b89b32072..231f6543ac 100644 --- a/backend/capellacollab/tools/routes.py +++ b/backend/capellacollab/tools/routes.py @@ -12,9 +12,6 @@ from capellacollab.core import database from capellacollab.core import exceptions as core_exceptions from capellacollab.core.authentication import injectables as auth_injectables -from capellacollab.tools.integrations import ( - routes as tools_integrations_routes, -) from capellacollab.users import models as users_models from . import crud, injectables, models @@ -222,47 +219,6 @@ def delete_tool_nature( crud.delete_nature(db, nature) -@router.get( - "/{tool_id}/dockerimages", - response_model=models.ToolDockerimage, - dependencies=[ - fastapi.Depends( - auth_injectables.RoleVerification( - required_role=users_models.Role.ADMIN - ) - ) - ], -) -def get_dockerimages( - tool: models.DatabaseTool = fastapi.Depends(injectables.get_existing_tool), -) -> models.DatabaseTool: - return tool - - -@router.put( - "/{tool_id}/dockerimages", - response_model=models.ToolDockerimage, - dependencies=[ - fastapi.Depends( - auth_injectables.RoleVerification( - required_role=users_models.Role.ADMIN - ) - ) - ], -) -def update_dockerimages( - body: models.PatchToolDockerimage, - tool: models.DatabaseTool = fastapi.Depends(injectables.get_existing_tool), - db: orm.Session = fastapi.Depends(database.get_db), -) -> models.DatabaseTool: - return crud.update_tool_dockerimages(db, tool, body) - - -router.include_router( - tools_integrations_routes.router, prefix="/{tool_id}/integrations" -) - - def raise_when_tool_dependency_exist( db: orm.Session, tool: models.DatabaseTool ) -> None: diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 31aef06f16..950e46ad0d 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -51,6 +51,7 @@ import { HighlightPipeTransform, ModelDiagramCodeBlockComponent, } from 'src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component'; +import { CreateToolComponent } from 'src/app/settings/core/tools-settings/create-tool/create-tool.component'; import { BasicAuthTokenComponent } from 'src/app/users/basic-auth-token/basic-auth-token.component'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -175,6 +176,7 @@ import { UsersProfileComponent } from './users/users-profile/users-profile.compo CreateReadonlySessionComponent, CreateReadonlySessionDialogComponent, CreateT4cModelNewRepositoryComponent, + CreateToolComponent, DeleteGitSettingsDialogComponent, DeleteSessionDialogComponent, DisplayValueComponent, diff --git a/frontend/src/app/settings/core/configuration-settings/configuration-settings.component.ts b/frontend/src/app/settings/core/configuration-settings/configuration-settings.component.ts index 4d35987e1a..18e30f7434 100644 --- a/frontend/src/app/settings/core/configuration-settings/configuration-settings.component.ts +++ b/frontend/src/app/settings/core/configuration-settings/configuration-settings.component.ts @@ -35,7 +35,6 @@ export class ConfigurationSettingsComponent implements OnInit { }); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any submitValue(value: any) { this.configurationSettingsService .putConfigurationSettings('global', value) diff --git a/frontend/src/app/settings/core/tools-settings/create-tool/create-tool.component.html b/frontend/src/app/settings/core/tools-settings/create-tool/create-tool.component.html new file mode 100644 index 0000000000..3e38063829 --- /dev/null +++ b/frontend/src/app/settings/core/tools-settings/create-tool/create-tool.component.html @@ -0,0 +1,6 @@ + + + diff --git a/frontend/src/app/settings/core/tools-settings/create-tool/create-tool.component.ts b/frontend/src/app/settings/core/tools-settings/create-tool/create-tool.component.ts new file mode 100644 index 0000000000..8531238f69 --- /dev/null +++ b/frontend/src/app/settings/core/tools-settings/create-tool/create-tool.component.ts @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-create-tool', + templateUrl: './create-tool.component.html', +}) +export class CreateToolComponent {} diff --git a/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.html b/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.html index fce2d0f17e..37f02e06c2 100644 --- a/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.html +++ b/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.html @@ -4,126 +4,10 @@ -->
-
- -

Metadata

-
- - Name - - A name for the tool is required! - -
-
- Here you can specify the used Docker images:

- - Persistent workspaces - - You have to provide a persistent docker image! - The maximal allowed length is 4096! - The input is not a valid docker image name! - - - Read-only workspaces (optional) - - The maximal allowed length is 4096! - The input is not a valid docker image name! - - - Backup image (optional) - - The maximal allowed length is 4096! - The input is not a valid docker image name! - -
-
-
- - -
-
- - -
-
- -
-
-
- -
- - + +

Metadata

+ +
+ +
diff --git a/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.ts b/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.ts index d61c694f44..d8b4323f4e 100644 --- a/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.ts +++ b/frontend/src/app/settings/core/tools-settings/tool-details/tool-details.component.ts @@ -3,21 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Component } from '@angular/core'; -import { - AbstractControl, - FormControl, - FormGroup, - ValidationErrors, - ValidatorFn, - Validators, -} from '@angular/forms'; +import { Component, ViewChild } from '@angular/core'; + import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; -import { combineLatest, filter, map, mergeMap, of, switchMap, tap } from 'rxjs'; +import { filter, map, mergeMap, tap } from 'rxjs'; import { BreadcrumbsService } from 'src/app/general/breadcrumbs/breadcrumbs.service'; +import { EditorComponent } from 'src/app/helpers/editor/editor.component'; import { ToastService } from 'src/app/helpers/toast/toast.service'; -import { Tool, ToolDockerimages, ToolService } from '../tool.service'; +import { Tool, ToolService } from '../tool.service'; import { ToolDeletionDialogComponent } from './tool-deletion-dialog/tool-deletion-dialog.component'; @Component({ @@ -26,30 +20,9 @@ import { ToolDeletionDialogComponent } from './tool-deletion-dialog/tool-deletio styleUrls: ['./tool-details.component.css'], }) export class ToolDetailsComponent { - editing = false; - existing = false; + @ViewChild(EditorComponent) editor: EditorComponent | undefined; selectedTool?: Tool; - dockerimages?: ToolDockerimages; - - public form = new FormGroup({ - name: new FormControl('', Validators.required), - dockerimages: new FormGroup({ - persistent: new FormControl('', [ - Validators.required, - Validators.maxLength(4096), - this.validDockerImageNameValidator(), - ]), - readonly: new FormControl('', [ - Validators.maxLength(4096), - this.validDockerImageNameValidator(), - ]), - backup: new FormControl('', [ - Validators.maxLength(4096), - this.validDockerImageNameValidator(), - ]), - }), - }); constructor( private route: ActivatedRoute, @@ -65,143 +38,31 @@ export class ToolDetailsComponent { .pipe( map((params) => params.toolID), filter((toolID) => toolID !== undefined), - mergeMap((toolID) => { - return combineLatest([ - of(toolID), - this.toolService._tools, - this.toolService.getDockerimagesForTool(toolID), - ]); - }), - tap(([_toolID, _tools, dockerimages]) => { - this.dockerimages = dockerimages; - }), - map(([toolID, tools, _dockerimages]) => { - return tools?.find((tool: Tool) => { - return tool.id == toolID; - }); - }), + mergeMap((toolID) => this.toolService.getToolByID(toolID)), ) .subscribe({ next: (tool) => { this.breadcrumbsService.updatePlaceholder({ tool }); - this.existing = true; this.selectedTool = tool; - this.updateForm(); + this.editor!.value = this.selectedTool; }, }); } - enableEditing(): void { - this.editing = true; - this.form.enable(); - } - - cancelEditing(): void { - this.editing = false; - this.form.disable(); - } - - updateForm(): void { - this.form.patchValue({ - name: this.selectedTool?.name, - dockerimages: this.dockerimages, - }); - this.cancelEditing(); - } - - validDockerImageNameValidator(): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - /* - Name components may contain lowercase letters, digits and separators. - A separator is defined as a period, one or two underscores, or one or more dashes. - A name component may not start or end with a separator. - - https://docs.docker.com/engine/reference/commandline/tag/#extended-description - - In addition, we allow $ (to use the $version syntax) and : for the tag. - */ - if ( - control.value && - !/^[a-zA-Z0-9][a-zA-Z0-9_\-/\.:\$]*$/.test(control.value) - ) { - return { validDockerImageNameInvalid: true }; - } - return {}; - }; - } - - create(): void { - if (this.form.valid) { - const name = this.form.controls.name.value!; - - this.toolService - .createTool(name) - .pipe( - tap((tool) => { - this.toastService.showSuccess( - 'Tool created', - `The tool with name ${tool.name} was created.`, - ); - - this.selectedTool = tool; - }), - switchMap((tool) => { - return this.toolService.updateDockerimagesForTool( - tool.id, - this.form.controls.dockerimages.value as ToolDockerimages, - ); - }), - tap((_) => { - this.toastService.showSuccess( - 'Docker images updated', - `The Docker images for the tool '${name}' were updated.`, - ); - }), - ) - .subscribe(() => { - this.router.navigate(['../..', 'tool', this.selectedTool?.id], { - relativeTo: this.route, - }); - }); - } - } - - update(): void { - if (this.form.valid) { - this.toolService - .updateTool(this.selectedTool!.id, this.form.controls.name.value!) - .pipe( - tap((tool) => { - this.toastService.showSuccess( - 'Tool updated', - `The tool name changed from '${this.selectedTool?.name}' to '${tool.name}'.`, - ); - }), - ) - .subscribe((tool) => { - this.selectedTool = tool; - }); - - this.toolService - .updateDockerimagesForTool( - this.selectedTool!.id, - this.form.controls.dockerimages.value as ToolDockerimages, - ) - .pipe( - tap((dockerimages) => { - this.dockerimages = dockerimages; - }), - ) - .subscribe((_) => { + submitValue(value: any): void { + this.toolService + .updateTool(this.selectedTool!.id, value) + .pipe( + tap((tool) => { this.toastService.showSuccess( - 'Docker images for Tool updated', - `The Docker images for the tool with id ${ - this.selectedTool!.id - } were updated.`, + 'Tool updated', + `The configuration of the tool '${tool.name}' has been updated successfully.`, ); - this.cancelEditing(); - }); - } + }), + ) + .subscribe((tool) => { + this.selectedTool = tool; + }); } deleteTool(): void { @@ -221,12 +82,4 @@ export class ToolDetailsComponent { ); }); } - - submit(): void { - if (this.existing) { - this.update(); - } else { - this.create(); - } - } } diff --git a/frontend/src/app/settings/core/tools-settings/tool-details/tool-version/tool-version.component.html b/frontend/src/app/settings/core/tools-settings/tool-details/tool-version/tool-version.component.html index ceb1c1d9f4..d13265509a 100644 --- a/frontend/src/app/settings/core/tools-settings/tool-details/tool-version/tool-version.component.html +++ b/frontend/src/app/settings/core/tools-settings/tool-details/tool-version/tool-version.component.html @@ -6,16 +6,32 @@

Tool Versions

+ + @for (version of toolVersions; track version.id) { + + + + } + + + add_box + Add version + + + Add version add_box + + +
Version name - Please enter a version name - Version name is already used
diff --git a/frontend/src/app/settings/core/tools-settings/tool.service.ts b/frontend/src/app/settings/core/tools-settings/tool.service.ts index f43e2f8bfe..c805f8f0df 100644 --- a/frontend/src/app/settings/core/tools-settings/tool.service.ts +++ b/frontend/src/app/settings/core/tools-settings/tool.service.ts @@ -78,6 +78,10 @@ export class ToolService { ); } + getToolByID(id: string): Observable { + return this.http.get(`${this.baseURL}/${id}`); + } + createTool(name: string): Observable { return this.http.post(this.baseURL, { name }); } @@ -144,22 +148,6 @@ export class ToolService { ); } - getDockerimagesForTool(toolId: number): Observable { - return this.http.get( - `${this.baseURL}/${toolId}/dockerimages`, - ); - } - - updateDockerimagesForTool( - toolId: number, - dockerimages: ToolDockerimages, - ): Observable { - return this.http.put( - `${this.baseURL}/${toolId}/dockerimages`, - dockerimages, - ); - } - patchToolIntegrations( toolId: number, toolIntegrations: ToolIntegrations,