Skip to content

Commit 7372b91

Browse files
authored
SE-123: Fetch product updates from backend (#15079)
1 parent f5d0efc commit 7372b91

File tree

8 files changed

+72
-55
lines changed

8 files changed

+72
-55
lines changed

datahub-web-react/src/app/shared/product/update/ProductUpdates.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,9 @@ const StyledCloseRounded = styled(X)`
8484
export default function ProductUpdates() {
8585
const isFeatureEnabled = useIsProductAnnouncementEnabled();
8686
const latestUpdate = useGetLatestProductAnnouncementData();
87-
const { title, image, description, ctaText, ctaLink } = latestUpdate;
8887

89-
const { visible, refetch } = useIsProductAnnouncementVisible(latestUpdate);
90-
const dismiss = useDismissProductAnnouncement(latestUpdate, refetch);
88+
const { visible, refetch } = useIsProductAnnouncementVisible(latestUpdate?.id);
89+
const dismiss = useDismissProductAnnouncement(latestUpdate?.id, refetch);
9190

9291
// Local state to hide immediately on dismiss
9392
const [isLocallyVisible, setIsLocallyVisible] = useState(false);
@@ -102,14 +101,18 @@ export default function ProductUpdates() {
102101
};
103102

104103
const trackClick = () => {
104+
if (!latestUpdate) return;
105105
analytics.event({
106106
type: EventType.ClickProductUpdate,
107107
id: latestUpdate.id,
108108
url: latestUpdate.ctaLink,
109109
});
110110
};
111111

112-
if (!isFeatureEnabled || !isLocallyVisible || !latestUpdate.enabled) return null;
112+
// Don't show if feature disabled, not locally visible, update not loaded, or update not enabled
113+
if (!isFeatureEnabled || !isLocallyVisible || !latestUpdate || !latestUpdate.enabled) return null;
114+
115+
const { title, image, description, ctaText, ctaLink } = latestUpdate;
113116

114117
return (
115118
<CardWrapper>

datahub-web-react/src/app/shared/product/update/__tests__/hooks.test.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ import { renderHook } from '@testing-library/react-hooks';
44
import React from 'react';
55

66
import * as useUserContextModule from '@app/context/useUserContext';
7-
import {
8-
useGetLatestProductAnnouncementData,
9-
useIsProductAnnouncementEnabled,
10-
useIsProductAnnouncementVisible,
11-
} from '@app/shared/product/update/hooks';
12-
import { latestUpdate } from '@app/shared/product/update/latestUpdate';
7+
import { useIsProductAnnouncementEnabled, useIsProductAnnouncementVisible } from '@app/shared/product/update/hooks';
138
import * as useAppConfigModule from '@app/useAppConfig';
149

1510
import { BatchGetStepStatesDocument } from '@graphql/step.generated';
@@ -109,13 +104,6 @@ describe('product update hooks', () => {
109104
});
110105
});
111106

112-
describe('useGetLatestProductAnnouncementData', () => {
113-
it('returns latest update object', () => {
114-
const { result } = renderHook(() => useGetLatestProductAnnouncementData());
115-
expect(result.current).toBe(latestUpdate);
116-
});
117-
});
118-
119107
describe('useIsProductAnnouncementVisible', () => {
120108
beforeEach(() => {
121109
vi.spyOn(useUserContextModule, 'useUserContext').mockReturnValue({
@@ -124,7 +112,7 @@ describe('product update hooks', () => {
124112
});
125113

126114
it('returns visible=false when step state exists', async () => {
127-
const { result } = renderHook(() => useIsProductAnnouncementVisible(TEST_UPDATE), {
115+
const { result } = renderHook(() => useIsProductAnnouncementVisible(TEST_UPDATE.id), {
128116
wrapper: ({ children }) => (
129117
<MockedProvider mocks={[BATCH_GET_STEP_STATES_MOCK_PRESENT]} addTypename={false}>
130118
{children}
@@ -138,7 +126,7 @@ describe('product update hooks', () => {
138126
});
139127

140128
it('returns visible=true when step state does not exist', async () => {
141-
const { result } = renderHook(() => useIsProductAnnouncementVisible(TEST_UPDATE), {
129+
const { result } = renderHook(() => useIsProductAnnouncementVisible(TEST_UPDATE.id), {
142130
wrapper: ({ children }) => (
143131
<MockedProvider mocks={[BATCH_GET_STEP_STATES_MOCK_NOT_PRESENT]} addTypename={false}>
144132
{children}
@@ -152,7 +140,7 @@ describe('product update hooks', () => {
152140
});
153141

154142
it('returns visible=false when query is loading', () => {
155-
const { result } = renderHook(() => useIsProductAnnouncementVisible(TEST_UPDATE), {
143+
const { result } = renderHook(() => useIsProductAnnouncementVisible(TEST_UPDATE.id), {
156144
wrapper: ({ children }) => (
157145
<MockedProvider mocks={[BATCH_GET_STEP_STATES_MOCK_LOADING]} addTypename={false}>
158146
{children}

datahub-web-react/src/app/shared/product/update/hooks.ts

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useCallback } from 'react';
22

33
import { useUserContext } from '@app/context/useUserContext';
4-
import { ProductUpdate, latestUpdate } from '@app/shared/product/update/latestUpdate';
54
import { useAppConfig } from '@app/useAppConfig';
65

6+
import { useGetLatestProductUpdateQuery } from '@graphql/app.generated';
77
import { useBatchGetStepStatesQuery, useBatchUpdateStepStatesMutation } from '@graphql/step.generated';
88

99
const PRODUCT_UPDATE_STEP_PREFIX = 'product_updates';
@@ -22,10 +22,19 @@ export function useIsProductAnnouncementEnabled() {
2222
}
2323

2424
/**
25-
* Hook to fetch the announcement data (eventually can replace with fetch).
25+
* Hook to fetch the latest product announcement data from GraphQL.
2626
*/
2727
export function useGetLatestProductAnnouncementData() {
28-
return latestUpdate;
28+
const { data, loading, error } = useGetLatestProductUpdateQuery({
29+
fetchPolicy: 'cache-first',
30+
});
31+
32+
// Return null if loading, error, or no data
33+
if (loading || error || !data?.latestProductUpdate) {
34+
return null;
35+
}
36+
37+
return data.latestProductUpdate;
2938
}
3039

3140
export type ProductAnnouncementResult = {
@@ -36,18 +45,34 @@ export type ProductAnnouncementResult = {
3645
/**
3746
* Hook to check if the announcement should be shown based on dismissal state
3847
*/
39-
export function useIsProductAnnouncementVisible(update: ProductUpdate): ProductAnnouncementResult {
48+
export function useIsProductAnnouncementVisible(updateId: string | null | undefined): ProductAnnouncementResult {
4049
const userUrn = useUserContext()?.user?.urn;
41-
const productUpdateStepId = userUrn ? buildProductUpdateStepId(userUrn, update.id) : null;
50+
const productUpdateStepId = userUrn && updateId ? buildProductUpdateStepId(userUrn, updateId) : null;
4251
const productUpdateStepIds = productUpdateStepId ? [productUpdateStepId] : [];
4352
const { data, loading, error, refetch } = useBatchGetStepStatesQuery({
44-
skip: !userUrn,
53+
skip: !userUrn || !updateId,
4554
variables: { input: { ids: productUpdateStepIds } },
4655
fetchPolicy: 'cache-first',
4756
});
4857

49-
// If query is loading or has an error or userUrn is not loaded yet, don't show the announcement (wait for user context to load)
50-
if (!userUrn || loading || error) {
58+
// If userUrn is not loaded yet, don't show the announcement (wait for user context to load)
59+
if (!userUrn) {
60+
return {
61+
visible: false,
62+
refetch,
63+
};
64+
}
65+
66+
// If updateId is not available, don't show
67+
if (!updateId) {
68+
return {
69+
visible: false,
70+
refetch,
71+
};
72+
}
73+
74+
// If query is loading or has an error, don't show yet
75+
if (loading || error) {
5176
return {
5277
visible: false,
5378
refetch,
@@ -69,9 +94,9 @@ export function useIsProductAnnouncementVisible(update: ProductUpdate): ProductA
6994
/**
7095
* Optional helper to dismiss the announcement (can also inline in `onClose`)
7196
*/
72-
export function useDismissProductAnnouncement(update: ProductUpdate, refetch: () => void): () => void {
97+
export function useDismissProductAnnouncement(updateId: string | null | undefined, refetch: () => void): () => void {
7398
const userUrn = useUserContext()?.user?.urn;
74-
const productUpdateStepId = userUrn ? buildProductUpdateStepId(userUrn, update.id) : null;
99+
const productUpdateStepId = userUrn && updateId ? buildProductUpdateStepId(userUrn, updateId) : null;
75100

76101
const [batchUpdateStepStates] = useBatchUpdateStepStatesMutation();
77102

datahub-web-react/src/app/shared/product/update/latestUpdate.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

datahub-web-react/src/graphql/app.graphql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,15 @@ mutation updateDocPropagationSettings($input: UpdateDocPropagationSettingsInput!
180180
mutation updateApplicationsSettings($input: UpdateApplicationsSettingsInput!) {
181181
updateApplicationsSettings(input: $input)
182182
}
183+
184+
query getLatestProductUpdate {
185+
latestProductUpdate {
186+
enabled
187+
id
188+
title
189+
description
190+
image
191+
ctaText
192+
ctaLink
193+
}
194+
}

metadata-service/configuration/src/main/resources/application.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,9 @@ featureFlags:
847847
showHomePageRedesign: ${SHOW_HOME_PAGE_REDESIGN:false} # If turned on, show the re-designed home page
848848
lineageGraphV3: ${LINEAGE_GRAPH_V3:false} # Enables the redesign of the lineage v2 graph
849849
showProductUpdates: ${SHOW_PRODUCT_UPDATES:true} # Whether to show in-product update popover on new updates.
850-
productUpdatesJsonUrl: ${PRODUCT_UPDATES_JSON_URL:https://raw.githubusercontent.com/datahub-project/datahub/master/metadata-service/configuration/src/main/resources/product-update.json} # URL to fetch product updates JSON from remote source.
850+
productUpdatesJsonUrl: ${PRODUCT_UPDATES_JSON_URL:https://product.datahub.com/updates/datahub-core} # URL to fetch product updates JSON from remote source.
851+
# for Saas:
852+
#productUpdatesJsonUrl: ${PRODUCT_UPDATES_JSON_URL:https://product.datahub.com/updates/datahub-cloud} # URL to fetch product updates JSON from remote source.
851853
productUpdatesJsonFallbackResource: ${PRODUCT_UPDATES_JSON_FALLBACK_RESOURCE:product-update.json} # Classpath resource to use as fallback when remote fetch fails.
852854
logicalModelsEnabled: ${LOGICAL_MODELS_ENABLED:false} # Enables logical models feature
853855
showHomepageUserRole: ${SHOW_HOMEPAGE_USER_ROLE:false} # Enables displaying the homepage user role underneath the name. Only relevant for custom home page
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"enabled": true,
3+
"id": "v1.2.1",
4+
"title": "What's New In DataHub",
5+
"description": "Explore version v1.2.1",
6+
"image": "https://raw.githubusercontent.com/datahub-project/datahub/master/datahub-web-react/src/images/sample-product-update-image.png",
7+
"ctaText": "Read updates",
8+
"ctaLink": "https://docs.datahub.com/docs/releases#v1-2-1"
9+
}
10+

metadata-service/configuration/src/main/resources/product-update.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"id": "v1.2.1",
44
"title": "What's New In DataHub",
55
"description": "Explore version v1.2.1",
6+
"image": "https://raw.githubusercontent.com/datahub-project/datahub/master/datahub-web-react/src/images/sample-product-update-image.png",
67
"ctaText": "Read updates",
78
"ctaLink": "https://docs.datahub.com/docs/releases#v1-2-1"
89
}

0 commit comments

Comments
 (0)