Skip to content

Commit 027b3b8

Browse files
oidacraclaude
andauthored
refactor(analytics): remove FEATURE_FLAG_CONTENT_ANALYTICS_SHOW_ENGAGEMENT_DASHBOARD (#34893)
## Summary - Remove `FEATURE_FLAG_CONTENT_ANALYTICS_SHOW_ENGAGEMENT_DASHBOARD` feature flag from backend (`FeatureFlagName.java`, `ConfigurationResource.WHITE_LIST`) - Delete the `dotAnalyticsEngagementResolver` and its spec file - Remove resolver from analytics dashboard route config - Replace conditional tab logic (`$engagementEnabled` signal, `$tabs` computed, breadcrumb effect) with a static `DASHBOARD_TAB_LIST` — Engagement tab is now always visible - Update dashboard component test to account for new tab order Closes #34850 ## Test plan - [x] `yarn nx lint portlets-dot-analytics` passes - [x] `yarn nx test portlets-dot-analytics` — 17 suites, 245 tests pass (1 pre-existing sparkline failure unrelated) - [ ] Verify Engagement tab is visible in Analytics Dashboard without feature flag - [ ] Verify Pageview and Conversions tabs still work correctly - [ ] Verify KPIs, sparkline charts, breakdown, and platforms table load in Engagement tab 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0ca19ef commit 027b3b8

8 files changed

Lines changed: 13 additions & 145 deletions

File tree

core-web/libs/portlets/dot-analytics/portlet/src/lib/dot-analytics-dashboard/dot-analytics-dashboard.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@
3636
<!-- Tabs -->
3737
<p-tabs [value]="store.currentTab()" (valueChange)="onTabChange($event)">
3838
<p-tablist>
39-
@for (tab of $tabs(); track tab.id) {
39+
@for (tab of tabs; track tab.id) {
4040
<p-tab [value]="tab.id">{{ tab.label | dm }}</p-tab>
4141
}
4242
</p-tablist>
4343
<p-tabpanels>
44-
@for (tab of $tabs(); track tab.id) {
44+
@for (tab of tabs; track tab.id) {
4545
<p-tabpanel [value]="tab.id">
4646
@switch (tab.id) {
4747
@case ('pageview') {

core-web/libs/portlets/dot-analytics/portlet/src/lib/dot-analytics-dashboard/dot-analytics-dashboard.component.spec.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe('DotAnalyticsDashboardComponent', () => {
5858
provide: DotMessageService,
5959
useValue: messageServiceMock
6060
},
61+
// GlobalStore is required transitively by child report components (pageview, engagement, conversions)
6162
mockProvider(GlobalStore, {
6263
currentSiteId: jest.fn().mockReturnValue('test-site-123'),
6364
addNewBreadcrumb: jest.fn()
@@ -80,14 +81,9 @@ describe('DotAnalyticsDashboardComponent', () => {
8081
expect(spectator.component).toBeTruthy();
8182
});
8283

83-
it('should render exactly 3 metric cards', () => {
84-
// p-tabs renders all panels in DOM, so we need to check only active panel
85-
const activePanels = spectator.queryAll('p-tabpanel');
86-
const firstPanel = activePanels[0];
87-
const metricCards = firstPanel?.querySelectorAll(
88-
'[data-testid="analytics-metric-card"]'
89-
);
90-
expect(metricCards?.length).toBe(3);
84+
it('should render pageview report component', () => {
85+
const pageviewReport = spectator.query('dot-analytics-pageview-report');
86+
expect(pageviewReport).toExist();
9187
});
9288

9389
it('should render line chart component', () => {
@@ -102,7 +98,7 @@ describe('DotAnalyticsDashboardComponent', () => {
10298

10399
it('should render tab panels for each report type', () => {
104100
const tabPanels = spectator.queryAll('p-tabpanel');
105-
expect(tabPanels.length).toBeGreaterThanOrEqual(1);
101+
expect(tabPanels.length).toBe(3);
106102
});
107103

108104
it('should render filters component', () => {

core-web/libs/portlets/dot-analytics/portlet/src/lib/dot-analytics-dashboard/dot-analytics-dashboard.component.ts

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,18 @@
11
import { CommonModule } from '@angular/common';
2-
import {
3-
ChangeDetectionStrategy,
4-
Component,
5-
computed,
6-
effect,
7-
inject,
8-
signal
9-
} from '@angular/core';
10-
import { toSignal } from '@angular/core/rxjs-interop';
11-
import { ActivatedRoute } from '@angular/router';
2+
import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
123

134
import { ButtonModule } from 'primeng/button';
145
import { MessageModule } from 'primeng/message';
156
import { TabsModule } from 'primeng/tabs';
167

17-
import { map } from 'rxjs/operators';
18-
198
import { DotLocalstorageService } from '@dotcms/data-access';
209
import {
2110
DASHBOARD_TAB_LIST,
22-
DASHBOARD_TABS,
2311
DashboardTab,
2412
DotAnalyticsDashboardStore,
2513
isValidTab,
2614
TimeRangeInput
2715
} from '@dotcms/portlets/dot-analytics/data-access';
28-
import { GlobalStore } from '@dotcms/store';
2916
import { DotMessagePipe } from '@dotcms/ui';
3017

3118
import DotAnalyticsConversionsReportComponent from './reports/conversions/dot-analytics-conversions-report/dot-analytics-conversions-report.component';
@@ -54,50 +41,20 @@ const HIDE_ANALYTICS_MESSAGE_BANNER_KEY = 'analytics-dashboard-hide-message-bann
5441
})
5542
/**
5643
* Root analytics dashboard component. Manages tab navigation, time range filters,
57-
* and feature-flag-gated visibility of the Engagement tab.
44+
* and the Engagement, Pageview, and Conversions tabs.
5845
*/
5946
export default class DotAnalyticsDashboardComponent {
60-
readonly #globalStore = inject(GlobalStore);
6147
/** Analytics dashboard store providing data and actions */
6248
protected readonly store = inject(DotAnalyticsDashboardStore);
63-
readonly #activatedRoute = inject(ActivatedRoute);
6449
readonly #localStorageService = inject(DotLocalstorageService);
6550

6651
/** Controls visibility of the top informational message banner */
6752
readonly $showMessage = signal<boolean>(
6853
!this.#localStorageService.getItem(HIDE_ANALYTICS_MESSAGE_BANNER_KEY)
6954
);
7055

71-
/**
72-
* Whether the Engagement tab is enabled via feature flag.
73-
* TODO: Remove this signal when the feature flag is removed.
74-
*/
75-
readonly $engagementEnabled = toSignal(
76-
this.#activatedRoute.data.pipe(
77-
map((data: Record<string, unknown>) => data['engagementEnabled'] === true)
78-
)
79-
);
80-
81-
/** Visible tabs, filtered by feature flag (Engagement tab hidden when disabled) */
82-
readonly $tabs = computed(() => {
83-
const enabled = this.$engagementEnabled();
84-
return DASHBOARD_TAB_LIST.filter((tab) => tab.id !== DASHBOARD_TABS.engagement || enabled);
85-
});
86-
87-
constructor() {
88-
// TODO: Remove this effect when the feature flag is removed
89-
effect(() => {
90-
const enabled = this.$engagementEnabled();
91-
const params = this.#activatedRoute.snapshot.queryParamMap;
92-
93-
if (enabled && !params.has('tab')) {
94-
this.#globalStore.addNewBreadcrumb({
95-
label: DASHBOARD_TABS.engagement,
96-
url: '/analytics/dashboard?tab=engagement'
97-
});
98-
}
99-
});
100-
}
56+
/** All dashboard tabs — always visible */
57+
readonly tabs = DASHBOARD_TAB_LIST;
10158

10259
/**
10360
* Closes the message banner and stores the preference in localStorage

core-web/libs/portlets/dot-analytics/portlet/src/lib/lib.routes.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { DotAnalyticsDashboardStore } from '@dotcms/portlets/dot-analytics/data-
44

55
import DotAnalyticsDashboardComponent from './dot-analytics-dashboard/dot-analytics-dashboard.component';
66
import { analyticsHealthGuard } from './guards/analytics-health.guard';
7-
import { dotAnalyticsEngagementResolver } from './resolvers/dot-analytics-engagement.resolver';
87

98
export const dotAnalyticsRoutes: Route[] = [
109
{
@@ -24,11 +23,7 @@ export const dotAnalyticsRoutes: Route[] = [
2423
path: 'dashboard',
2524
canMatch: [analyticsHealthGuard],
2625
providers: [DotAnalyticsDashboardStore],
27-
component: DotAnalyticsDashboardComponent,
28-
// TODO: Remove this resolver when the feature flag is removed
29-
resolve: {
30-
engagementEnabled: dotAnalyticsEngagementResolver
31-
}
26+
component: DotAnalyticsDashboardComponent
3227
},
3328
{
3429
path: '',

core-web/libs/portlets/dot-analytics/portlet/src/lib/resolvers/dot-analytics-engagement.resolver.spec.ts

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

core-web/libs/portlets/dot-analytics/portlet/src/lib/resolvers/dot-analytics-engagement.resolver.ts

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

dotCMS/src/main/java/com/dotcms/featureflag/FeatureFlagName.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ public interface FeatureFlagName {
1515

1616
String FEATURE_FLAG_CONTENT_ANALYTICS_AUTO_INJECT = "FEATURE_FLAG_CONTENT_ANALYTICS_AUTO_INJECT";
1717

18-
// Engagement Dashboard
19-
String FEATURE_FLAG_CONTENT_ANALYTICS_SHOW_ENGAGEMENT_DASHBOARD = "FEATURE_FLAG_CONTENT_ANALYTICS_SHOW_ENGAGEMENT_DASHBOARD";
20-
2118
// Unique Fields
2219
String FEATURE_FLAG_DB_UNIQUE_FIELD_VALIDATION = "FEATURE_FLAG_DB_UNIQUE_FIELD_VALIDATION";
2320

dotCMS/src/main/java/com/dotcms/rest/api/v1/system/ConfigurationResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public class ConfigurationResource implements Serializable {
7171
FeatureFlagName.FEATURE_FLAG_SEO_PAGE_TOOLS, FeatureFlagName.FEATURE_FLAG_EDIT_URL_CONTENT_MAP, "CONTENT_EDITOR2_ENABLED", "CONTENT_EDITOR2_CONTENT_TYPE",
7272
FeatureFlagName.FEATURE_FLAG_NEW_BINARY_FIELD, FeatureFlagName.FEATURE_FLAG_ANNOUNCEMENTS, FeatureFlagName.FEATURE_FLAG_NEW_EDIT_PAGE,
7373
FeatureFlagName.FEATURE_FLAG_UVE_PREVIEW_MODE, FeatureFlagName.FEATURE_FLAG_UVE_TOGGLE_LOCK, FeatureFlagName.FEATURE_FLAG_UVE_STYLE_EDITOR,
74-
FeatureFlagName.FEATURE_FLAG_CONTENT_ANALYTICS_SHOW_ENGAGEMENT_DASHBOARD, FeatureFlagName.FEATURE_FLAG_UVE_STYLE_EDITOR_FOR_TRADITIONAL_PAGES }));
74+
FeatureFlagName.FEATURE_FLAG_UVE_STYLE_EDITOR_FOR_TRADITIONAL_PAGES }));
7575

7676

7777
private boolean isOnBlackList(final String key) {

0 commit comments

Comments
 (0)