diff --git a/backend/capellacollab/navbar/routes.py b/backend/capellacollab/navbar/routes.py
index 267ba4b5a9..c860e124db 100644
--- a/backend/capellacollab/navbar/routes.py
+++ b/backend/capellacollab/navbar/routes.py
@@ -4,9 +4,14 @@
import fastapi
from sqlalchemy import orm
-from capellacollab.core import database
+from capellacollab.core import (
+ CLUSTER_DEVELOPMENT_MODE,
+ LOCAL_DEVELOPMENT_MODE,
+ database,
+)
from capellacollab.settings.configuration import core as config_core
from capellacollab.settings.configuration import models as config_models
+from capellacollab.settings.configuration.models import BadgeVariant
router = fastapi.APIRouter()
@@ -18,6 +23,22 @@
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()
- )
+ if cfg.navbar.badge.show:
+ if cfg.navbar.badge.text == "auto":
+ if CLUSTER_DEVELOPMENT_MODE:
+ cfg.navbar.badge.text = "Cluster Development"
+ elif LOCAL_DEVELOPMENT_MODE:
+ cfg.navbar.badge.text = "Local Development"
+ else:
+ cfg.navbar.badge.text = (
+ cfg.metadata.environment or "Unknown Environment"
+ )
+
+ if cfg.navbar.badge.variant == BadgeVariant.AUTO:
+ words = ["dev", "development", "unknown", "staging"]
+ if any(word in cfg.navbar.badge.text.lower() for word in words):
+ cfg.navbar.badge.variant = BadgeVariant.WARNING
+ else:
+ cfg.navbar.badge.variant = BadgeVariant.SUCCESS
+
+ return cfg.navbar
diff --git a/backend/capellacollab/settings/configuration/models.py b/backend/capellacollab/settings/configuration/models.py
index c1cbc1d03f..ef92af9822 100644
--- a/backend/capellacollab/settings/configuration/models.py
+++ b/backend/capellacollab/settings/configuration/models.py
@@ -12,7 +12,7 @@
from sqlalchemy import orm
from capellacollab import core
-from capellacollab.core import database
+from capellacollab.core import DEVELOPMENT_MODE, database
from capellacollab.core import pydantic as core_pydantic
from capellacollab.users import models as users_models
@@ -69,6 +69,27 @@ class CustomNavbarLink(NavbarLink):
)
+class BadgeVariant(str, enum.Enum):
+ AUTO = "auto"
+ WARNING = "warning"
+ SUCCESS = "success"
+
+
+class Badge(core_pydantic.BaseModelStrict):
+ show: bool = pydantic.Field(
+ default=True,
+ description="Show a badge with the current environment.",
+ )
+ variant: BadgeVariant = pydantic.Field(
+ default=BadgeVariant.AUTO,
+ description="Color of the badge.",
+ )
+ text: str | t.Literal["auto"] = pydantic.Field(
+ default="auto",
+ description="Text to display in the badge. Use 'auto' to display the environment name.",
+ )
+
+
class NavbarConfiguration(core_pydantic.BaseModelStrict):
external_links: collections_abc.Sequence[
BuiltInNavbarLink | CustomNavbarLink
@@ -105,6 +126,14 @@ class NavbarConfiguration(core_pydantic.BaseModelStrict):
),
description="Links to display in the navigation bar.",
)
+ logo_url: str | None = pydantic.Field(
+ default=None,
+ description="URL to a logo to display in the navigation bar.",
+ )
+ badge: Badge = pydantic.Field(
+ default=Badge(show=DEVELOPMENT_MODE),
+ description="Badge to display in the navigation bar.",
+ )
class FeedbackIntervalConfiguration(core_pydantic.BaseModelStrict):
diff --git a/docs/docs/admin/configure-for-your-org.md b/docs/docs/admin/configure-for-your-org.md
index c1adc2ee66..0ad80cf3d6 100644
--- a/docs/docs/admin/configure-for-your-org.md
+++ b/docs/docs/admin/configure-for-your-org.md
@@ -27,11 +27,11 @@ metadata:
environment: '-'
```
-## Navigation Bar
+## Logo and Navigation Bar
-You can edit the links in the navigation bar. This can be useful if you want to
-link to external resources or if you are not using the default monitoring
-setup.
+You can edit the logo, badge, and links in the navigation bar. This can be
+useful to brand the Collaboration Manager for your organization, remind users
+which environment they are in, or link to external resources.
```yaml
navbar:
@@ -45,6 +45,11 @@ navbar:
- name: Documentation
service: documentation
role: user
+ logo_url: null
+ badge:
+ show: true
+ variant: auto
+ text: auto
```
In addition to the default service links, you can add your own by using `href`
@@ -63,6 +68,15 @@ hide the link from users without the appropriate role, it is not a security
feature, and you should make sure that the linked service enforces the
necessary access controls.
+To show the logo in the navigation bar, set the `logo_url` field to the URL of
+the image you want to use.
+
+The badge can be used to show the environment the user is in. The `variant`
+field can be set to `auto` (it will be determined by the environment),
+`success`, or `warning`. The `text` field will use the environment name if set
+to `auto`, or you can specify a custom text. If you don't want to show the
+badge, set `show` to `false`.
+
## Feedback
!!! info "Configure SMTP server for feedback"
diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts
index 0f2f946b44..368042f87e 100644
--- a/frontend/.storybook/main.ts
+++ b/frontend/.storybook/main.ts
@@ -23,6 +23,7 @@ const config: StorybookConfig = {
docs: {
autodocs: 'tag',
},
+ staticDirs: [{ from: './test-assets', to: '/test-assets' }],
core: {
disableTelemetry: true,
enableCrashReports: false,
diff --git a/frontend/.storybook/test-assets/narrow_logo.svg b/frontend/.storybook/test-assets/narrow_logo.svg
new file mode 100644
index 0000000000..2efe7e65f2
--- /dev/null
+++ b/frontend/.storybook/test-assets/narrow_logo.svg
@@ -0,0 +1,9 @@
+
+
+
diff --git a/frontend/.storybook/test-assets/wide_logo.svg b/frontend/.storybook/test-assets/wide_logo.svg
new file mode 100644
index 0000000000..f338a4794e
--- /dev/null
+++ b/frontend/.storybook/test-assets/wide_logo.svg
@@ -0,0 +1,9 @@
+
+
+
diff --git a/frontend/src/app/general/header/header.component.html b/frontend/src/app/general/header/header.component.html
index eff6ada2e7..49e40531cd 100644
--- a/frontend/src/app/general/header/header.component.html
+++ b/frontend/src/app/general/header/header.component.html
@@ -17,11 +17,10 @@