From 4b70bc8fcf786dae953b5f53dfc4b88b78ef0aea Mon Sep 17 00:00:00 2001 From: Tobias Messner Date: Wed, 20 Nov 2024 15:12:34 +0100 Subject: [PATCH] feat: Unify various API endpoints related to config More details in the linked issue. Closes #1960 --- backend/capellacollab/feedback/routes.py | 18 +- backend/capellacollab/metadata/routes.py | 45 ----- backend/capellacollab/navbar/routes.py | 23 --- backend/capellacollab/routes.py | 8 +- .../settings/configuration/models.py | 20 +++ .../settings/configuration/routes.py | 39 ++++- .../settings/configuration/util.py | 34 ++++ backend/capellacollab/users/routes.py | 13 -- .../settings/test_global_configuration.py | 8 +- backend/tests/test_feedback.py | 8 +- .../app/general/metadata/metadata.service.ts | 24 +-- .../app/general/nav-bar/nav-bar.service.ts | 32 +--- .../src/app/openapi/.openapi-generator/FILES | 3 +- frontend/src/app/openapi/api/api.ts | 6 +- .../app/openapi/api/configuration.service.ts | 69 ++++++++ .../src/app/openapi/api/feedback.service.ts | 62 ------- .../src/app/openapi/api/metadata.service.ts | 155 ------------------ .../src/app/openapi/api/navbar.service.ts | 155 ------------------ frontend/src/app/openapi/api/users.service.ts | 69 -------- frontend/src/app/openapi/model/models.ts | 1 + .../src/app/openapi/model/unified-config.ts | 24 +++ .../model-diagram-code-block.component.ts | 1 - .../unified-config-wrapper.service.ts | 31 ++++ .../app/sessions/feedback/feedback.service.ts | 58 +++---- .../configuration-settings.component.ts | 12 +- .../users-profile.component.html | 5 +- .../users-profile/users-profile.component.ts | 19 +-- 27 files changed, 274 insertions(+), 668 deletions(-) delete mode 100644 backend/capellacollab/metadata/routes.py delete mode 100644 backend/capellacollab/navbar/routes.py create mode 100644 backend/capellacollab/settings/configuration/util.py delete mode 100644 frontend/src/app/openapi/api/metadata.service.ts delete mode 100644 frontend/src/app/openapi/api/navbar.service.ts create mode 100644 frontend/src/app/openapi/model/unified-config.ts create mode 100644 frontend/src/app/services/unified-config-wrapper/unified-config-wrapper.service.ts diff --git a/backend/capellacollab/feedback/routes.py b/backend/capellacollab/feedback/routes.py index c1299f00cc..b245c48b8f 100644 --- a/backend/capellacollab/feedback/routes.py +++ b/backend/capellacollab/feedback/routes.py @@ -9,12 +9,9 @@ import fastapi from sqlalchemy import orm -from capellacollab.config import config from capellacollab.core import database from capellacollab.core import logging as log from capellacollab.core.authentication import injectables as auth_injectables -from capellacollab.settings.configuration import core as config_core -from capellacollab.settings.configuration import models as config_models from capellacollab.users import injectables as user_injectables from capellacollab.users import models as users_models @@ -23,21 +20,8 @@ router = fastapi.APIRouter() -@router.get( - "/configurations/feedback", - response_model=config_models.FeedbackConfiguration, -) -def get_feedback_configuration( - db: orm.Session = fastapi.Depends(database.get_db), -): - feedback = config_core.get_global_configuration(db).feedback - if not (config.smtp and config.smtp.enabled): - util.disable_feedback(feedback) - return feedback - - @router.post( - "/feedback", + "", status_code=204, dependencies=[ fastapi.Depends( diff --git a/backend/capellacollab/metadata/routes.py b/backend/capellacollab/metadata/routes.py deleted file mode 100644 index d079708618..0000000000 --- a/backend/capellacollab/metadata/routes.py +++ /dev/null @@ -1,45 +0,0 @@ -# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors -# SPDX-License-Identifier: Apache-2.0 - -import fastapi -from sqlalchemy import orm - -import capellacollab -from capellacollab.config import config -from capellacollab.core import database -from capellacollab.core import pydantic as core_pydantic -from capellacollab.settings.configuration import core as config_core - - -class Metadata(core_pydantic.BaseModel): - version: str - privacy_policy_url: str | None - imprint_url: str | None - provider: str | None - authentication_provider: str | None - environment: str | None - - host: str | None - port: str | None - protocol: str | None - - -router = fastapi.APIRouter() - - -@router.get( - "/metadata", - response_model=Metadata, -) -def get_metadata(db: orm.Session = fastapi.Depends(database.get_db)): - cfg = config_core.get_global_configuration(db) - - return Metadata.model_validate( - cfg.metadata.model_dump() - | { - "version": capellacollab.__version__, - "host": config.general.host, - "port": str(config.general.port), - "protocol": config.general.scheme, - } - ) diff --git a/backend/capellacollab/navbar/routes.py b/backend/capellacollab/navbar/routes.py deleted file mode 100644 index 267ba4b5a9..0000000000 --- a/backend/capellacollab/navbar/routes.py +++ /dev/null @@ -1,23 +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.settings.configuration import core as config_core -from capellacollab.settings.configuration import models as config_models - -router = fastapi.APIRouter() - - -@router.get( - "/navbar", - response_model=config_models.NavbarConfiguration, -) -def get_navbar(db: orm.Session = fastapi.Depends(database.get_db)): - cfg = config_core.get_global_configuration(db) - - return config_models.NavbarConfiguration.model_validate( - cfg.navbar.model_dump() - ) diff --git a/backend/capellacollab/routes.py b/backend/capellacollab/routes.py index 5c3d6fdce3..3a30672f9f 100644 --- a/backend/capellacollab/routes.py +++ b/backend/capellacollab/routes.py @@ -11,8 +11,6 @@ from capellacollab.events import routes as events_router from capellacollab.feedback import routes as feedback_routes from capellacollab.health import routes as health_routes -from capellacollab.metadata import routes as core_metadata -from capellacollab.navbar import routes as navbar_routes from capellacollab.notices import routes as notices_routes from capellacollab.projects import routes as projects_routes from capellacollab.sessions import routes as sessions_routes @@ -30,9 +28,9 @@ responses=auth_responses.api_exceptions(include_authentication=True), tags=["Health"], ) -router.include_router(core_metadata.router, tags=["Metadata"]) -router.include_router(navbar_routes.router, tags=["Navbar"]) -router.include_router(feedback_routes.router, tags=["Feedback"]) +router.include_router( + feedback_routes.router, prefix="/feedback", tags=["Feedback"] +) router.include_router( sessions_routes.router, prefix="/sessions", diff --git a/backend/capellacollab/settings/configuration/models.py b/backend/capellacollab/settings/configuration/models.py index c1cbc1d03f..177d49307c 100644 --- a/backend/capellacollab/settings/configuration/models.py +++ b/backend/capellacollab/settings/configuration/models.py @@ -244,3 +244,23 @@ class GlobalConfiguration(ConfigurationBase): NAME_TO_MODEL_TYPE_MAPPING: dict[str, t.Type[ConfigurationBase]] = { model()._name: model for model in ConfigurationBase.__subclasses__() } + + +class Metadata(core_pydantic.BaseModel): + version: str + privacy_policy_url: str | None + imprint_url: str | None + provider: str | None + authentication_provider: str | None + environment: str | None + + host: str | None + port: str | None + protocol: str | None + + +class UnifiedConfig(core_pydantic.BaseModel): + metadata: Metadata + feedback: FeedbackConfiguration + navbar: NavbarConfiguration + beta: BetaConfiguration diff --git a/backend/capellacollab/settings/configuration/routes.py b/backend/capellacollab/settings/configuration/routes.py index 7690fc19a2..c64b4f8317 100644 --- a/backend/capellacollab/settings/configuration/routes.py +++ b/backend/capellacollab/settings/configuration/routes.py @@ -12,25 +12,41 @@ from capellacollab.users import crud as users_crud from capellacollab.users import models as users_models -from . import core, crud, models +from . import core, crud, models, util router = fastapi.APIRouter( - dependencies=[ - fastapi.Depends( - auth_injectables.RoleVerification( - required_role=users_models.Role.ADMIN - ) - ) - ], tags=["Configuration"], ) schema_router = fastapi.APIRouter(dependencies=[], tags=["Configuration"]) +@router.get( + "/unified", +) +def get_unified_config( + db: orm.Session = fastapi.Depends(database.get_db), +) -> models.UnifiedConfig: + cfg = core.get_global_configuration(db) + + return models.UnifiedConfig( + metadata=util.get_metadata(cfg), + feedback=util.get_feedback(cfg), + beta=cfg.beta, + navbar=cfg.navbar, + ) + + @router.get( f"/{models.GlobalConfiguration._name}", response_model=models.GlobalConfiguration, + dependencies=[ + fastapi.Depends( + auth_injectables.RoleVerification( + required_role=users_models.Role.ADMIN + ) + ) + ], ) async def get_configuration( db: orm.Session = fastapi.Depends(database.get_db), @@ -41,6 +57,13 @@ async def get_configuration( @router.put( f"/{models.GlobalConfiguration._name}", response_model=models.GlobalConfiguration, + dependencies=[ + fastapi.Depends( + auth_injectables.RoleVerification( + required_role=users_models.Role.ADMIN + ) + ) + ], ) async def update_configuration( body: models.GlobalConfiguration, diff --git a/backend/capellacollab/settings/configuration/util.py b/backend/capellacollab/settings/configuration/util.py new file mode 100644 index 0000000000..b9ddfe87ca --- /dev/null +++ b/backend/capellacollab/settings/configuration/util.py @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors +# SPDX-License-Identifier: Apache-2.0 + +import capellacollab +from capellacollab.config import config +from capellacollab.settings.configuration import models + + +def get_metadata( + global_config: models.GlobalConfiguration, +) -> models.Metadata: + return models.Metadata.model_validate( + global_config.metadata.model_dump() + | { + "version": capellacollab.__version__, + "host": config.general.host, + "port": str(config.general.port), + "protocol": config.general.scheme, + } + ) + + +def get_feedback( + global_config: models.GlobalConfiguration, +) -> models.FeedbackConfiguration: + feedback = global_config.feedback + if not (config.smtp and config.smtp.enabled): + feedback.enabled = False + feedback.after_session = False + feedback.on_footer = False + feedback.on_session_card = False + feedback.interval.enabled = False + + return feedback diff --git a/backend/capellacollab/users/routes.py b/backend/capellacollab/users/routes.py index 1ce274724f..6684372a0c 100644 --- a/backend/capellacollab/users/routes.py +++ b/backend/capellacollab/users/routes.py @@ -16,7 +16,6 @@ from capellacollab.projects.users import crud as projects_users_crud from capellacollab.sessions import routes as session_routes from capellacollab.settings.configuration import core as config_core -from capellacollab.settings.configuration import models as config_models from capellacollab.users import injectables as users_injectables from capellacollab.users import models as users_models from capellacollab.users.tokens import routes as tokens_routes @@ -41,18 +40,6 @@ def get_current_user( return user -@router.get( - "/beta", - response_model=config_models.BetaConfiguration, -) -def get_beta_config(db: orm.Session = fastapi.Depends(database.get_db)): - cfg = config_core.get_global_configuration(db) - - return config_models.BetaConfiguration.model_validate( - cfg.beta.model_dump() - ) - - @router.get( "/{user_id}", response_model=models.User, diff --git a/backend/tests/settings/test_global_configuration.py b/backend/tests/settings/test_global_configuration.py index baa199d66f..3b3377256d 100644 --- a/backend/tests/settings/test_global_configuration.py +++ b/backend/tests/settings/test_global_configuration.py @@ -128,9 +128,9 @@ def test_metadata_is_updated( assert response.status_code == 200 - response = client.get("/api/v1/metadata") + response = client.get("/api/v1/settings/configurations/unified") assert response.status_code == 200 - assert response.json()["environment"] == "test" + assert response.json()["metadata"]["environment"] == "test" @pytest.mark.usefixtures("admin") @@ -154,9 +154,9 @@ def test_navbar_is_updated( assert response.status_code == 200 - response = client.get("/api/v1/navbar") + response = client.get("/api/v1/settings/configurations/unified") assert response.status_code == 200 - assert response.json()["external_links"][0] == { + assert response.json()["navbar"]["external_links"][0] == { "name": "Example", "href": "https://example.com", "role": "user", diff --git a/backend/tests/test_feedback.py b/backend/tests/test_feedback.py index a89b55be83..60d6a211ed 100644 --- a/backend/tests/test_feedback.py +++ b/backend/tests/test_feedback.py @@ -210,9 +210,9 @@ def test_feedback_is_updated( assert response.status_code == 200 - response = client.get("/api/v1/configurations/feedback") + response = client.get("/api/v1/settings/configurations/unified") assert response.status_code == 200 - assert response.json() == { + assert response.json()["feedback"] == { "enabled": True, "after_session": True, "on_footer": True, @@ -262,9 +262,9 @@ def test_activate_feedback_without_recipients( @pytest.mark.usefixtures("user", "smtp_config_not_set", "feedback_enabled") def test_feedback_is_disabled_without_smtp(client: testclient.TestClient): - response = client.get("/api/v1/configurations/feedback") + response = client.get("/api/v1/settings/configurations/unified") assert response.status_code == 200 - assert response.json()["enabled"] is False + assert response.json()["feedback"]["enabled"] is False def test_feedback_metric(db: orm.Session): diff --git a/frontend/src/app/general/metadata/metadata.service.ts b/frontend/src/app/general/metadata/metadata.service.ts index 191f3455fe..b6506cf68e 100644 --- a/frontend/src/app/general/metadata/metadata.service.ts +++ b/frontend/src/app/general/metadata/metadata.service.ts @@ -5,11 +5,8 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { BehaviorSubject, Observable, tap } from 'rxjs'; -import { - Metadata, - MetadataService as OpenAPIMetadataService, -} from 'src/app/openapi'; +import { map } from 'rxjs'; +import { UnifiedConfigWrapperService } from '../../services/unified-config-wrapper/unified-config-wrapper.service'; @Injectable({ providedIn: 'root', @@ -18,19 +15,18 @@ export class MetadataService { constructor( private httpClient: HttpClient, public dialog: MatDialog, - private metadataService: OpenAPIMetadataService, + private unifiedConfigWrapperService: UnifiedConfigWrapperService, ) { this.loadVersion(); - this.loadBackendMetadata().subscribe(); } public version: Version | undefined; public oldVersion: string | undefined; - private _backendMetadata = new BehaviorSubject( - undefined, - ); - readonly backendMetadata = this._backendMetadata.asObservable(); + readonly backendMetadata = + this.unifiedConfigWrapperService.unifiedConfig$.pipe( + map((unifiedConfig) => unifiedConfig?.metadata), + ); loadVersion(): void { if (!this.version) { @@ -42,12 +38,6 @@ export class MetadataService { } } - loadBackendMetadata(): Observable { - return this.metadataService - .getMetadata() - .pipe(tap((metadata: Metadata) => this._backendMetadata.next(metadata))); - } - get changedVersion(): boolean { const currentVersion = localStorage.getItem('version'); diff --git a/frontend/src/app/general/nav-bar/nav-bar.service.ts b/frontend/src/app/general/nav-bar/nav-bar.service.ts index a78e16a0c8..da10caa86d 100644 --- a/frontend/src/app/general/nav-bar/nav-bar.service.ts +++ b/frontend/src/app/general/nav-bar/nav-bar.service.ts @@ -4,37 +4,23 @@ */ import { Injectable } from '@angular/core'; import { MatSidenav } from '@angular/material/sidenav'; -import { BehaviorSubject, map, Observable, tap } from 'rxjs'; -import { - BuiltInLinkItem, - NavbarConfigurationOutput, - NavbarService as OpenAPINavbarService, - Role, -} from 'src/app/openapi'; +import { map } from 'rxjs'; +import { BuiltInLinkItem, Role } from 'src/app/openapi'; import { environment } from 'src/environments/environment'; +import { UnifiedConfigWrapperService } from '../../services/unified-config-wrapper/unified-config-wrapper.service'; @Injectable({ providedIn: 'root', }) export class NavBarService { - constructor(private navbarService: OpenAPINavbarService) { - this.loadNavbarConfig().subscribe(); - } - - loadNavbarConfig(): Observable { - return this.navbarService - .getNavbar() - .pipe(tap((navConf) => this._navbarConfig.next(navConf))); - } - - private _navbarConfig = new BehaviorSubject< - NavbarConfigurationOutput | undefined - >(undefined); + constructor( + private unifiedConfigWrapperService: UnifiedConfigWrapperService, + ) {} - readonly navbarItems$ = this._navbarConfig.pipe( + readonly navbarItems$ = this.unifiedConfigWrapperService.unifiedConfig$.pipe( map( - (navbarConfig): NavBarItem[] => - navbarConfig?.external_links.map((link) => ({ + (unifiedConfig): NavBarItem[] => + unifiedConfig?.navbar?.external_links.map((link) => ({ name: link.name, href: link.service ? this._linkMap[link.service] : link.href, target: '_blank', diff --git a/frontend/src/app/openapi/.openapi-generator/FILES b/frontend/src/app/openapi/.openapi-generator/FILES index 3103057927..20e81fab73 100644 --- a/frontend/src/app/openapi/.openapi-generator/FILES +++ b/frontend/src/app/openapi/.openapi-generator/FILES @@ -6,8 +6,6 @@ api/events.service.ts api/feedback.service.ts api/health.service.ts api/integrations-pure-variants.service.ts -api/metadata.service.ts -api/navbar.service.ts api/notices.service.ts api/projects-events.service.ts api/projects-models-backups.service.ts @@ -215,6 +213,7 @@ model/tool-version-with-tool.ts model/tool-version.ts model/tool.ts model/toolmodel-status.ts +model/unified-config.ts model/user-metadata.ts model/user-token-with-password.ts model/user-token.ts diff --git a/frontend/src/app/openapi/api/api.ts b/frontend/src/app/openapi/api/api.ts index b6ce03b8da..72a053c3c5 100644 --- a/frontend/src/app/openapi/api/api.ts +++ b/frontend/src/app/openapi/api/api.ts @@ -21,10 +21,6 @@ export * from './health.service'; import { HealthService } from './health.service'; export * from './integrations-pure-variants.service'; import { IntegrationsPureVariantsService } from './integrations-pure-variants.service'; -export * from './metadata.service'; -import { MetadataService } from './metadata.service'; -export * from './navbar.service'; -import { NavbarService } from './navbar.service'; export * from './notices.service'; import { NoticesService } from './notices.service'; export * from './projects.service'; @@ -69,4 +65,4 @@ export * from './users-token.service'; import { UsersTokenService } from './users-token.service'; export * from './users-workspaces.service'; import { UsersWorkspacesService } from './users-workspaces.service'; -export const APIS = [AuthenticationService, ConfigurationService, EventsService, FeedbackService, HealthService, IntegrationsPureVariantsService, MetadataService, NavbarService, NoticesService, ProjectsService, ProjectsEventsService, ProjectsModelsService, ProjectsModelsBackupsService, ProjectsModelsDiagramsService, ProjectsModelsGitService, ProjectsModelsModelComplexityBadgeService, ProjectsModelsProvisioningService, ProjectsModelsREADMEService, ProjectsModelsRestrictionsService, ProjectsModelsT4CService, ProjectsToolsService, SessionsService, SettingsModelsourcesGitService, SettingsModelsourcesT4CInstancesService, SettingsModelsourcesT4CLicenseServersService, ToolsService, UsersService, UsersSessionsService, UsersTokenService, UsersWorkspacesService]; +export const APIS = [AuthenticationService, ConfigurationService, EventsService, FeedbackService, HealthService, IntegrationsPureVariantsService, NoticesService, ProjectsService, ProjectsEventsService, ProjectsModelsService, ProjectsModelsBackupsService, ProjectsModelsDiagramsService, ProjectsModelsGitService, ProjectsModelsModelComplexityBadgeService, ProjectsModelsProvisioningService, ProjectsModelsREADMEService, ProjectsModelsRestrictionsService, ProjectsModelsT4CService, ProjectsToolsService, SessionsService, SettingsModelsourcesGitService, SettingsModelsourcesT4CInstancesService, SettingsModelsourcesT4CLicenseServersService, ToolsService, UsersService, UsersSessionsService, UsersTokenService, UsersWorkspacesService]; diff --git a/frontend/src/app/openapi/api/configuration.service.ts b/frontend/src/app/openapi/api/configuration.service.ts index bb2d495d52..5d01ac8243 100644 --- a/frontend/src/app/openapi/api/configuration.service.ts +++ b/frontend/src/app/openapi/api/configuration.service.ts @@ -24,6 +24,8 @@ import { GlobalConfigurationInput } from '../model/global-configuration-input'; import { GlobalConfigurationOutput } from '../model/global-configuration-output'; // @ts-ignore import { HTTPValidationError } from '../model/http-validation-error'; +// @ts-ignore +import { UnifiedConfig } from '../model/unified-config'; // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; @@ -223,6 +225,73 @@ export class ConfigurationService { ); } + /** + * Get Unified Config + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getUnifiedConfig(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; + public getUnifiedConfig(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public getUnifiedConfig(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public getUnifiedConfig(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { + + let localVarHeaders = this.defaultHeaders; + + let localVarCredential: string | undefined; + // authentication (PersonalAccessToken) required + localVarCredential = this.configuration.lookupCredential('PersonalAccessToken'); + if (localVarCredential) { + localVarHeaders = localVarHeaders.set('Authorization', 'Basic ' + localVarCredential); + } + + let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; + if (localVarHttpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = [ + 'application/json' + ]; + localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); + } + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + let localVarHttpContext: HttpContext | undefined = options && options.context; + if (localVarHttpContext === undefined) { + localVarHttpContext = new HttpContext(); + } + + let localVarTransferCache: boolean | undefined = options && options.transferCache; + if (localVarTransferCache === undefined) { + localVarTransferCache = true; + } + + + let responseType_: 'text' | 'json' | 'blob' = 'json'; + if (localVarHttpHeaderAcceptSelected) { + if (localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { + responseType_ = 'json'; + } else { + responseType_ = 'blob'; + } + } + + let localVarPath = `/api/v1/settings/configurations/unified`; + return this.httpClient.request('get', `${this.configuration.basePath}${localVarPath}`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + transferCache: localVarTransferCache, + reportProgress: reportProgress + } + ); + } + /** * Update Configuration * @param globalConfigurationInput diff --git a/frontend/src/app/openapi/api/feedback.service.ts b/frontend/src/app/openapi/api/feedback.service.ts index b86b031e3b..bc17aa9fe8 100644 --- a/frontend/src/app/openapi/api/feedback.service.ts +++ b/frontend/src/app/openapi/api/feedback.service.ts @@ -21,8 +21,6 @@ import { Observable } from 'rxjs'; // @ts-ignore import { Feedback } from '../model/feedback'; // @ts-ignore -import { FeedbackConfigurationOutput } from '../model/feedback-configuration-output'; -// @ts-ignore import { HTTPValidationError } from '../model/http-validation-error'; // @ts-ignore @@ -96,66 +94,6 @@ export class FeedbackService { return httpParams; } - /** - * Get Feedback Configuration - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getFeedbackConfiguration(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; - public getFeedbackConfiguration(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getFeedbackConfiguration(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getFeedbackConfiguration(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { - - let localVarHeaders = this.defaultHeaders; - - let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; - if (localVarHttpHeaderAcceptSelected === undefined) { - // to determine the Accept header - const httpHeaderAccepts: string[] = [ - 'application/json' - ]; - localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); - } - if (localVarHttpHeaderAcceptSelected !== undefined) { - localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); - } - - let localVarHttpContext: HttpContext | undefined = options && options.context; - if (localVarHttpContext === undefined) { - localVarHttpContext = new HttpContext(); - } - - let localVarTransferCache: boolean | undefined = options && options.transferCache; - if (localVarTransferCache === undefined) { - localVarTransferCache = true; - } - - - let responseType_: 'text' | 'json' | 'blob' = 'json'; - if (localVarHttpHeaderAcceptSelected) { - if (localVarHttpHeaderAcceptSelected.startsWith('text')) { - responseType_ = 'text'; - } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { - responseType_ = 'json'; - } else { - responseType_ = 'blob'; - } - } - - let localVarPath = `/api/v1/configurations/feedback`; - return this.httpClient.request('get', `${this.configuration.basePath}${localVarPath}`, - { - context: localVarHttpContext, - responseType: responseType_, - withCredentials: this.configuration.withCredentials, - headers: localVarHeaders, - observe: observe, - transferCache: localVarTransferCache, - reportProgress: reportProgress - } - ); - } - /** * Submit Feedback * @param feedback diff --git a/frontend/src/app/openapi/api/metadata.service.ts b/frontend/src/app/openapi/api/metadata.service.ts deleted file mode 100644 index cddbd1e271..0000000000 --- a/frontend/src/app/openapi/api/metadata.service.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Capella Collaboration - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit the class manually. - + To generate a new version, run `make openapi` in the root directory of this repository. - */ - -/* tslint:disable:no-unused-variable member-ordering */ - -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent, HttpParameterCodec, HttpContext - } from '@angular/common/http'; -import { CustomHttpParameterCodec } from '../encoder'; -import { Observable } from 'rxjs'; - -// @ts-ignore -import { Metadata } from '../model/metadata'; - -// @ts-ignore -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - - - -@Injectable({ - providedIn: 'root' -}) -export class MetadataService { - - protected basePath = 'http://localhost'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - public encoder: HttpParameterCodec; - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string|string[], @Optional() configuration: Configuration) { - if (configuration) { - this.configuration = configuration; - } - if (typeof this.configuration.basePath !== 'string') { - const firstBasePath = Array.isArray(basePath) ? basePath[0] : undefined; - if (firstBasePath != undefined) { - basePath = firstBasePath; - } - - if (typeof basePath !== 'string') { - basePath = this.basePath; - } - this.configuration.basePath = basePath; - } - this.encoder = this.configuration.encoder || new CustomHttpParameterCodec(); - } - - - // @ts-ignore - private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams { - if (typeof value === "object" && value instanceof Date === false) { - httpParams = this.addToHttpParamsRecursive(httpParams, value); - } else { - httpParams = this.addToHttpParamsRecursive(httpParams, value, key); - } - return httpParams; - } - - private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams { - if (value == null) { - return httpParams; - } - - if (typeof value === "object") { - if (Array.isArray(value)) { - (value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key)); - } else if (value instanceof Date) { - if (key != null) { - httpParams = httpParams.append(key, (value as Date).toISOString().substring(0, 10)); - } else { - throw Error("key may not be null if value is Date"); - } - } else { - Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive( - httpParams, value[k], key != null ? `${key}.${k}` : k)); - } - } else if (key != null) { - httpParams = httpParams.append(key, value); - } else { - throw Error("key may not be null if value is not object or array"); - } - return httpParams; - } - - /** - * Get Metadata - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getMetadata(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; - public getMetadata(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getMetadata(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getMetadata(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { - - let localVarHeaders = this.defaultHeaders; - - let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; - if (localVarHttpHeaderAcceptSelected === undefined) { - // to determine the Accept header - const httpHeaderAccepts: string[] = [ - 'application/json' - ]; - localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); - } - if (localVarHttpHeaderAcceptSelected !== undefined) { - localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); - } - - let localVarHttpContext: HttpContext | undefined = options && options.context; - if (localVarHttpContext === undefined) { - localVarHttpContext = new HttpContext(); - } - - let localVarTransferCache: boolean | undefined = options && options.transferCache; - if (localVarTransferCache === undefined) { - localVarTransferCache = true; - } - - - let responseType_: 'text' | 'json' | 'blob' = 'json'; - if (localVarHttpHeaderAcceptSelected) { - if (localVarHttpHeaderAcceptSelected.startsWith('text')) { - responseType_ = 'text'; - } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { - responseType_ = 'json'; - } else { - responseType_ = 'blob'; - } - } - - let localVarPath = `/api/v1/metadata`; - return this.httpClient.request('get', `${this.configuration.basePath}${localVarPath}`, - { - context: localVarHttpContext, - responseType: responseType_, - withCredentials: this.configuration.withCredentials, - headers: localVarHeaders, - observe: observe, - transferCache: localVarTransferCache, - reportProgress: reportProgress - } - ); - } - -} diff --git a/frontend/src/app/openapi/api/navbar.service.ts b/frontend/src/app/openapi/api/navbar.service.ts deleted file mode 100644 index ec60ae1904..0000000000 --- a/frontend/src/app/openapi/api/navbar.service.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Capella Collaboration - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit the class manually. - + To generate a new version, run `make openapi` in the root directory of this repository. - */ - -/* tslint:disable:no-unused-variable member-ordering */ - -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent, HttpParameterCodec, HttpContext - } from '@angular/common/http'; -import { CustomHttpParameterCodec } from '../encoder'; -import { Observable } from 'rxjs'; - -// @ts-ignore -import { NavbarConfigurationOutput } from '../model/navbar-configuration-output'; - -// @ts-ignore -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - - - -@Injectable({ - providedIn: 'root' -}) -export class NavbarService { - - protected basePath = 'http://localhost'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - public encoder: HttpParameterCodec; - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string|string[], @Optional() configuration: Configuration) { - if (configuration) { - this.configuration = configuration; - } - if (typeof this.configuration.basePath !== 'string') { - const firstBasePath = Array.isArray(basePath) ? basePath[0] : undefined; - if (firstBasePath != undefined) { - basePath = firstBasePath; - } - - if (typeof basePath !== 'string') { - basePath = this.basePath; - } - this.configuration.basePath = basePath; - } - this.encoder = this.configuration.encoder || new CustomHttpParameterCodec(); - } - - - // @ts-ignore - private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams { - if (typeof value === "object" && value instanceof Date === false) { - httpParams = this.addToHttpParamsRecursive(httpParams, value); - } else { - httpParams = this.addToHttpParamsRecursive(httpParams, value, key); - } - return httpParams; - } - - private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams { - if (value == null) { - return httpParams; - } - - if (typeof value === "object") { - if (Array.isArray(value)) { - (value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key)); - } else if (value instanceof Date) { - if (key != null) { - httpParams = httpParams.append(key, (value as Date).toISOString().substring(0, 10)); - } else { - throw Error("key may not be null if value is Date"); - } - } else { - Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive( - httpParams, value[k], key != null ? `${key}.${k}` : k)); - } - } else if (key != null) { - httpParams = httpParams.append(key, value); - } else { - throw Error("key may not be null if value is not object or array"); - } - return httpParams; - } - - /** - * Get Navbar - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getNavbar(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; - public getNavbar(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getNavbar(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getNavbar(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { - - let localVarHeaders = this.defaultHeaders; - - let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; - if (localVarHttpHeaderAcceptSelected === undefined) { - // to determine the Accept header - const httpHeaderAccepts: string[] = [ - 'application/json' - ]; - localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); - } - if (localVarHttpHeaderAcceptSelected !== undefined) { - localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); - } - - let localVarHttpContext: HttpContext | undefined = options && options.context; - if (localVarHttpContext === undefined) { - localVarHttpContext = new HttpContext(); - } - - let localVarTransferCache: boolean | undefined = options && options.transferCache; - if (localVarTransferCache === undefined) { - localVarTransferCache = true; - } - - - let responseType_: 'text' | 'json' | 'blob' = 'json'; - if (localVarHttpHeaderAcceptSelected) { - if (localVarHttpHeaderAcceptSelected.startsWith('text')) { - responseType_ = 'text'; - } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { - responseType_ = 'json'; - } else { - responseType_ = 'blob'; - } - } - - let localVarPath = `/api/v1/navbar`; - return this.httpClient.request('get', `${this.configuration.basePath}${localVarPath}`, - { - context: localVarHttpContext, - responseType: responseType_, - withCredentials: this.configuration.withCredentials, - headers: localVarHeaders, - observe: observe, - transferCache: localVarTransferCache, - reportProgress: reportProgress - } - ); - } - -} diff --git a/frontend/src/app/openapi/api/users.service.ts b/frontend/src/app/openapi/api/users.service.ts index 45b107b2af..9495cfdf00 100644 --- a/frontend/src/app/openapi/api/users.service.ts +++ b/frontend/src/app/openapi/api/users.service.ts @@ -18,8 +18,6 @@ import { HttpClient, HttpHeaders, HttpParams, import { CustomHttpParameterCodec } from '../encoder'; import { Observable } from 'rxjs'; -// @ts-ignore -import { BetaConfigurationOutput } from '../model/beta-configuration-output'; // @ts-ignore import { HTTPValidationError } from '../model/http-validation-error'; // @ts-ignore @@ -560,73 +558,6 @@ export class UsersService { ); } - /** - * Get Beta Config - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getBetaConfig(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; - public getBetaConfig(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getBetaConfig(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getBetaConfig(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { - - let localVarHeaders = this.defaultHeaders; - - let localVarCredential: string | undefined; - // authentication (PersonalAccessToken) required - localVarCredential = this.configuration.lookupCredential('PersonalAccessToken'); - if (localVarCredential) { - localVarHeaders = localVarHeaders.set('Authorization', 'Basic ' + localVarCredential); - } - - let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; - if (localVarHttpHeaderAcceptSelected === undefined) { - // to determine the Accept header - const httpHeaderAccepts: string[] = [ - 'application/json' - ]; - localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); - } - if (localVarHttpHeaderAcceptSelected !== undefined) { - localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); - } - - let localVarHttpContext: HttpContext | undefined = options && options.context; - if (localVarHttpContext === undefined) { - localVarHttpContext = new HttpContext(); - } - - let localVarTransferCache: boolean | undefined = options && options.transferCache; - if (localVarTransferCache === undefined) { - localVarTransferCache = true; - } - - - let responseType_: 'text' | 'json' | 'blob' = 'json'; - if (localVarHttpHeaderAcceptSelected) { - if (localVarHttpHeaderAcceptSelected.startsWith('text')) { - responseType_ = 'text'; - } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { - responseType_ = 'json'; - } else { - responseType_ = 'blob'; - } - } - - let localVarPath = `/api/v1/users/beta`; - return this.httpClient.request('get', `${this.configuration.basePath}${localVarPath}`, - { - context: localVarHttpContext, - responseType: responseType_, - withCredentials: this.configuration.withCredentials, - headers: localVarHeaders, - observe: observe, - transferCache: localVarTransferCache, - reportProgress: reportProgress - } - ); - } - /** * Get Common Projects * @param userId diff --git a/frontend/src/app/openapi/model/models.ts b/frontend/src/app/openapi/model/models.ts index 672e44a528..2bb091f6c5 100644 --- a/frontend/src/app/openapi/model/models.ts +++ b/frontend/src/app/openapi/model/models.ts @@ -190,6 +190,7 @@ export * from './tool-version-configuration-input'; export * from './tool-version-configuration-output'; export * from './tool-version-with-tool'; export * from './toolmodel-status'; +export * from './unified-config'; export * from './user'; export * from './user-metadata'; export * from './user-token'; diff --git a/frontend/src/app/openapi/model/unified-config.ts b/frontend/src/app/openapi/model/unified-config.ts new file mode 100644 index 0000000000..615afbb1a9 --- /dev/null +++ b/frontend/src/app/openapi/model/unified-config.ts @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Capella Collaboration + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit the class manually. + + To generate a new version, run `make openapi` in the root directory of this repository. + */ + +import { NavbarConfigurationOutput } from './navbar-configuration-output'; +import { BetaConfigurationOutput } from './beta-configuration-output'; +import { Metadata } from './metadata'; +import { FeedbackConfigurationOutput } from './feedback-configuration-output'; + + +export interface UnifiedConfig { + metadata: Metadata; + feedback: FeedbackConfigurationOutput; + navbar: NavbarConfigurationOutput; + beta: BetaConfigurationOutput; +} + diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts index 6e16ae09ff..a4188f93fb 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts @@ -47,7 +47,6 @@ import { TokenService } from 'src/app/users/basic-auth-service/basic-auth-token. }) export class ModelDiagramCodeBlockComponent implements OnInit, AfterViewInit { passwordValue?: string; - metadata?: Metadata; constructor( diff --git a/frontend/src/app/services/unified-config-wrapper/unified-config-wrapper.service.ts b/frontend/src/app/services/unified-config-wrapper/unified-config-wrapper.service.ts new file mode 100644 index 0000000000..deb22a3dca --- /dev/null +++ b/frontend/src/app/services/unified-config-wrapper/unified-config-wrapper.service.ts @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable, tap } from 'rxjs'; +import { UnifiedConfig, ConfigurationService } from '../../openapi'; + +@Injectable({ + providedIn: 'root', +}) +export class UnifiedConfigWrapperService { + constructor(private configurationService: ConfigurationService) { + this.loadUnifiedConfig().subscribe(); + } + + loadUnifiedConfig(): Observable { + return this.configurationService + .getUnifiedConfig() + .pipe(tap((unified) => this._unifiedConfig.next(unified))); + } + private _unifiedConfig = new BehaviorSubject( + undefined, + ); + + get unifiedConfig() { + return this._unifiedConfig.value; + } + + readonly unifiedConfig$ = this._unifiedConfig.asObservable(); +} diff --git a/frontend/src/app/sessions/feedback/feedback.service.ts b/frontend/src/app/sessions/feedback/feedback.service.ts index 532764fb41..df03c98043 100644 --- a/frontend/src/app/sessions/feedback/feedback.service.ts +++ b/frontend/src/app/sessions/feedback/feedback.service.ts @@ -4,13 +4,11 @@ */ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { BehaviorSubject, Observable, tap } from 'rxjs'; +import { map, take } from 'rxjs'; +import { filter } from 'rxjs/operators'; import { AuthenticationWrapperService } from 'src/app/services/auth/auth.service'; -import { - FeedbackConfigurationOutput, - FeedbackService as OpenAPIFeedbackService, - Session, -} from '../../openapi'; +import { FeedbackConfigurationOutput, Session } from '../../openapi'; +import { UnifiedConfigWrapperService } from '../../services/unified-config-wrapper/unified-config-wrapper.service'; import { FeedbackDialogComponent } from './feedback-dialog/feedback-dialog.component'; @Injectable({ @@ -18,30 +16,28 @@ import { FeedbackDialogComponent } from './feedback-dialog/feedback-dialog.compo }) export class FeedbackWrapperService { constructor( - private feedbackService: OpenAPIFeedbackService, public dialog: MatDialog, private authService: AuthenticationWrapperService, + public unifiedConfigWrapperService: UnifiedConfigWrapperService, ) { - this.loadFeedbackConfig().subscribe(() => this.triggerFeedbackPrompt()); + this.unifiedConfigWrapperService.unifiedConfig$.subscribe(() => { + this.triggerFeedbackPrompt(); + }); } - private _feedbackConfig = new BehaviorSubject< - FeedbackConfigurationOutput | undefined - >(undefined); - - public readonly feedbackConfig$ = this._feedbackConfig.asObservable(); - - loadFeedbackConfig(): Observable { - return this.feedbackService - .getFeedbackConfiguration() - .pipe(tap((feedbackConf) => this._feedbackConfig.next(feedbackConf))); - } + public readonly feedbackConfig$ = + this.unifiedConfigWrapperService.unifiedConfig$.pipe( + map((unifiedConfig) => unifiedConfig?.feedback), + ); triggerFeedbackPrompt(): void { - if (this.shouldShowIntervalPrompt() && this.authService.isLoggedIn()) { - this.showDialog([], 'On interval'); - this.saveFeedbackPromptDate(); - } + if (!this.authService.isLoggedIn()) return; + this.feedbackConfig$.pipe(filter(Boolean), take(1)).subscribe((config) => { + if (this.shouldShowIntervalPrompt(config)) { + this.showDialog([], 'On interval'); + this.saveFeedbackPromptDate(); + } + }); } public showDialog(sessions: Session[], trigger: string) { @@ -51,22 +47,18 @@ export class FeedbackWrapperService { }); } - public shouldShowIntervalPrompt() { - if (!this._feedbackConfig.value?.interval?.enabled) return false; + public shouldShowIntervalPrompt(config: FeedbackConfigurationOutput) { + if (!config?.interval?.enabled) return false; const lastPrompt = localStorage.getItem('feedbackPrompt'); if (!lastPrompt) { return true; } const lastPromptDate = new Date(parseInt(lastPrompt)); - const hoursInterval = - this._feedbackConfig.value.interval.hours_between_prompt; + const hoursInterval = config.interval.hours_between_prompt; const diff = new Date().getTime() - lastPromptDate.getTime(); const hours = diff / (1000 * 60 * 60); - if (hours >= hoursInterval) { - return true; - } - return false; + return hours >= hoursInterval; } public saveFeedbackPromptDate() { @@ -74,7 +66,7 @@ export class FeedbackWrapperService { } public shouldShowPostSessionPrompt() { - if (this._feedbackConfig.value?.after_session) return true; - return false; + return !!this.unifiedConfigWrapperService.unifiedConfig?.feedback + ?.after_session; } } 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 5a27402d6d..9047bdaad1 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 @@ -5,13 +5,11 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatIcon } from '@angular/material/icon'; -import { MetadataService } from 'src/app/general/metadata/metadata.service'; -import { NavBarService } from 'src/app/general/nav-bar/nav-bar.service'; import { EditorComponent } from 'src/app/helpers/editor/editor.component'; import { ToastService } from 'src/app/helpers/toast/toast.service'; import { ConfigurationSettingsService } from 'src/app/settings/core/configuration-settings/configuration-settings.service'; import { EditorComponent as EditorComponent_1 } from '../../../helpers/editor/editor.component'; -import { FeedbackWrapperService } from '../../../sessions/feedback/feedback.service'; +import { UnifiedConfigWrapperService } from '../../../services/unified-config-wrapper/unified-config-wrapper.service'; @Component({ selector: 'app-configuration-settings', @@ -24,9 +22,7 @@ export class ConfigurationSettingsComponent implements OnInit { constructor( private configurationSettingsService: ConfigurationSettingsService, private toastService: ToastService, - private metadataService: MetadataService, - private navbarService: NavBarService, - private feedbackService: FeedbackWrapperService, + private unifiedConfigService: UnifiedConfigWrapperService, ) {} ngOnInit(): void { @@ -52,9 +48,7 @@ export class ConfigurationSettingsComponent implements OnInit { 'The global configuration has been successfully updated. The metadata will be reloaded.', ); this.fetchConfiguration(); - this.metadataService.loadBackendMetadata().subscribe(); - this.navbarService.loadNavbarConfig().subscribe(); - this.feedbackService.loadFeedbackConfig().subscribe(); + this.unifiedConfigService.loadUnifiedConfig().subscribe(); }, }); } diff --git a/frontend/src/app/users/users-profile/users-profile.component.html b/frontend/src/app/users/users-profile/users-profile.component.html index 3b1a24042f..74924e6caf 100644 --- a/frontend/src/app/users/users-profile/users-profile.component.html +++ b/frontend/src/app/users/users-profile/users-profile.component.html @@ -27,11 +27,12 @@

Profile of {{ user?.name }}

@if (ownUserService.user?.role === "administrator") { } - @if ((betaConfig$ | async)?.enabled) { + @let betaConfig = (unifiedConfigWrapperService.unifiedConfig$ | async)?.beta; + @if (betaConfig?.enabled) { @if ( ownUserService.user?.role === "administrator" || (ownUserService.user?.id === (userWrapperService.user$ | async)?.id && - (betaConfig$ | async)?.allow_self_enrollment) + betaConfig?.allow_self_enrollment) ) { } diff --git a/frontend/src/app/users/users-profile/users-profile.component.ts b/frontend/src/app/users/users-profile/users-profile.component.ts index 50fe378abf..12ba1a6869 100644 --- a/frontend/src/app/users/users-profile/users-profile.component.ts +++ b/frontend/src/app/users/users-profile/users-profile.component.ts @@ -5,10 +5,9 @@ import { AsyncPipe, DatePipe } from '@angular/common'; import { Component } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; -import { BehaviorSubject } from 'rxjs'; import { OwnUserWrapperService } from 'src/app/services/user/user.service'; import { UserWrapperService } from 'src/app/users/user-wrapper/user-wrapper.service'; -import { BetaConfigurationOutput, UsersService } from '../../openapi'; +import { UnifiedConfigWrapperService } from '../../services/unified-config-wrapper/unified-config-wrapper.service'; import { BetaTestingComponent } from './beta-testing/beta-testing.component'; import { CommonProjectsComponent } from './common-projects/common-projects.component'; import { UserInformationComponent } from './user-information/user-information.component'; @@ -31,18 +30,6 @@ export class UsersProfileComponent { constructor( public ownUserService: OwnUserWrapperService, public userWrapperService: UserWrapperService, - private usersService: UsersService, - ) { - this.getBetaConfig(); - } - - readonly betaConfig$ = new BehaviorSubject< - BetaConfigurationOutput | undefined - >(undefined); - - getBetaConfig() { - return this.usersService.getBetaConfig().subscribe((res) => { - this.betaConfig$.next(res); - }); - } + public unifiedConfigWrapperService: UnifiedConfigWrapperService, + ) {} }