Skip to content

Commit 6d1d33b

Browse files
committed
Merge remote-tracking branch 'upstream/feature/pbs-25.04' into fix/ENG-9275
2 parents 8082f22 + 99cd1ae commit 6d1d33b

File tree

10 files changed

+74
-38
lines changed

10 files changed

+74
-38
lines changed

src/app/features/analytics/analytics.component.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export class AnalyticsComponent implements OnInit {
140140
navigateToLinkedProjects() {
141141
this.router.navigate(['linked-projects'], { relativeTo: this.route });
142142
}
143+
143144
private setData() {
144145
const analytics = this.analytics();
145146

@@ -171,7 +172,14 @@ export class AnalyticsComponent implements OnInit {
171172
},
172173
];
173174

174-
this.popularPagesLabels = analytics.popularPages.map((item) => item.title);
175+
this.popularPagesLabels = analytics.popularPages.map((item) => {
176+
const parts = item.path.split('/').filter(Boolean);
177+
const resource = parts[1]?.replace('-', ' ') || 'overview';
178+
let cleanTitle = item.title === 'OSF' ? item.title : item.title.replace(/^OSF \| /, '');
179+
cleanTitle = cleanTitle.replace(/&amp;/gi, '&').replace(/&lt;/gi, '<').replace(/&gt;/gi, '>');
180+
return cleanTitle.endsWith(resource) ? cleanTitle : `${cleanTitle} | ${resource}`;
181+
});
182+
175183
this.popularPagesDataset = [
176184
{
177185
label: this.translateService.instant('project.analytics.charts.popularPages'),

src/app/features/preprints/pages/preprint-details/preprint-details.component.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,6 @@ export class PreprintDetailsComponent implements OnInit, OnDestroy {
175175
this.helpScoutService.setResourceType('preprint');
176176
this.prerenderReady.setNotReady();
177177

178-
effect(() => {
179-
const currentPreprint = this.preprint();
180-
181-
if (currentPreprint && currentPreprint.isPublic) {
182-
this.analyticsService.sendCountedUsage(currentPreprint.id, 'preprint.detail').subscribe();
183-
}
184-
});
185-
186178
effect(() => {
187179
const preprint = this.preprint();
188180
const contributors = this.contributors();

src/app/features/project/overview/project-overview.component.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ export class ProjectOverviewComponent implements OnInit {
104104
submissions = select(CollectionsModerationSelectors.getCollectionSubmissions);
105105
collectionProvider = select(CollectionsSelectors.getCollectionProvider);
106106
currentReviewAction = select(CollectionsModerationSelectors.getCurrentReviewAction);
107-
isCollectionProviderLoading = select(CollectionsSelectors.getCollectionProviderLoading);
108-
isReviewActionsLoading = select(CollectionsModerationSelectors.getCurrentReviewActionLoading);
109107
components = select(CurrentResourceSelectors.getResourceWithChildren);
110108
areComponentsLoading = select(CurrentResourceSelectors.isResourceWithChildrenLoading);
111109
currentProject = select(ProjectOverviewSelectors.getProject);
@@ -120,7 +118,6 @@ export class ProjectOverviewComponent implements OnInit {
120118
configuredCitationAddons = select(AddonsSelectors.getConfiguredCitationAddons);
121119
operationInvocation = select(AddonsSelectors.getOperationInvocation);
122120
storage = select(ProjectOverviewSelectors.getStorage);
123-
isStorageLoading = select(ProjectOverviewSelectors.isStorageLoading);
124121

125122
private readonly actions = createDispatchMap({
126123
getProject: GetProjectById,
@@ -259,14 +256,6 @@ export class ProjectOverviewComponent implements OnInit {
259256
this.actions.getHomeWiki(ResourceType.Project, project.id);
260257
}
261258
});
262-
263-
effect(() => {
264-
const currentProject = this.currentProject();
265-
266-
if (currentProject && currentProject.isPublic) {
267-
this.analyticsService.sendCountedUsage(currentProject.id, 'project.detail').subscribe();
268-
}
269-
});
270259
}
271260

272261
private setupAddonsEffects(): void {

src/app/features/project/project.component.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { PrerenderReadyService } from '@core/services/prerender-ready.service';
66
import { DataciteService } from '@osf/shared/services/datacite/datacite.service';
77
import { MetaTagsService } from '@osf/shared/services/meta-tags.service';
88
import { ContributorsSelectors } from '@osf/shared/stores/contributors';
9+
import { CurrentResourceSelectors } from '@osf/shared/stores/current-resource';
910

1011
import { ProjectOverviewSelectors } from './overview/store';
1112
import { ProjectComponent } from './project.component';
@@ -52,6 +53,7 @@ describe('Component: Project', () => {
5253
{ selector: ProjectOverviewSelectors.isLicenseLoading, value: false },
5354
{ selector: ContributorsSelectors.getBibliographicContributors, value: [] },
5455
{ selector: ContributorsSelectors.isBibliographicContributorsLoading, value: false },
56+
{ selector: CurrentResourceSelectors.getCurrentResource, value: null },
5557
],
5658
}),
5759
],

src/app/features/project/project.component.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createDispatchMap, select } from '@ngxs/store';
22

3-
import { map } from 'rxjs';
3+
import { filter, map } from 'rxjs';
44

55
import { DatePipe } from '@angular/common';
66
import {
@@ -15,14 +15,16 @@ import {
1515
signal,
1616
} from '@angular/core';
1717
import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';
18-
import { ActivatedRoute, RouterOutlet } from '@angular/router';
18+
import { ActivatedRoute, NavigationEnd, Router, RouterOutlet } from '@angular/router';
1919

2020
import { HelpScoutService } from '@core/services/help-scout.service';
2121
import { PrerenderReadyService } from '@core/services/prerender-ready.service';
2222
import { ResourceType } from '@osf/shared/enums/resource-type.enum';
2323
import { DataciteService } from '@osf/shared/services/datacite/datacite.service';
2424
import { MetaTagsService } from '@osf/shared/services/meta-tags.service';
2525
import { ContributorsSelectors, GetBibliographicContributors } from '@osf/shared/stores/contributors';
26+
import { AnalyticsService } from '@shared/services/analytics.service';
27+
import { CurrentResourceSelectors } from '@shared/stores/current-resource';
2628

2729
import {
2830
GetProjectById,
@@ -50,6 +52,9 @@ export class ProjectComponent implements OnDestroy {
5052
private readonly route = inject(ActivatedRoute);
5153
private readonly datePipe = inject(DatePipe);
5254
private readonly prerenderReady = inject(PrerenderReadyService);
55+
private readonly router = inject(Router);
56+
private readonly analyticsService = inject(AnalyticsService);
57+
currentResource = select(CurrentResourceSelectors.getCurrentResource);
5358

5459
readonly identifiersForDatacite$ = toObservable(select(ProjectOverviewSelectors.getIdentifiers)).pipe(
5560
map((identifiers) => (identifiers?.length ? { identifiers } : null))
@@ -123,6 +128,18 @@ export class ProjectComponent implements OnDestroy {
123128
.logIdentifiableView(this.identifiersForDatacite$)
124129
.pipe(takeUntilDestroyed(this.destroyRef))
125130
.subscribe();
131+
132+
this.router.events
133+
.pipe(
134+
filter((event) => event instanceof NavigationEnd),
135+
takeUntilDestroyed(this.destroyRef)
136+
)
137+
.subscribe((event: NavigationEnd) => {
138+
this.analyticsService.sendCountedUsageForRegistrationAndProjects(
139+
event.urlAfterRedirects,
140+
this.currentResource()
141+
);
142+
});
126143
}
127144

128145
ngOnDestroy(): void {

src/app/features/registry/registry.component.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createDispatchMap, select } from '@ngxs/store';
22

3-
import { map } from 'rxjs';
3+
import { filter, map } from 'rxjs';
44

55
import { DatePipe } from '@angular/common';
66
import {
@@ -15,7 +15,7 @@ import {
1515
signal,
1616
} from '@angular/core';
1717
import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';
18-
import { ActivatedRoute, RouterOutlet } from '@angular/router';
18+
import { ActivatedRoute, NavigationEnd, Router, RouterOutlet } from '@angular/router';
1919

2020
import { ENVIRONMENT } from '@core/provider/environment.provider';
2121
import { HelpScoutService } from '@core/services/help-scout.service';
@@ -27,6 +27,7 @@ import { AnalyticsService } from '@osf/shared/services/analytics.service';
2727
import { MetaTagsService } from '@osf/shared/services/meta-tags.service';
2828
import { ContributorsSelectors, GetBibliographicContributors } from '@osf/shared/stores/contributors';
2929
import { DataciteService } from '@shared/services/datacite/datacite.service';
30+
import { CurrentResourceSelectors } from '@shared/stores/current-resource';
3031

3132
import { GetRegistryIdentifiers, GetRegistryWithRelatedData, RegistrySelectors } from './store/registry';
3233

@@ -59,7 +60,7 @@ export class RegistryComponent implements OnDestroy {
5960
});
6061

6162
private registryId = toSignal(this.route.params.pipe(map((params) => params['id'])));
62-
63+
readonly currentResource = select(CurrentResourceSelectors.getCurrentResource);
6364
readonly registry = select(RegistrySelectors.getRegistry);
6465
readonly isRegistryLoading = select(RegistrySelectors.isRegistryLoading);
6566
readonly identifiersForDatacite$ = toObservable(select(RegistrySelectors.getIdentifiers)).pipe(
@@ -79,6 +80,7 @@ export class RegistryComponent implements OnDestroy {
7980
);
8081

8182
private readonly lastMetaTagsRegistryId = signal<string | null>(null);
83+
readonly router = inject(Router);
8284

8385
constructor() {
8486
this.prerenderReady.setNotReady();
@@ -106,17 +108,22 @@ export class RegistryComponent implements OnDestroy {
106108
}
107109
});
108110

109-
effect(() => {
110-
const currentRegistry = this.registry();
111-
if (currentRegistry && currentRegistry.isPublic) {
112-
this.analyticsService.sendCountedUsage(currentRegistry.id, 'registry.detail').subscribe();
113-
}
114-
});
115-
116111
this.dataciteService
117112
.logIdentifiableView(this.identifiersForDatacite$)
118113
.pipe(takeUntilDestroyed(this.destroyRef))
119114
.subscribe();
115+
116+
this.router.events
117+
.pipe(
118+
filter((event) => event instanceof NavigationEnd),
119+
takeUntilDestroyed(this.destroyRef)
120+
)
121+
.subscribe((event: NavigationEnd) => {
122+
this.analyticsService.sendCountedUsageForRegistrationAndProjects(
123+
event.urlAfterRedirects,
124+
this.currentResource()
125+
);
126+
});
120127
}
121128

122129
ngOnDestroy(): void {

src/app/shared/models/current-resource.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export interface CurrentResource {
88
rootResourceId?: string;
99
wikiEnabled?: boolean;
1010
permissions: UserPermissions[];
11+
title?: string;
1112
}

src/app/shared/models/guid-response-json-api.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface GuidDataJsonApi {
1111
guid: string;
1212
wiki_enabled: boolean;
1313
current_user_permissions: UserPermissions[];
14+
title?: string;
1415
};
1516
relationships: {
1617
target?: {

src/app/shared/services/analytics.service.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { Observable } from 'rxjs';
33
import { inject, Injectable } from '@angular/core';
44

55
import { ENVIRONMENT } from '@core/provider/environment.provider';
6-
7-
import { JsonApiService } from './json-api.service';
6+
import { CurrentResource } from '@osf/shared/models/current-resource.model';
7+
import { JsonApiService } from '@osf/shared/services/json-api.service';
88

99
@Injectable({ providedIn: 'root' })
1010
export class AnalyticsService {
@@ -15,23 +15,41 @@ export class AnalyticsService {
1515
return `${this.environment.apiDomainUrl}/_/metrics/events/counted_usage/`;
1616
}
1717

18-
sendCountedUsage(guid: string, routeName: string): Observable<void> {
19-
const payload = {
18+
getPageviewPayload(resource: CurrentResource, routeName: string) {
19+
const all_attrs = { item_guid: resource?.id } as const;
20+
const attributes = Object.fromEntries(
21+
Object.entries(all_attrs).filter(([_, value]: [unknown, unknown]) => typeof value !== 'undefined')
22+
);
23+
const pageTitle = document.title === 'OSF' ? `OSF | ${resource.title}` : document.title;
24+
return {
2025
data: {
2126
type: 'counted-usage',
2227
attributes: {
23-
item_guid: guid,
28+
...attributes,
2429
action_labels: ['web', 'view'],
2530
pageview_info: {
2631
page_url: document.URL,
27-
page_title: document.title,
32+
page_title: pageTitle,
2833
referer_url: document.referrer,
2934
route_name: `angular-osf-web.${routeName}`,
3035
},
3136
},
3237
},
3338
};
39+
}
3440

41+
sendCountedUsage(resource: CurrentResource, route: string): Observable<void> {
42+
const payload = this.getPageviewPayload(resource, route);
3543
return this.jsonApiService.post<void>(this.apiDomainUrl, payload);
3644
}
45+
46+
sendCountedUsageForRegistrationAndProjects(urlPath: string, resource: CurrentResource | null) {
47+
if (resource) {
48+
let route = urlPath.split('/').filter(Boolean).join('.');
49+
if (resource?.type) {
50+
route = `${resource?.type}.${route}`;
51+
}
52+
this.sendCountedUsage(resource, route).subscribe();
53+
}
54+
}
3755
}

src/app/shared/services/resource.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export class ResourceGuidService {
5555
wikiEnabled: res.data.attributes.wiki_enabled,
5656
permissions: res.data.attributes.current_user_permissions,
5757
rootResourceId: res.data.relationships.root?.data?.id,
58+
title: res.data.attributes?.title,
5859
}) as CurrentResource
5960
),
6061
finalize(() => this.loaderService.hide())

0 commit comments

Comments
 (0)