From c8a1fcf408622a7a26d7c4f7deb321645ce8b2e7 Mon Sep 17 00:00:00 2001 From: Jason Esterhuizen Date: Sat, 1 Feb 2025 20:12:46 +0200 Subject: [PATCH 1/6] [BUG] Fixed startup updates --- app/constants/files.py | 18 +++++++++++------- app/constants/folders.py | 8 ++++---- app/startup.py | 18 +++++++++--------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/constants/files.py b/app/constants/files.py index 1003a5f..6918aa2 100644 --- a/app/constants/files.py +++ b/app/constants/files.py @@ -1,6 +1,7 @@ # DEPENDENCIES ## Built-in import os +import json ## Local from .base_enum import BaseEnum from .components import Components @@ -20,6 +21,8 @@ class Files(BaseEnum): # Startup STARTUP_HISTORY: str = f"{Folders.STORAGE}.startup_history" VERSION: str = "version" + # Storage + CONTROLLER_SETTINGS: str = f"{Folders.CONTROLLER_STORAGE}.settings" # INIT @@ -91,12 +94,13 @@ def setup_user_deployment_file(dev: bool): user_deployment_file.write(deployment_string) user_deployment_file.close() -_ENSURE_FILES: frozenset[str] = frozenset([ - Files.STARTUP_HISTORY +_ENSURE_JSON_FILES: frozenset[str] = frozenset([ + Files.STARTUP_HISTORY, + Files.CONTROLLER_SETTINGS ]) -def _ensure_files(): - for file in _ENSURE_FILES: +def _ensure_json_files(): + for file in _ENSURE_JSON_FILES: if not os.path.isfile(file): - with open(file, "w", encoding="utf-8"): - pass -_ensure_files() \ No newline at end of file + with open(file, "w", encoding="utf-8") as file: + json.dump({}, file) +_ensure_json_files() diff --git a/app/constants/folders.py b/app/constants/folders.py index 4339382..44f0b72 100644 --- a/app/constants/folders.py +++ b/app/constants/folders.py @@ -15,10 +15,10 @@ class Folders(BaseEnum): # Storage STORAGE: str = ".storage/" _HOST_STORAGE: str = f"{os.getcwd()}/{STORAGE}" - CONTROLLER_STORAGE: str = f"{_HOST_STORAGE}controller" - LAYERS_STORAGE: str = f"{_HOST_STORAGE}layers" - MODEL_PROVIDER_STORAGE: str = f"{_HOST_STORAGE}model_provider" - OUTPUT_STORAGE: str = f"{_HOST_STORAGE}output" + CONTROLLER_STORAGE: str = f"{_HOST_STORAGE}controller/" + LAYERS_STORAGE: str = f"{_HOST_STORAGE}layers/" + MODEL_PROVIDER_STORAGE: str = f"{_HOST_STORAGE}model_provider/" + OUTPUT_STORAGE: str = f"{_HOST_STORAGE}output/" # INIT diff --git a/app/startup.py b/app/startup.py index aef5a20..38fa6a5 100755 --- a/app/startup.py +++ b/app/startup.py @@ -32,15 +32,14 @@ def update() -> bool: logger.startup(f"Updating {Names.ACE}...") execute_shell(ShellCommands.UPDATE) +def check_if_latest_build() -> bool: + """Compares the update history and version files to check if the container needs to be rebuilt""" updates: dict[str] = {} history: dict[str] = {} - with open(Files.STARTUP_UPDATES, "r", encoding="utf-8") as updates_file: + with open(Files.VERSION, "r", encoding="utf-8") as updates_file: updates = json.load(updates_file) with open(Files.STARTUP_HISTORY, "r", encoding="utf-8") as history_file: - if history_file.read() == "": - history = {} - else: - history = json.load(history_file) + history = json.loads(history_file.read()) if not history: with open(Files.STARTUP_HISTORY, "w", encoding="utf-8") as history_file: history[DictKeys.REBUILD_DATE] = "" @@ -69,7 +68,7 @@ def build_container(force_build: bool = False): updates: dict[str] = {} history: dict[str] = {} - with open(Files.STARTUP_UPDATES, "r", encoding="utf-8") as updates_file: + with open(Files.VERSION, "r", encoding="utf-8") as updates_file: updates = json.load(updates_file) with open(Files.STARTUP_HISTORY, "r", encoding="utf-8") as history_file: history = json.load(history_file) @@ -115,9 +114,10 @@ def startup(): setup_user_deployment_file(dev) setup_network() if not dev: - update_build: bool = update() - if update_build: - force_build = True + update() + update_build: bool = check_if_latest_build() + if update_build: + force_build = True build_container(force_build=force_build) execute_shell(ShellCommands.CLEAR_OLD_IMAGES) From 941da865064e7aa88a3a6645683fdbfc641ea315 Mon Sep 17 00:00:00 2001 From: Jason Esterhuizen Date: Sat, 1 Feb 2025 21:29:11 +0200 Subject: [PATCH 2/6] [FEAT] Added controller api with basic endpoints --- app/components/controller/api/__init__.py | 1 + app/components/controller/api/routes.py | 64 +++++++++++++++++++++++ app/components/controller/api/schemas.py | 26 +++++++++ app/components/controller/api/service.py | 34 ++++++++++++ app/components/controller/start.py | 17 ++++++ app/constants/__init__.py | 3 +- app/constants/base_enum.py | 8 +-- app/constants/defaults.py | 14 +++++ app/constants/dict_keys.py | 1 + app/constants/model_providers.py | 13 +++++ app/requirements | 3 ++ 11 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 app/components/controller/api/__init__.py create mode 100644 app/components/controller/api/routes.py create mode 100644 app/components/controller/api/schemas.py create mode 100644 app/components/controller/api/service.py create mode 100644 app/constants/model_providers.py diff --git a/app/components/controller/api/__init__.py b/app/components/controller/api/__init__.py new file mode 100644 index 0000000..1c363db --- /dev/null +++ b/app/components/controller/api/__init__.py @@ -0,0 +1 @@ +from .routes import controller_api \ No newline at end of file diff --git a/app/components/controller/api/routes.py b/app/components/controller/api/routes.py new file mode 100644 index 0000000..88f426e --- /dev/null +++ b/app/components/controller/api/routes.py @@ -0,0 +1,64 @@ +# DEPENDENCIES +## Third-Party +from fastapi import FastAPI, HTTPException +from http import HTTPStatus +from pydantic import ValidationError +## Local +from constants import Defaults, DefaultAPIResponseSchema, Names +from logger import logger +from . import service +from .schemas import ( + EditSettingsRequest, + GetSettingsResponse, GetVersionDetailsResponse +) + + +controller_api = FastAPI() + + +# ROUTES +@controller_api.get( + "/settings", + response_model=GetSettingsResponse, + description=f"Get the {Names.ACE} controller settings data" +) +async def get_settings_route() -> dict: + try: + return service.get_settings_data() + except ValidationError as error: + logger.error(error) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Settings data error!") + except Exception as error: + logger.error(error) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=Defaults.INTERNAL_SERVER_ERROR_MESSAGE) + +@controller_api.post( + "/settings", + response_model=DefaultAPIResponseSchema, + description=f"Edit the {Names.ACE} controller settings data" +) +async def set_settings_route(updated_settings: EditSettingsRequest) -> dict: + try: + service.edit_settings_data(updated_settings=updated_settings.dict()) + return DefaultAPIResponseSchema(message="Settings data updated successfully!") + except ValidationError as error: + logger.error(error) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Settings data error!") + except Exception as error: + logger.error(error) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=Defaults.INTERNAL_SERVER_ERROR_MESSAGE) + +@controller_api.get( + "/version", + response_model=GetVersionDetailsResponse, + description=f"Get the {Names.ACE}'s version data" +) +async def get_version_route() -> dict: + try: + return service.get_version_data() + except ValidationError as error: + logger.error(error) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Version data error!") + except Exception as error: + logger.error(error) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=Defaults.INTERNAL_SERVER_ERROR_MESSAGE) diff --git a/app/components/controller/api/schemas.py b/app/components/controller/api/schemas.py new file mode 100644 index 0000000..857c996 --- /dev/null +++ b/app/components/controller/api/schemas.py @@ -0,0 +1,26 @@ +# DEPENDENCIES +## Third-Party +from pydantic import BaseModel, validator +## Local +from constants import Defaults + + +class SettingsSchema(BaseModel): + # These are not required + ace_name: str = Defaults.ACE_NAME + model_provider: str = Defaults.MODEL_PROVIDER + temperature: float = Defaults.TEMPERATURE + + @validator("temperature") + def validate_temperature(cls, value): + return min(max(0.0, value), 1.0) + + +# REQUESTS +EditSettingsRequest: type[BaseModel] = SettingsSchema + +# RESPONSES +GetSettingsResponse: type[BaseModel] = SettingsSchema + +class GetVersionDetailsResponse(BaseModel): + version: str diff --git a/app/components/controller/api/service.py b/app/components/controller/api/service.py new file mode 100644 index 0000000..90c8be3 --- /dev/null +++ b/app/components/controller/api/service.py @@ -0,0 +1,34 @@ +# DEPENDENCIES +## Built-In +import json +## Local +from constants import DictKeys, Files, ModelProviders + + +# HELPERS +def _get_settings() -> dict: + settings: dict = {} + with open(Files.CONTROLLER_SETTINGS, "r", encoding="utf-8") as settings_file: + settings = json.loads(settings_file.read()) + return settings + + +# ROUTES +def get_settings_data() -> dict: + return _get_settings() + +def edit_settings_data(updated_settings: dict): + settings: dict = _get_settings() + new_model_provider: str | None = updated_settings.get(DictKeys.MODEL_PROVIDER) + if new_model_provider: + available_model_providers: dict = ModelProviders.get_frozenset() + if new_model_provider not in available_model_providers: + raise ValueError(f"Invalid model provider: {new_model_provider}") + settings.update(updated_settings) + with open(Files.CONTROLLER_SETTINGS, "w", encoding="utf-8") as settings_file: + settings_file.write(json.dumps(settings)) + +def get_version_data() -> dict: + with open(Files.VERSION, "r", encoding="utf-8") as settings_file: + return json.loads(settings_file.read()) + \ No newline at end of file diff --git a/app/components/controller/start.py b/app/components/controller/start.py index 1197928..733e82d 100644 --- a/app/components/controller/start.py +++ b/app/components/controller/start.py @@ -1,6 +1,23 @@ # DEPENDENCIES +## Built-In +import json +## Third-Party +import uvicorn ## Local +from constants import NetworkPorts from logger import logger +from .api import controller_api, service +from .api.schemas import SettingsSchema +from constants import Files + + +def _ensure_settings() -> dict: + settings: dict = service._get_settings() + settings = SettingsSchema(**settings).dict() + with open(Files.CONTROLLER_SETTINGS, "w", encoding="utf-8") as settings_file: + settings_file.write(json.dumps(settings)) def start_controller(component_type: str, dev: bool) -> None: logger.startup(f"Starting {component_type}...") + _ensure_settings() + uvicorn.run(controller_api, host="0.0.0.0", port=int(NetworkPorts.CONTROLLER)) diff --git a/app/constants/__init__.py b/app/constants/__init__.py index ac42544..818875a 100644 --- a/app/constants/__init__.py +++ b/app/constants/__init__.py @@ -1,11 +1,12 @@ from .components import Components from .container_folders import ContainerFolders -from .defaults import Defaults +from .defaults import Defaults, DefaultAPIResponseSchema from .dict_keys import DictKeys from .environment_variables import EnvironmentVariables from .files import Files from .folders import Folders from .logger import CustomLogLevels, TERMINAL_COLOR_CODES +from .model_providers import ModelProviders from .names import Names from .network import NetworkPorts from .shell_commands import ShellCommands diff --git a/app/constants/base_enum.py b/app/constants/base_enum.py index 0d2e174..e2e06dc 100644 --- a/app/constants/base_enum.py +++ b/app/constants/base_enum.py @@ -7,7 +7,7 @@ # ENUMS class BaseEnum(ABC): """Base Enum Class""" - _ALLOWED_ENUM_TYPES: tuple[type, ...] = (str, int) + _ALLOWED_ENUM_TYPES: tuple[type, ...] = (str, int, float) def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) @@ -27,9 +27,9 @@ def get_dict(cls) -> dict[str, str]: return base_enum_dict @classmethod - def get_variable_values_tuple(cls) -> tuple[str, ...]: + def get_tuple(cls) -> tuple[str, ...]: return tuple(cls.get_dict().values()) @classmethod - def get_variable_values_frozenset(cls) -> frozenset[str]: - return frozenset(cls.get_values()) + def get_frozenset(cls) -> frozenset[str]: + return frozenset(cls.get_tuple()) diff --git a/app/constants/defaults.py b/app/constants/defaults.py index db55531..fee934a 100644 --- a/app/constants/defaults.py +++ b/app/constants/defaults.py @@ -1,8 +1,22 @@ # DEPENDENCIES +## Third-Party +from pydantic import BaseModel ## Local from .base_enum import BaseEnum +from .model_providers import ModelProviders class Defaults(BaseEnum): + # API + INTERNAL_SERVER_ERROR_MESSAGE: str = "Server experienced an internal error!" + # Layers + ACE_NAME: str = "PrototypeACE" + # Model Provider + MODEL_PROVIDER: str = ModelProviders.OLLAMA + TEMPERATURE: float = 0.2 + # Logger TERMINAL_COLOR_CODE: str = "\033[0m" # Default color SHUTDOWN_MESSAGE: str = "Shutting down logger..." + +class DefaultAPIResponseSchema(BaseModel): + message: str diff --git a/app/constants/dict_keys.py b/app/constants/dict_keys.py index 61c5b07..eee50a9 100644 --- a/app/constants/dict_keys.py +++ b/app/constants/dict_keys.py @@ -9,6 +9,7 @@ class DictKeys(BaseEnum): FUNCTION_NAME: str = "function_name" LEVEL: str = "level" MESSAGE: str = "message" + MODEL_PROVIDER: str = "model_provider" PROD: str = "prod" REBUILD_DATE: str = "rebuild_date" RESTART: str = "restart" diff --git a/app/constants/model_providers.py b/app/constants/model_providers.py new file mode 100644 index 0000000..1b9d9c9 --- /dev/null +++ b/app/constants/model_providers.py @@ -0,0 +1,13 @@ +# DEPENDENCIES +## Local +from .base_enum import BaseEnum + + +class ModelProviders(BaseEnum): + CLAUDE: str = "claude" + DEEPSEEK: str = "deepsee" + GOOGLE_VERTEX_AI: str = "google_vertex_ai" + GROK: str = "grok" + GROQ: str = "groq" + OLLAMA: str = "ollama" + OPENAI: str = "openai" diff --git a/app/requirements b/app/requirements index e69de29..22cb80b 100644 --- a/app/requirements +++ b/app/requirements @@ -0,0 +1,3 @@ +fastapi==0.115.8 +pydantic==2.10.6 +uvicorn==0.34.0 \ No newline at end of file From e8fd27885113d43d2c9f9fe6fd128607b9a40933 Mon Sep 17 00:00:00 2001 From: Jason Esterhuizen Date: Sat, 1 Feb 2025 23:01:25 +0200 Subject: [PATCH 3/6] [FEAT] Added app store --- app/components/ui/package-lock.json | 86 +++++++++++++++++++ app/components/ui/package.json | 10 ++- app/components/ui/src/app/api.urls.ts | 5 ++ app/components/ui/src/app/app.component.ts | 3 +- app/components/ui/src/app/app.config.ts | 13 ++- .../ui/src/app/models/app.models.ts | 3 + .../app/pages/settings/settings.service.ts | 0 .../pages/settings/store/settings.actions.ts | 0 .../pages/settings/store/settings.effects.ts | 0 .../pages/settings/store/settings.reducers.ts | 0 .../settings/store/settings.selectors.ts | 0 .../pages/settings/store/settings.state.ts | 0 .../ui/src/app/services/app.service.ts | 24 ++++++ .../ui/src/app/store/actions/app.actions.ts | 11 +++ .../ui/src/app/store/effects/app.effects.ts | 26 ++++++ .../ui/src/app/store/reducers/app.reducers.ts | 11 +++ .../src/app/store/selectors/app.selectors.ts | 5 ++ .../ui/src/app/store/state/app.state.ts | 17 ++++ .../ui/src/app/store/state/loadable.state.ts | 35 ++++++++ 19 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 app/components/ui/src/app/api.urls.ts create mode 100644 app/components/ui/src/app/models/app.models.ts create mode 100644 app/components/ui/src/app/pages/settings/settings.service.ts create mode 100644 app/components/ui/src/app/pages/settings/store/settings.actions.ts create mode 100644 app/components/ui/src/app/pages/settings/store/settings.effects.ts create mode 100644 app/components/ui/src/app/pages/settings/store/settings.reducers.ts create mode 100644 app/components/ui/src/app/pages/settings/store/settings.selectors.ts create mode 100644 app/components/ui/src/app/pages/settings/store/settings.state.ts create mode 100644 app/components/ui/src/app/services/app.service.ts create mode 100644 app/components/ui/src/app/store/actions/app.actions.ts create mode 100644 app/components/ui/src/app/store/effects/app.effects.ts create mode 100644 app/components/ui/src/app/store/reducers/app.reducers.ts create mode 100644 app/components/ui/src/app/store/selectors/app.selectors.ts create mode 100644 app/components/ui/src/app/store/state/app.state.ts create mode 100644 app/components/ui/src/app/store/state/loadable.state.ts diff --git a/app/components/ui/package-lock.json b/app/components/ui/package-lock.json index 5bfd994..54fac81 100644 --- a/app/components/ui/package-lock.json +++ b/app/components/ui/package-lock.json @@ -18,6 +18,12 @@ "@angular/platform-browser": "^19.1.0", "@angular/platform-browser-dynamic": "^19.1.0", "@angular/router": "^19.1.0", + "@ngrx/component": "^19.0.1", + "@ngrx/data": "^19.0.1", + "@ngrx/effects": "^19.0.1", + "@ngrx/entity": "^19.0.1", + "@ngrx/store": "^19.0.1", + "@ngrx/store-devtools": "^19.0.1", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" @@ -2768,6 +2774,86 @@ "node": ">= 10" } }, + "node_modules/@ngrx/component": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/component/-/component-19.0.1.tgz", + "integrity": "sha512-uuGgjB8eAcIj9IiaMUxbIqCHo++jcPPsV2zEiF0q6v8CY07wrCQnn02jxwY09eNCUnvXQiGfYosV2wIWF1gu5A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/data": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/data/-/data-19.0.1.tgz", + "integrity": "sha512-B8HVkBauCycRB9VlvpGovIbldnXrMz9tga0SUQa0tSTQ3IBYY3IEtHO7Q4X1LnCxxuIw8sR6guT+erBaURHDfg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@ngrx/effects": "19.0.1", + "@ngrx/entity": "19.0.1", + "@ngrx/store": "19.0.1", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/effects": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-19.0.1.tgz", + "integrity": "sha512-q+eztS1zN1247BtUZ41gxhumj4wMmvtfdSMfkFEuu6zuA57Vbx8zitEsw9boqPGtP5E4Cj5HKJLSJrl2kgwgcQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^19.0.0", + "@ngrx/store": "19.0.1", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/entity": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-19.0.1.tgz", + "integrity": "sha512-Dw6UhLi7tGVWb/pLgYI81k1fPxCIbCWMztGKj08e8fLWoMvTWYTbG5tFbOJNSa9D3gPmxsBbbS8VMNqcUgl7wQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^19.0.0", + "@ngrx/store": "19.0.1", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/store": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-19.0.1.tgz", + "integrity": "sha512-+6eBLb+0rdJ856JRuKnvSzFxv1ISbYuX/OM12dMPf4wm+ddxjhyvi6tF8lPiNnaYb717PGNxXQzBFIGfIs4zGQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^19.0.0", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/store-devtools": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-19.0.1.tgz", + "integrity": "sha512-afvr6NHh12LpYrOH9JKKEEi/z2DHq/wJ45hRn3mrcRDArQTKpTl7V2eu0dYgjGItSRSeJ2drzzKGjccL61PPSg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^19.0.0", + "@ngrx/store": "19.0.1", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, "node_modules/@ngtools/webpack": { "version": "19.1.5", "dev": true, diff --git a/app/components/ui/package.json b/app/components/ui/package.json index 0f77025..2722ef4 100644 --- a/app/components/ui/package.json +++ b/app/components/ui/package.json @@ -1,5 +1,5 @@ { - "name": "ui", + "name": "ACE", "version": "0.0.0", "scripts": { "ng": "ng", @@ -21,6 +21,12 @@ "@angular/platform-browser": "^19.1.0", "@angular/platform-browser-dynamic": "^19.1.0", "@angular/router": "^19.1.0", + "@ngrx/component": "^19.0.1", + "@ngrx/data": "^19.0.1", + "@ngrx/effects": "^19.0.1", + "@ngrx/entity": "^19.0.1", + "@ngrx/store": "^19.0.1", + "@ngrx/store-devtools": "^19.0.1", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" @@ -38,4 +44,4 @@ "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.7.2" } -} \ No newline at end of file +} diff --git a/app/components/ui/src/app/api.urls.ts b/app/components/ui/src/app/api.urls.ts new file mode 100644 index 0000000..38b1ad8 --- /dev/null +++ b/app/components/ui/src/app/api.urls.ts @@ -0,0 +1,5 @@ +const defaultClusterURL: string = `http://127.0.0.1`; + +export const serviceURLs = { + controller: defaultClusterURL + ":2349" +}; diff --git a/app/components/ui/src/app/app.component.ts b/app/components/ui/src/app/app.component.ts index 701580e..10bdc6e 100644 --- a/app/components/ui/src/app/app.component.ts +++ b/app/components/ui/src/app/app.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; +import { EffectsModule } from '@ngrx/effects'; +import { AppEffects } from './store/effects/app.effects'; import { ACESidebarComponent } from './components/sidebar/sidebar.component'; @Component({ diff --git a/app/components/ui/src/app/app.config.ts b/app/components/ui/src/app/app.config.ts index 96116fd..7fd8c73 100644 --- a/app/components/ui/src/app/app.config.ts +++ b/app/components/ui/src/app/app.config.ts @@ -1,9 +1,18 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; - +import { provideEffects } from '@ngrx/effects'; +import { provideStore } from '@ngrx/store'; import { routes } from './app.routes'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; +import { AppEffects } from './store/effects/app.effects'; +import { appReducer } from './store/reducers/app.reducers'; export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideAnimationsAsync()] + providers: [ + provideAnimationsAsync(), + provideEffects([AppEffects]), + provideStore({ app: appReducer }), + provideRouter(routes), + provideZoneChangeDetection({ eventCoalescing: true }) + ] }; diff --git a/app/components/ui/src/app/models/app.models.ts b/app/components/ui/src/app/models/app.models.ts new file mode 100644 index 0000000..ac57ffc --- /dev/null +++ b/app/components/ui/src/app/models/app.models.ts @@ -0,0 +1,3 @@ +export interface IACEVersionData { + version: string +} diff --git a/app/components/ui/src/app/pages/settings/settings.service.ts b/app/components/ui/src/app/pages/settings/settings.service.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ui/src/app/pages/settings/store/settings.actions.ts b/app/components/ui/src/app/pages/settings/store/settings.actions.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ui/src/app/pages/settings/store/settings.effects.ts b/app/components/ui/src/app/pages/settings/store/settings.effects.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ui/src/app/pages/settings/store/settings.reducers.ts b/app/components/ui/src/app/pages/settings/store/settings.reducers.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ui/src/app/pages/settings/store/settings.selectors.ts b/app/components/ui/src/app/pages/settings/store/settings.selectors.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ui/src/app/pages/settings/store/settings.state.ts b/app/components/ui/src/app/pages/settings/store/settings.state.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ui/src/app/services/app.service.ts b/app/components/ui/src/app/services/app.service.ts new file mode 100644 index 0000000..da1a9b7 --- /dev/null +++ b/app/components/ui/src/app/services/app.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { Observable } from 'rxjs/internal/Observable'; +import { serviceURLs } from "../api.urls"; + + +export type HttpListResponseFailure = { status: string, message: string }; + + +const endpoints = { + getACEVersionData: `${serviceURLs.controller}/version`, +}; + + +@Injectable({ + providedIn: "root" +}) +export class AppService { + constructor(private http: HttpClient) { } + + getACEVersionData(): Observable { + return this.http.get(endpoints.getACEVersionData); + } +} diff --git a/app/components/ui/src/app/store/actions/app.actions.ts b/app/components/ui/src/app/store/actions/app.actions.ts new file mode 100644 index 0000000..206ce72 --- /dev/null +++ b/app/components/ui/src/app/store/actions/app.actions.ts @@ -0,0 +1,11 @@ +import { createActionGroup, props, emptyProps } from "@ngrx/store"; +import { IACEVersionData } from "../../models/app.models"; + +export const appActions = createActionGroup({ + source: "app", + events: { + getACEVersionData: emptyProps(), + getACEVersionDataSuccess: props<{ versionData: IACEVersionData }>(), + getACEVersionDataFailure: emptyProps() + }, +}); diff --git a/app/components/ui/src/app/store/effects/app.effects.ts b/app/components/ui/src/app/store/effects/app.effects.ts new file mode 100644 index 0000000..45fb17f --- /dev/null +++ b/app/components/ui/src/app/store/effects/app.effects.ts @@ -0,0 +1,26 @@ +import { inject, Injectable } from "@angular/core"; +import { createEffect, ofType, Actions } from "@ngrx/effects"; +import { select, Store } from "@ngrx/store"; +import { map, catchError, of, switchMap, filter, withLatestFrom, Observable, throwError } from "rxjs"; +import { appActions } from "../actions/app.actions"; +import { IACEVersionData } from "../../models/app.models"; +import { AppService } from "../../services/app.service"; + + +@Injectable() +export class AppEffects { + private actions$ = inject(Actions); + private store$ = inject(Store); + + getACEVersionData$ = createEffect(() => this.actions$.pipe( + ofType(appActions.getACEVersionData), + switchMap(() => this.appService.getACEVersionData().pipe( + map((versionData: IACEVersionData) => appActions.getACEVersionDataSuccess({ versionData })), + catchError(() => of(appActions.getACEVersionDataFailure())) + )) + )) + + constructor( + private appService: AppService + ) { } +} diff --git a/app/components/ui/src/app/store/reducers/app.reducers.ts b/app/components/ui/src/app/store/reducers/app.reducers.ts new file mode 100644 index 0000000..e046933 --- /dev/null +++ b/app/components/ui/src/app/store/reducers/app.reducers.ts @@ -0,0 +1,11 @@ +import { createReducer, on } from "@ngrx/store"; +import { onLoadableError, onLoadableLoad, onLoadableSuccess } from "../state/loadable.state"; +import { appActions } from "../actions/app.actions"; +import { createInitialAppState } from "../state/app.state"; + +export const appReducer = createReducer( + createInitialAppState(), + on(appActions.getACEVersionData, state => ({...onLoadableLoad(state)})), + on(appActions.getACEVersionDataSuccess, (state, { versionData }) => ({...onLoadableSuccess(state), versionData: {...versionData}})), + on(appActions.getACEVersionDataFailure, state => ({...onLoadableError(state, "Error getting ace version data")})), +) diff --git a/app/components/ui/src/app/store/selectors/app.selectors.ts b/app/components/ui/src/app/store/selectors/app.selectors.ts new file mode 100644 index 0000000..0a27133 --- /dev/null +++ b/app/components/ui/src/app/store/selectors/app.selectors.ts @@ -0,0 +1,5 @@ +import { createSelector, createFeatureSelector } from "@ngrx/store"; +import { IAppState } from "../state/app.state"; + +export const selectAppState = createFeatureSelector("app"); +export const selectACEVersionData = createSelector(selectAppState, (state: IAppState) => state.versionData); diff --git a/app/components/ui/src/app/store/state/app.state.ts b/app/components/ui/src/app/store/state/app.state.ts new file mode 100644 index 0000000..40159f7 --- /dev/null +++ b/app/components/ui/src/app/store/state/app.state.ts @@ -0,0 +1,17 @@ +import { createDefaultLoadable, Loadable } from "./loadable.state"; +import { IACEVersionData } from "../../models/app.models"; + +export interface IAppState extends Loadable { + versionData: IACEVersionData; +} + +export function createInitialAppState(): IAppState { + return { + ...createDefaultLoadable(), + versionData: { + version: "0" + } + } +} + + diff --git a/app/components/ui/src/app/store/state/loadable.state.ts b/app/components/ui/src/app/store/state/loadable.state.ts new file mode 100644 index 0000000..920f398 --- /dev/null +++ b/app/components/ui/src/app/store/state/loadable.state.ts @@ -0,0 +1,35 @@ +export interface Loadable { + loading: boolean; + error: any; +} + +export function createDefaultLoadable(): Loadable { + return { + loading: false, + error: null, + }; +} + +export function onLoadableLoad(loadable: T): T { + return { + ...(loadable as any), + loading: true, + error: null, + } as T; +} + +export function onLoadableSuccess(loadable: T): T { + return { + ...(loadable as any), + loading: false, + error: null, + } as T; +} + +export function onLoadableError(loadable: T, error: any): T { + return { + ...(loadable as any), + loading: false, + error: error, + } as T; +} From 9b6bfcece0b3cff95a8c007a074c0b16e9fd5a06 Mon Sep 17 00:00:00 2001 From: Jason Esterhuizen Date: Sun, 2 Feb 2025 00:17:25 +0200 Subject: [PATCH 4/6] [FEAT] Added footer --- app/components/controller/api/routes.py | 8 ++++ app/components/ui/src/app/app.component.ts | 24 ++++++---- app/components/ui/src/app/app.config.ts | 9 +++- .../components/footer/footer.component.html | 6 +++ .../components/footer/footer.component.scss | 8 ++++ .../app/components/footer/footer.component.ts | 23 ++++++++++ .../components/sidebar/sidebar.component.html | 44 ++++++++++--------- .../components/sidebar/sidebar.component.scss | 28 +++++++----- .../components/sidebar/sidebar.component.ts | 2 + .../ui/src/app/store/actions/app.actions.ts | 2 +- .../ui/src/app/store/effects/app.effects.ts | 6 +-- .../ui/src/app/store/reducers/app.reducers.ts | 2 +- .../src/app/store/selectors/app.selectors.ts | 6 +-- .../ui/src/app/store/state/app.state.ts | 4 +- 14 files changed, 121 insertions(+), 51 deletions(-) create mode 100644 app/components/ui/src/app/components/footer/footer.component.html create mode 100644 app/components/ui/src/app/components/footer/footer.component.scss create mode 100644 app/components/ui/src/app/components/footer/footer.component.ts diff --git a/app/components/controller/api/routes.py b/app/components/controller/api/routes.py index 88f426e..8e54830 100644 --- a/app/components/controller/api/routes.py +++ b/app/components/controller/api/routes.py @@ -1,6 +1,7 @@ # DEPENDENCIES ## Third-Party from fastapi import FastAPI, HTTPException +from fastapi.middleware.cors import CORSMiddleware from http import HTTPStatus from pydantic import ValidationError ## Local @@ -14,6 +15,13 @@ controller_api = FastAPI() +controller_api.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:4200"], # Allow requests from your Angular app + allow_credentials=True, + allow_methods=["*"], # Allow all HTTP methods + allow_headers=["*"], # Allow all headers +) # ROUTES diff --git a/app/components/ui/src/app/app.component.ts b/app/components/ui/src/app/app.component.ts index 10bdc6e..e754689 100644 --- a/app/components/ui/src/app/app.component.ts +++ b/app/components/ui/src/app/app.component.ts @@ -1,16 +1,22 @@ -import { Component } from '@angular/core'; -import { EffectsModule } from '@ngrx/effects'; -import { AppEffects } from './store/effects/app.effects'; -import { ACESidebarComponent } from './components/sidebar/sidebar.component'; +import { Component, OnInit } from "@angular/core"; +import { Store } from "@ngrx/store"; +import { appActions } from "./store/actions/app.actions"; +import { ACESidebarComponent } from "./components/sidebar/sidebar.component"; @Component({ - selector: 'app-root', + selector: "app-root", imports: [ ACESidebarComponent ], - templateUrl: './app.component.html', - styleUrl: './app.component.scss' + templateUrl: "./app.component.html", + styleUrl: "./app.component.scss" }) -export class AppComponent { - title = 'ACE'; +export class AppComponent implements OnInit { + title = "ACE"; + + constructor(private store: Store) {} + + ngOnInit(): void { + this.store.dispatch(appActions.getACEVersionData()); + } } diff --git a/app/components/ui/src/app/app.config.ts b/app/components/ui/src/app/app.config.ts index 7fd8c73..f5521d8 100644 --- a/app/components/ui/src/app/app.config.ts +++ b/app/components/ui/src/app/app.config.ts @@ -1,7 +1,9 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideHttpClient } from '@angular/common/http'; import { provideRouter } from '@angular/router'; import { provideEffects } from '@ngrx/effects'; import { provideStore } from '@ngrx/store'; +import { provideStoreDevtools } from '@ngrx/store-devtools'; import { routes } from './app.routes'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { AppEffects } from './store/effects/app.effects'; @@ -11,7 +13,12 @@ export const appConfig: ApplicationConfig = { providers: [ provideAnimationsAsync(), provideEffects([AppEffects]), - provideStore({ app: appReducer }), + provideHttpClient(), + provideStore({ app_data: appReducer }), + provideStoreDevtools({ + maxAge: 25, + logOnly: false + }), provideRouter(routes), provideZoneChangeDetection({ eventCoalescing: true }) ] diff --git a/app/components/ui/src/app/components/footer/footer.component.html b/app/components/ui/src/app/components/footer/footer.component.html new file mode 100644 index 0000000..e7400a7 --- /dev/null +++ b/app/components/ui/src/app/components/footer/footer.component.html @@ -0,0 +1,6 @@ +
+

Developed by JayFalls

+

Version: v{{ version }}

+
+ + diff --git a/app/components/ui/src/app/components/footer/footer.component.scss b/app/components/ui/src/app/components/footer/footer.component.scss new file mode 100644 index 0000000..e0ae1fa --- /dev/null +++ b/app/components/ui/src/app/components/footer/footer.component.scss @@ -0,0 +1,8 @@ +.footer { + display: flex; + align-items: center; + justify-content: center; + height: 2rem; + gap: 2rem; + outline: auto; +} diff --git a/app/components/ui/src/app/components/footer/footer.component.ts b/app/components/ui/src/app/components/footer/footer.component.ts new file mode 100644 index 0000000..8c4f14b --- /dev/null +++ b/app/components/ui/src/app/components/footer/footer.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { AppState } from '../../store/state/app.state'; +import { selectAppState } from '../../store/selectors/app.selectors'; + +@Component({ + selector: 'ace-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'] +}) +export class ACEFooterComponent implements OnInit { + versionData$: Observable; + version: string = "0"; + + constructor(private store: Store) { + this.versionData$ = this.store.select(selectAppState); + } + + ngOnInit(): void { + this.versionData$.subscribe( versionData => this.version = versionData.versionData.version); + } +} diff --git a/app/components/ui/src/app/components/sidebar/sidebar.component.html b/app/components/ui/src/app/components/sidebar/sidebar.component.html index ce3f6cb..1b8b127 100644 --- a/app/components/ui/src/app/components/sidebar/sidebar.component.html +++ b/app/components/ui/src/app/components/sidebar/sidebar.component.html @@ -1,21 +1,25 @@ - - - - @for (item of sidebarItems(); track item.name) { - - - {{ item.icon }} - - - } - - +
+ + + + @for (item of sidebarItems(); track item.name) { + + + {{ item.icon }} + + + } + + - - - - + + + + + + +
diff --git a/app/components/ui/src/app/components/sidebar/sidebar.component.scss b/app/components/ui/src/app/components/sidebar/sidebar.component.scss index 9eab438..04524b9 100644 --- a/app/components/ui/src/app/components/sidebar/sidebar.component.scss +++ b/app/components/ui/src/app/components/sidebar/sidebar.component.scss @@ -1,18 +1,24 @@ -.sidebar-root { +.page-root { + display: flex; + flex-direction: column; height: 100%; -} -.sidebar { - width: 3.5rem; - display: grid; - align-content: center; - outline: auto; + .sidebar-root { + height: 100%; + + .sidebar { + width: 3.5rem; + display: grid; + align-content: center; + outline: auto; - .sidebar-item { - margin-bottom: 1rem; + .sidebar-item { + margin-bottom: 1rem; - .active-link { - background-color: rgba(0, 0, 0, 0.04); + .active-link { + background-color: rgba(0, 0, 0, 0.04); + } + } } } } diff --git a/app/components/ui/src/app/components/sidebar/sidebar.component.ts b/app/components/ui/src/app/components/sidebar/sidebar.component.ts index 84384c7..7b0793e 100644 --- a/app/components/ui/src/app/components/sidebar/sidebar.component.ts +++ b/app/components/ui/src/app/components/sidebar/sidebar.component.ts @@ -5,6 +5,7 @@ import { MatListModule } from "@angular/material/list"; import { MatTooltipModule } from "@angular/material/tooltip"; import { MatSidenavModule } from "@angular/material/sidenav"; import { RouterModule, RouterOutlet } from "@angular/router"; +import { ACEFooterComponent } from "../footer/footer.component"; export type SidebarItem = { @@ -19,6 +20,7 @@ export type SidebarItem = { templateUrl: "sidebar.component.html", styleUrl: "sidebar.component.scss", imports: [ + ACEFooterComponent, MatButtonModule, MatIconModule, MatListModule, diff --git a/app/components/ui/src/app/store/actions/app.actions.ts b/app/components/ui/src/app/store/actions/app.actions.ts index 206ce72..35b306d 100644 --- a/app/components/ui/src/app/store/actions/app.actions.ts +++ b/app/components/ui/src/app/store/actions/app.actions.ts @@ -6,6 +6,6 @@ export const appActions = createActionGroup({ events: { getACEVersionData: emptyProps(), getACEVersionDataSuccess: props<{ versionData: IACEVersionData }>(), - getACEVersionDataFailure: emptyProps() + getACEVersionDataFailure: props<{ error: Error }>() }, }); diff --git a/app/components/ui/src/app/store/effects/app.effects.ts b/app/components/ui/src/app/store/effects/app.effects.ts index 45fb17f..8de462e 100644 --- a/app/components/ui/src/app/store/effects/app.effects.ts +++ b/app/components/ui/src/app/store/effects/app.effects.ts @@ -1,7 +1,7 @@ import { inject, Injectable } from "@angular/core"; import { createEffect, ofType, Actions } from "@ngrx/effects"; -import { select, Store } from "@ngrx/store"; -import { map, catchError, of, switchMap, filter, withLatestFrom, Observable, throwError } from "rxjs"; +import { Store } from "@ngrx/store"; +import { map, catchError, of, switchMap } from "rxjs"; import { appActions } from "../actions/app.actions"; import { IACEVersionData } from "../../models/app.models"; import { AppService } from "../../services/app.service"; @@ -16,7 +16,7 @@ export class AppEffects { ofType(appActions.getACEVersionData), switchMap(() => this.appService.getACEVersionData().pipe( map((versionData: IACEVersionData) => appActions.getACEVersionDataSuccess({ versionData })), - catchError(() => of(appActions.getACEVersionDataFailure())) + catchError(error => of(appActions.getACEVersionDataFailure({ error }))) )) )) diff --git a/app/components/ui/src/app/store/reducers/app.reducers.ts b/app/components/ui/src/app/store/reducers/app.reducers.ts index e046933..27458f4 100644 --- a/app/components/ui/src/app/store/reducers/app.reducers.ts +++ b/app/components/ui/src/app/store/reducers/app.reducers.ts @@ -7,5 +7,5 @@ export const appReducer = createReducer( createInitialAppState(), on(appActions.getACEVersionData, state => ({...onLoadableLoad(state)})), on(appActions.getACEVersionDataSuccess, (state, { versionData }) => ({...onLoadableSuccess(state), versionData: {...versionData}})), - on(appActions.getACEVersionDataFailure, state => ({...onLoadableError(state, "Error getting ace version data")})), + on(appActions.getACEVersionDataFailure, (state, { error }) => ({...onLoadableError(state, error)})) ) diff --git a/app/components/ui/src/app/store/selectors/app.selectors.ts b/app/components/ui/src/app/store/selectors/app.selectors.ts index 0a27133..e2b001e 100644 --- a/app/components/ui/src/app/store/selectors/app.selectors.ts +++ b/app/components/ui/src/app/store/selectors/app.selectors.ts @@ -1,5 +1,5 @@ import { createSelector, createFeatureSelector } from "@ngrx/store"; -import { IAppState } from "../state/app.state"; +import { AppState } from "../state/app.state"; -export const selectAppState = createFeatureSelector("app"); -export const selectACEVersionData = createSelector(selectAppState, (state: IAppState) => state.versionData); +export const selectAppState = createFeatureSelector("app_data"); +export const selectACEVersionData = createSelector(selectAppState, (state: AppState) => state.versionData); diff --git a/app/components/ui/src/app/store/state/app.state.ts b/app/components/ui/src/app/store/state/app.state.ts index 40159f7..1c2859c 100644 --- a/app/components/ui/src/app/store/state/app.state.ts +++ b/app/components/ui/src/app/store/state/app.state.ts @@ -1,11 +1,11 @@ import { createDefaultLoadable, Loadable } from "./loadable.state"; import { IACEVersionData } from "../../models/app.models"; -export interface IAppState extends Loadable { +export interface AppState extends Loadable { versionData: IACEVersionData; } -export function createInitialAppState(): IAppState { +export function createInitialAppState(): AppState { return { ...createDefaultLoadable(), versionData: { From df6239f3788ed72f64f8f6aa9fe56ff1d249599c Mon Sep 17 00:00:00 2001 From: Jason Esterhuizen Date: Sun, 2 Feb 2025 00:34:23 +0200 Subject: [PATCH 5/6] [REFACT] Fixed styliing --- app/components/ui/src/app/app.component.html | 2 +- app/components/ui/src/app/app.component.ts | 4 ++-- .../rootpage.component.html} | 0 .../rootpage.component.scss} | 1 + .../rootpage.component.ts} | 8 ++++---- 5 files changed, 8 insertions(+), 7 deletions(-) rename app/components/ui/src/app/components/{sidebar/sidebar.component.html => rootpage/rootpage.component.html} (100%) rename app/components/ui/src/app/components/{sidebar/sidebar.component.scss => rootpage/rootpage.component.scss} (93%) rename app/components/ui/src/app/components/{sidebar/sidebar.component.ts => rootpage/rootpage.component.ts} (89%) diff --git a/app/components/ui/src/app/app.component.html b/app/components/ui/src/app/app.component.html index 9e8a8ca..c2c1903 100644 --- a/app/components/ui/src/app/app.component.html +++ b/app/components/ui/src/app/app.component.html @@ -1 +1 @@ - + diff --git a/app/components/ui/src/app/app.component.ts b/app/components/ui/src/app/app.component.ts index e754689..a1b53d1 100644 --- a/app/components/ui/src/app/app.component.ts +++ b/app/components/ui/src/app/app.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from "@angular/core"; import { Store } from "@ngrx/store"; import { appActions } from "./store/actions/app.actions"; -import { ACESidebarComponent } from "./components/sidebar/sidebar.component"; +import { ACERootpageComponent } from "./components/rootpage/rootpage.component"; @Component({ selector: "app-root", imports: [ - ACESidebarComponent + ACERootpageComponent ], templateUrl: "./app.component.html", styleUrl: "./app.component.scss" diff --git a/app/components/ui/src/app/components/sidebar/sidebar.component.html b/app/components/ui/src/app/components/rootpage/rootpage.component.html similarity index 100% rename from app/components/ui/src/app/components/sidebar/sidebar.component.html rename to app/components/ui/src/app/components/rootpage/rootpage.component.html diff --git a/app/components/ui/src/app/components/sidebar/sidebar.component.scss b/app/components/ui/src/app/components/rootpage/rootpage.component.scss similarity index 93% rename from app/components/ui/src/app/components/sidebar/sidebar.component.scss rename to app/components/ui/src/app/components/rootpage/rootpage.component.scss index 04524b9..859e941 100644 --- a/app/components/ui/src/app/components/sidebar/sidebar.component.scss +++ b/app/components/ui/src/app/components/rootpage/rootpage.component.scss @@ -11,6 +11,7 @@ display: grid; align-content: center; outline: auto; + border-radius: 0; .sidebar-item { margin-bottom: 1rem; diff --git a/app/components/ui/src/app/components/sidebar/sidebar.component.ts b/app/components/ui/src/app/components/rootpage/rootpage.component.ts similarity index 89% rename from app/components/ui/src/app/components/sidebar/sidebar.component.ts rename to app/components/ui/src/app/components/rootpage/rootpage.component.ts index 7b0793e..b031f09 100644 --- a/app/components/ui/src/app/components/sidebar/sidebar.component.ts +++ b/app/components/ui/src/app/components/rootpage/rootpage.component.ts @@ -16,9 +16,9 @@ export type SidebarItem = { @Component({ - selector: "ace-sidebar", - templateUrl: "sidebar.component.html", - styleUrl: "sidebar.component.scss", + selector: "ace-rootpage", + templateUrl: "rootpage.component.html", + styleUrl: "rootpage.component.scss", imports: [ ACEFooterComponent, MatButtonModule, @@ -30,7 +30,7 @@ export type SidebarItem = { RouterOutlet ], }) -export class ACESidebarComponent { +export class ACERootpageComponent { sidebarItems = signal([ { name: "Home", From c41adab6472fac4b32d3466d4f6f77ba9803c4f4 Mon Sep 17 00:00:00 2001 From: Jason Esterhuizen Date: Sun, 2 Feb 2025 00:36:35 +0200 Subject: [PATCH 6/6] [BUG] Fixed auto tests --- ace | 1 + 1 file changed, 1 insertion(+) diff --git a/ace b/ace index 1109cc1..ad3268d 100755 --- a/ace +++ b/ace @@ -7,6 +7,7 @@ ACE_LOGGER_VERBOSE_ENV="." # STARTUP run_tests() { echo "Installing/Updating test dependencies..." + pip install --upgrade -r app/requirements pip install --upgrade -r tests/requirements python -m pytest tests/unit/ -v