diff --git a/hermes-console/json-server/db.json b/hermes-console/json-server/db.json
index 23dab13ee0..da34651d34 100644
--- a/hermes-console/json-server/db.json
+++ b/hermes-console/json-server/db.json
@@ -581,7 +581,17 @@
"title": "hermes console",
"contactLink": "https://google.com",
"environmentName": "LOCAL",
- "criticalEnvironment": false
+ "criticalEnvironment": false,
+ "knownEnvironments": [
+ {
+ "name": "local",
+ "url": "localhost:5173"
+ },
+ {
+ "name": "also-local",
+ "url": "127.0.0.1:5173"
+ }
+ ]
},
"dashboard": {
"metrics": "http://localhost:8082",
diff --git a/hermes-console/src/api/app-configuration.ts b/hermes-console/src/api/app-configuration.ts
index e1eb50b32f..1d21baea5a 100644
--- a/hermes-console/src/api/app-configuration.ts
+++ b/hermes-console/src/api/app-configuration.ts
@@ -17,6 +17,12 @@ export interface ConsoleConfiguration {
contactLink: string;
environmentName: string;
criticalEnvironment: boolean;
+ knownEnvironments: ConsoleEnvironment[];
+}
+
+export interface ConsoleEnvironment {
+ name: string;
+ url: string;
}
export interface DashboardConfiguration {
diff --git a/hermes-console/src/components/console-header/ConsoleHeader.vue b/hermes-console/src/components/console-header/ConsoleHeader.vue
index f03dd11218..d132aefa3b 100644
--- a/hermes-console/src/components/console-header/ConsoleHeader.vue
+++ b/hermes-console/src/components/console-header/ConsoleHeader.vue
@@ -6,6 +6,7 @@
import { useRouter } from 'vue-router';
import { useTheme } from 'vuetify';
import EnvironmentBadge from '@/components/environment-badge/EnviromentBadge.vue';
+ import EnvironmentSwitch from '@/components/environment-switch/EnvironmentSwitch.vue';
import ThemeSwitch from '@/components/theme-switch/ThemeSwitch.vue';
const { t } = useI18n();
@@ -17,6 +18,9 @@
const authStore = useAuthStore();
const isLoggedIn = computed(() => authStore.isUserAuthorized);
+ const knownEnvironments = computed(
+ () => configStore.appConfig?.console.knownEnvironments,
+ );
function logIn() {
authStore.login(window.location.pathname);
@@ -57,6 +61,8 @@
configStore.appConfig?.console.criticalEnvironment || false
"
/>
+
+
diff --git a/hermes-console/src/components/environment-switch/EnvironmentSwitch.spec.ts b/hermes-console/src/components/environment-switch/EnvironmentSwitch.spec.ts
new file mode 100644
index 0000000000..7949db6788
--- /dev/null
+++ b/hermes-console/src/components/environment-switch/EnvironmentSwitch.spec.ts
@@ -0,0 +1,85 @@
+import { expect } from 'vitest';
+import { fireEvent } from '@testing-library/vue';
+import { render } from '@/utils/test-utils';
+import EnvironmentSwitch from '@/components/environment-switch/EnvironmentSwitch.vue';
+
+const mockReplace = vi.fn();
+const mockHref = vi.fn();
+
+Object.defineProperty(window, 'location', {
+ value: {
+ get href() {
+ return mockHref();
+ },
+ replace: mockReplace,
+ },
+});
+
+const TEST_URL_ENV_1 =
+ 'http://localhost:3000/ui/groups/pl.example.hermes/topics/pl.example.hermes.TemperatureChanged';
+const TEST_URL_ENV_2 =
+ 'http://127.0.0.1:3000/ui/groups/pl.example.hermes/topics/pl.example.hermes.TemperatureChanged';
+
+describe('EnvironmentSwitch', () => {
+ it('should highlight the button for the selected environment', () => {
+ // given
+ mockHref.mockReturnValue(TEST_URL_ENV_1);
+
+ // when
+ const { getByText } = render(EnvironmentSwitch, {
+ props: {
+ knownEnvironments: [
+ {
+ name: 'env1',
+ url: 'localhost:3000',
+ },
+ {
+ name: 'env2',
+ url: '127.0.0.1:3000',
+ },
+ ],
+ },
+ });
+
+ // then
+ expect(location.href).toBe(
+ 'http://localhost:3000/ui/groups/pl.example.hermes/topics/pl.example.hermes.TemperatureChanged',
+ );
+ expect(getByText('env1')).toBeVisible();
+ expect(getByText('env2')).toBeVisible();
+ expect(getByText('env1').closest('button')).toHaveClass('v-btn--active', {
+ exact: false,
+ });
+ expect(getByText('env2').closest('button')).not.toHaveClass(
+ 'v-btn--active',
+ { exact: false },
+ );
+ });
+
+ it('should switch between urls without changing the rest of the path', async () => {
+ // given
+ mockHref.mockReturnValue(TEST_URL_ENV_1);
+
+ // and
+ const { getByText } = render(EnvironmentSwitch, {
+ props: {
+ knownEnvironments: [
+ {
+ name: 'env1',
+ url: 'localhost:3000',
+ },
+ {
+ name: 'env2',
+ url: '127.0.0.1:3000',
+ },
+ ],
+ },
+ });
+
+ // when
+ await fireEvent.click(getByText('env2').closest('button'));
+
+ // then
+ expect(mockReplace).toHaveBeenCalledWith(TEST_URL_ENV_2);
+ });
+});
diff --git a/hermes-console/src/components/environment-switch/EnvironmentSwitch.vue b/hermes-console/src/components/environment-switch/EnvironmentSwitch.vue
new file mode 100644
index 0000000000..20374d549a
--- /dev/null
+++ b/hermes-console/src/components/environment-switch/EnvironmentSwitch.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+ {{ env.name }}
+
+
+
+
+
diff --git a/hermes-console/src/dummy/app-config.ts b/hermes-console/src/dummy/app-config.ts
index a5166433e7..93cef84ef3 100644
--- a/hermes-console/src/dummy/app-config.ts
+++ b/hermes-console/src/dummy/app-config.ts
@@ -5,7 +5,7 @@ export const dummyAppConfig: AppConfiguration = {
title: 'hermes console',
contactLink: '',
environmentName: 'local',
- criticalEnvironment: false,
+ criticalEnvironment: true,
},
dashboard: {
metrics: '',
diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/console/ConsoleProperties.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/console/ConsoleProperties.java
index c36fe397b9..1a58ab283a 100644
--- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/console/ConsoleProperties.java
+++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/console/ConsoleProperties.java
@@ -98,6 +98,8 @@ public static final class Console {
private boolean criticalEnvironment = false;
+ private List knownEnvironments = Collections.emptyList();
+
public String getTitle() {
return title;
}
@@ -129,6 +131,35 @@ public String getEnvironmentName() {
public void setEnvironmentName(String environmentName) {
this.environmentName = environmentName;
}
+
+ public List getKnownEnvironments() {
+ return knownEnvironments;
+ }
+
+ public void setKnownEnvironments(List knownEnvironments) {
+ this.knownEnvironments = knownEnvironments;
+ }
+ }
+
+ public static final class ConsoleEnvironment {
+ private String name;
+ private String url;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
}
public Owner getOwner() {
diff --git a/hermes-management/src/main/resources/application-local.yaml b/hermes-management/src/main/resources/application-local.yaml
index 845e296a4a..f643c3da20 100644
--- a/hermes-management/src/main/resources/application-local.yaml
+++ b/hermes-management/src/main/resources/application-local.yaml
@@ -1,6 +1,11 @@
console:
console:
title: hermes console
+ knownEnvironments:
+ - name: localhost
+ url: http://localhost:8090
+ - name: also-localhost
+ url: http://127.0.0.1:8090
dashboard:
metrics: http://localhost:8082
docs: http://hermes-pubsub.rtfd.org
@@ -51,4 +56,4 @@ spring:
order: 2147483647
mvc:
servlet:
- path: /
\ No newline at end of file
+ path: /
diff --git a/hermes-management/src/main/resources/console/config-local.json b/hermes-management/src/main/resources/console/config-local.json
index 5404d7ec4f..2944b4e6b2 100644
--- a/hermes-management/src/main/resources/console/config-local.json
+++ b/hermes-management/src/main/resources/console/config-local.json
@@ -1,6 +1,16 @@
{
"console": {
- "title": "hermes console"
+ "title": "hermes console",
+ "knownEnvironments": [
+ {
+ "name": "local",
+ "url": "localhost:8090"
+ },
+ {
+ "name": "also-local",
+ "url": "127.0.0.1:8090"
+ }
+ ]
},
"dashboard": {
"metrics": "http://localhost:8082",