Skip to content

Commit

Permalink
Merge branch 'master' into SKYEDEN-3271-KafkaConumerGroupDeletion-V2
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcinBobinski authored Jan 8, 2025
2 parents 3e3b4ec + 829b93a commit effb792
Show file tree
Hide file tree
Showing 18 changed files with 295 additions and 2 deletions.
5 changes: 5 additions & 0 deletions docs/docs/configuration/message-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,8 @@ LogRepository logRepository(Client client) {
return new ElasticsearchLogRepository(client);
}
```

### UI configuration
Ui console can be configured to show tracking urls to users for topics and subscriptions.
To enable this, make bean implementing `pl.allegro.tech.hermes.tracker.management.TrackingUrlProvider`
available in Spring context.
12 changes: 10 additions & 2 deletions hermes-console/json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
},
"jsonToAvroDryRun": false,
"ack": "LEADER",
"trackingEnabled": false,
"trackingEnabled": true,
"migratedFromJsonType": false,
"schemaIdAwareSerializationEnabled": false,
"contentType": "AVRO",
Expand Down Expand Up @@ -251,6 +251,14 @@
"throughput": "0.0"
}
],
"topicsTrackingUrls": [
{"name": "Tracking Link 1", "url": "#"},
{"name": "Tracking Link 2", "url": "#"}
],
"subscriptionsTrackingUrls": [
{"name": "Tracking Link 1", "url": "#"},
{"name": "Tracking Link 2", "url": "#"}
],
"topicsOwners": [
{
"id": "41",
Expand Down Expand Up @@ -393,7 +401,7 @@
"retryClientErrors": true,
"backoffMaxIntervalMillis": 600000
},
"trackingEnabled": false,
"trackingEnabled": true,
"trackingMode": "trackingOff",
"owner": {
"source": "Service Catalog",
Expand Down
2 changes: 2 additions & 0 deletions hermes-console/json-server/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"/owners/sources/Service%20Catalog/:id": "/topicsOwners/:id",
"/readiness/datacenters": "/readinessDatacenters",
"/topics": "/topicNames",
"/tracking-urls/topics/:topicName": "/topicsTrackingUrls",
"/tracking-urls/topics/:topicName/subscriptions/:subscriptionName": "/subscriptionsTrackingUrls",
"/topics/:id/metrics": "/topicsMetrics/:id",
"/topics/:id/preview": "/topicPreview",
"/topics/:id/offline-clients-source": "/offlineClientsSource",
Expand Down
16 changes: 16 additions & 0 deletions hermes-console/src/api/hermes-client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import type { Stats } from '@/api/stats';
import type { SubscriptionHealth } from '@/api/subscription-health';
import type { SubscriptionMetrics } from '@/api/subscription-metrics';
import type { TopicForm } from '@/composables/topic/use-form-topic/types';
import type { TrackingUrl } from '@/api/tracking-url';

const acceptHeader = 'Accept';
const contentTypeHeader = 'Content-Type';
Expand Down Expand Up @@ -190,6 +191,21 @@ export function fetchOfflineClientsSource(
);
}

export function getTopicTrackingUrls(
topicName: string,
): ResponsePromise<TrackingUrl[]> {
return axios.get<TrackingUrl[]>(`/tracking-urls/topics/${topicName}`);
}

export function getSubscriptionTrackingUrls(
topicName: string,
subscriptionName: string,
): ResponsePromise<TrackingUrl[]> {
return axios.get<TrackingUrl[]>(
`/tracking-urls/topics/${topicName}/subscriptions/${subscriptionName}`,
);
}

export function fetchTopicClients(
topicName: string,
): ResponsePromise<string[]> {
Expand Down
4 changes: 4 additions & 0 deletions hermes-console/src/api/tracking-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface TrackingUrl {
name: string;
url: string;
}
43 changes: 43 additions & 0 deletions hermes-console/src/components/tracking-card/TrackingCard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect } from 'vitest';
import { render } from '@/utils/test-utils';
import TrackingCard from '@/components/tracking-card/TrackingCard.vue';

describe('TrackingCard', () => {
const props = {
trackingUrls: [
{ name: 'url1', url: 'https://test-tracking-url1' },
{ name: 'url2', url: 'https://test-tracking-url2' },
],
};

it('should render title properly', () => {
// when
const { getByText } = render(TrackingCard, { props });

// then
const row = getByText('trackingCard.title');
expect(row).toBeVisible();
});

it('should render all tracking urls', () => {
// when
const { container } = render(TrackingCard, { props });

// then
const elements = container.querySelectorAll('a')!!;
expect(elements[0]).toHaveAttribute('href', 'https://test-tracking-url1');
expect(elements[0]).toHaveTextContent('url1');
expect(elements[1]).toHaveAttribute('href', 'https://test-tracking-url2');
expect(elements[1]).toHaveTextContent('url2');
});

it('should render message when no tracking urls', () => {
// given
const emptyProps = { trackingUrls: [] };
const { getByText } = render(TrackingCard, { emptyProps });

// then
const row = getByText('trackingCard.noTrackingUrls');
expect(row).toBeVisible();
});
});
34 changes: 34 additions & 0 deletions hermes-console/src/components/tracking-card/TrackingCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script setup lang="ts">
import type { TrackingUrl } from '@/api/tracking-url';
const props = defineProps<{
trackingUrls: TrackingUrl[];
}>();
</script>

<template>
<v-card>
<template #title>
<div class="d-flex justify-space-between">
<p class="font-weight-bold">
{{ $t('trackingCard.title') }}
</p>
</div>
</template>
<v-card-item v-if="props.trackingUrls && props.trackingUrls.length > 0">
<p v-for="trackingUrl in props.trackingUrls" :key="trackingUrl.name">
<v-btn
:href="trackingUrl.url"
target="_blank"
variant="text"
color="blue"
>
{{ trackingUrl.name }}
</v-btn>
</p>
</v-card-item>
<v-card-item v-else> {{ $t('trackingCard.noTrackingUrls') }} </v-card-item>
</v-card>
</template>

<style scoped lang="scss"></style>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
fetchSubscriptionHealth as getSubscriptionHealth,
fetchSubscriptionLastUndeliveredMessage as getSubscriptionLastUndeliveredMessage,
fetchSubscriptionMetrics as getSubscriptionMetrics,
getSubscriptionTrackingUrls,
fetchSubscriptionUndeliveredMessages as getSubscriptionUndeliveredMessages,
retransmitSubscriptionMessages,
suspendSubscription as suspend,
Expand All @@ -20,6 +21,7 @@ import type { SentMessageTrace } from '@/api/subscription-undelivered';
import type { Subscription } from '@/api/subscription';
import type { SubscriptionHealth } from '@/api/subscription-health';
import type { SubscriptionMetrics } from '@/api/subscription-metrics';
import type { TrackingUrl } from '@/api/tracking-url';

export interface UseSubscription {
subscription: Ref<Subscription | undefined>;
Expand All @@ -28,6 +30,7 @@ export interface UseSubscription {
subscriptionHealth: Ref<SubscriptionHealth | undefined>;
subscriptionUndeliveredMessages: Ref<SentMessageTrace[] | null>;
subscriptionLastUndeliveredMessage: Ref<SentMessageTrace | null>;
trackingUrls: Ref<TrackingUrl[] | undefined>;
loading: Ref<boolean>;
error: Ref<UseSubscriptionsErrors>;
removeSubscription: () => Promise<boolean>;
Expand All @@ -44,6 +47,7 @@ export interface UseSubscriptionsErrors {
fetchSubscriptionHealth: Error | null;
fetchSubscriptionUndeliveredMessages: Error | null;
fetchSubscriptionLastUndeliveredMessage: Error | null;
getSubscriptionTrackingUrls: Error | null;
}

export function useSubscription(
Expand All @@ -58,6 +62,7 @@ export function useSubscription(
const subscriptionHealth = ref<SubscriptionHealth>();
const subscriptionUndeliveredMessages = ref<SentMessageTrace[]>([]);
const subscriptionLastUndeliveredMessage = ref<SentMessageTrace | null>(null);
const trackingUrls = ref<TrackingUrl[]>();
const loading = ref(false);
const error = ref<UseSubscriptionsErrors>({
fetchSubscription: null,
Expand All @@ -66,6 +71,7 @@ export function useSubscription(
fetchSubscriptionHealth: null,
fetchSubscriptionUndeliveredMessages: null,
fetchSubscriptionLastUndeliveredMessage: null,
getSubscriptionTrackingUrls: null,
});

const fetchSubscription = async () => {
Expand Down Expand Up @@ -150,6 +156,16 @@ export function useSubscription(
}
};

const fetchSubscriptionTrackingUrls = async () => {
try {
trackingUrls.value = (
await getSubscriptionTrackingUrls(topicName, subscriptionName)
).data;
} catch (e) {
error.value.getSubscriptionTrackingUrls = e as Error;
}
};

const removeSubscription = async (): Promise<boolean> => {
try {
await deleteSubscription(topicName, subscriptionName);
Expand Down Expand Up @@ -278,6 +294,7 @@ export function useSubscription(
};

fetchSubscription();
fetchSubscriptionTrackingUrls();

return {
subscription,
Expand All @@ -286,6 +303,7 @@ export function useSubscription(
subscriptionHealth,
subscriptionUndeliveredMessages,
subscriptionLastUndeliveredMessage,
trackingUrls,
loading,
error,
removeSubscription,
Expand Down
16 changes: 16 additions & 0 deletions hermes-console/src/composables/topic/use-topic/useTopic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
fetchOwner as getTopicOwner,
fetchTopicSubscriptionDetails as getTopicSubscriptionDetails,
fetchTopicSubscriptions as getTopicSubscriptions,
getTopicTrackingUrls,
} from '@/api/hermes-client';
import { dispatchErrorNotification } from '@/utils/notification-utils';
import { ref } from 'vue';
Expand All @@ -24,6 +25,7 @@ import type { OfflineClientsSource } from '@/api/offline-clients-source';
import type { Owner } from '@/api/owner';
import type { Ref } from 'vue';
import type { Subscription } from '@/api/subscription';
import type { TrackingUrl } from '@/api/tracking-url';

export interface UseTopic {
topic: Ref<TopicWithSchema | undefined>;
Expand All @@ -32,6 +34,7 @@ export interface UseTopic {
metrics: Ref<TopicMetrics | undefined>;
subscriptions: Ref<Subscription[] | undefined>;
offlineClientsSource: Ref<OfflineClientsSource | undefined>;
trackingUrls: Ref<TrackingUrl[] | undefined>;
loading: Ref<boolean>;
error: Ref<UseTopicErrors>;
fetchOfflineClientsSource: () => Promise<void>;
Expand All @@ -46,6 +49,7 @@ export interface UseTopicErrors {
fetchTopicMetrics: Error | null;
fetchSubscriptions: Error | null;
fetchOfflineClientsSource: Error | null;
getTopicTrackingUrls: Error | null;
}

export function useTopic(topicName: string): UseTopic {
Expand All @@ -57,6 +61,7 @@ export function useTopic(topicName: string): UseTopic {
const metrics = ref<TopicMetrics>();
const subscriptions = ref<Subscription[]>();
const offlineClientsSource = ref<OfflineClientsSource>();
const trackingUrls = ref<TrackingUrl[]>();
const loading = ref(false);
const error = ref<UseTopicErrors>({
fetchTopic: null,
Expand All @@ -65,6 +70,7 @@ export function useTopic(topicName: string): UseTopic {
fetchTopicMetrics: null,
fetchSubscriptions: null,
fetchOfflineClientsSource: null,
getTopicTrackingUrls: null,
});

const fetchTopic = async () => {
Expand Down Expand Up @@ -152,6 +158,14 @@ export function useTopic(topicName: string): UseTopic {
}
};

const fetchTopicTrackingUrls = async () => {
try {
trackingUrls.value = (await getTopicTrackingUrls(topicName)).data;
} catch (e) {
error.value.getTopicTrackingUrls = e as Error;
}
};

const removeTopic = async (): Promise<boolean> => {
try {
await deleteTopic(topicName);
Expand Down Expand Up @@ -188,6 +202,7 @@ export function useTopic(topicName: string): UseTopic {
};

fetchTopic();
fetchTopicTrackingUrls();

return {
topic,
Expand All @@ -196,6 +211,7 @@ export function useTopic(topicName: string): UseTopic {
metrics,
subscriptions,
offlineClientsSource,
trackingUrls,
loading,
error,
fetchOfflineClientsSource,
Expand Down
6 changes: 6 additions & 0 deletions hermes-console/src/dummy/tracking-urls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { TrackingUrl } from '@/api/tracking-url';

export const dummyTrackingUrls: TrackingUrl[] = [
{ name: 'url1', url: 'https://test-url1' },
{ name: 'url2', url: 'https://test-url2' },
];
4 changes: 4 additions & 0 deletions hermes-console/src/i18n/en-US/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,10 @@ const en_US = {
title: 'Costs',
detailsButton: 'DASHBOARD',
},
trackingCard: {
title: 'Tracking',
noTrackingUrls: 'No tracking urls available',
},
};

export default en_US;
25 changes: 25 additions & 0 deletions hermes-console/src/views/subscription/SubscriptionView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
dummyUndeliveredMessage,
dummyUndeliveredMessages,
} from '@/dummy/subscription';
import { dummyTrackingUrls } from '@/dummy/tracking-urls';
import { fireEvent } from '@testing-library/vue';
import { render } from '@/utils/test-utils';
import { Role } from '@/api/role';
Expand All @@ -35,13 +36,15 @@ const useSubscriptionStub: ReturnType<typeof useSubscription> = {
subscriptionHealth: ref(dummySubscriptionHealth),
subscriptionUndeliveredMessages: ref(dummyUndeliveredMessages),
subscriptionLastUndeliveredMessage: ref(dummyUndeliveredMessage),
trackingUrls: ref(dummyTrackingUrls),
error: ref({
fetchSubscription: null,
fetchOwner: null,
fetchSubscriptionMetrics: null,
fetchSubscriptionHealth: null,
fetchSubscriptionUndeliveredMessages: null,
fetchSubscriptionLastUndeliveredMessage: null,
getSubscriptionTrackingUrls: null,
}),
loading: computed(() => false),
removeSubscription: () => Promise.resolve(true),
Expand Down Expand Up @@ -349,4 +352,26 @@ describe('SubscriptionView', () => {
// then
expect(queryByText('costsCard.title')).not.toBeInTheDocument();
});

it('should render tracking card when tracking is enabled', () => {
// given
const dummySubscription2 = dummySubscription;
dummySubscription2.trackingEnabled = true;

// and
vi.mocked(useSubscription).mockReturnValueOnce({
...useSubscriptionStub,
subscription: ref(dummySubscription2),
});
vi.mocked(useRoles).mockReturnValueOnce(useRolesStub);
vi.mocked(useMetrics).mockReturnValueOnce(useMetricsStub);

// when
const { getByText } = render(SubscriptionView, {
testPinia: createTestingPiniaWithState(),
});

// then
expect(getByText('trackingCard.title')).toBeVisible();
});
});
Loading

0 comments on commit effb792

Please sign in to comment.