diff --git a/src/app/features/analytics/analytics.component.html b/src/app/features/analytics/analytics.component.html index 4efeecbb4..8cb527800 100644 --- a/src/app/features/analytics/analytics.component.html +++ b/src/app/features/analytics/analytics.component.html @@ -42,45 +42,49 @@ } -
- + @if (!isMetricsLoading() && !isRelatedCountsLoading()) { +
+ - + - + - -
+ +
+ } @else { + + }
{ - const analytics = this.analytics(); - - if (analytics) { - this.setData(); - } + this.setData(); }); } diff --git a/src/app/features/analytics/mappers/analytics.mapper.ts b/src/app/features/analytics/mappers/analytics.mapper.ts index 540fde80d..c31350560 100644 --- a/src/app/features/analytics/mappers/analytics.mapper.ts +++ b/src/app/features/analytics/mappers/analytics.mapper.ts @@ -1,14 +1,21 @@ -import { AnalyticsMetricsGetResponse, AnalyticsMetricsModel } from '../models'; +import { NodeAnalyticsDataJsonApi, NodeAnalyticsModel, RefererDomainJsonApi, RefererDomainModel } from '../models'; export class AnalyticsMetricsMapper { - static fromResponse(response: AnalyticsMetricsGetResponse): AnalyticsMetricsModel { + static fromResponse(response: NodeAnalyticsDataJsonApi): NodeAnalyticsModel { return { id: response.id, type: response.type, popularPages: response.attributes.popular_pages, uniqueVisits: response.attributes.unique_visits, - refererDomain: response.attributes.referer_domain, + refererDomain: response.attributes.referer_domain.map((item) => this.getReferDomain(item)), timeOfDay: response.attributes.time_of_day, }; } + + static getReferDomain(data: RefererDomainJsonApi): RefererDomainModel { + return { + refererDomain: data.referer_domain, + count: data.count, + }; + } } diff --git a/src/app/features/analytics/models/analytics-metrics.model.ts b/src/app/features/analytics/models/analytics-metrics.model.ts deleted file mode 100644 index 0a2d3ee0f..000000000 --- a/src/app/features/analytics/models/analytics-metrics.model.ts +++ /dev/null @@ -1,44 +0,0 @@ -export interface AnalyticsMetricsGetResponse { - id: string; - type: string; - attributes: AnalyticsMetricsAttributes; -} - -interface AnalyticsMetricsAttributes { - popular_pages: []; - unique_visits: []; - time_of_day: []; - referer_domain: []; -} - -export interface AnalyticsMetricsModel { - id: string; - type: string; - popularPages: PopularPage[]; - uniqueVisits: UniqueVisit[]; - timeOfDay: TimeOfDay[]; - refererDomain: RefererDomain[]; - lastFetched?: number; -} - -export interface PopularPage { - path: string; - route: string; - title: string; - count: number; -} - -export interface UniqueVisit { - date: string; - count: number; -} - -export interface TimeOfDay { - hour: number; - count: number; -} - -export interface RefererDomain { - refererDomain: string; - count: number; -} diff --git a/src/app/features/analytics/models/index.ts b/src/app/features/analytics/models/index.ts index 7a6cd679c..ee81935a2 100644 --- a/src/app/features/analytics/models/index.ts +++ b/src/app/features/analytics/models/index.ts @@ -1,4 +1,5 @@ -export * from './analytics-metrics.model'; export * from './date-range-option.model'; +export * from './node-analytics.model'; +export * from './node-analytics-json-api.model'; export * from './related-counts.model'; export * from './related-counts-json-api.model'; diff --git a/src/app/features/analytics/models/node-analytics-json-api.model.ts b/src/app/features/analytics/models/node-analytics-json-api.model.ts new file mode 100644 index 000000000..362960f34 --- /dev/null +++ b/src/app/features/analytics/models/node-analytics-json-api.model.ts @@ -0,0 +1,38 @@ +import { ResponseDataJsonApi } from '@osf/shared/models'; + +export type NodeAnalyticsResponseJsonApi = ResponseDataJsonApi; + +export interface NodeAnalyticsDataJsonApi { + id: string; + type: 'node-analytics'; + attributes: NodeAnalyticsAttributesJsonApi; +} + +export interface NodeAnalyticsAttributesJsonApi { + popular_pages: PopularPageJsonApi[]; + unique_visits: UniqueVisitJsonApi[]; + time_of_day: TimeOfDayJsonApi[]; + referer_domain: RefererDomainJsonApi[]; +} + +export interface PopularPageJsonApi { + path: string; + route: string; + title: string; + count: number; +} + +export interface UniqueVisitJsonApi { + date: string; + count: number; +} + +export interface TimeOfDayJsonApi { + hour: number; + count: number; +} + +export interface RefererDomainJsonApi { + referer_domain: string; + count: number; +} diff --git a/src/app/features/analytics/models/node-analytics.model.ts b/src/app/features/analytics/models/node-analytics.model.ts new file mode 100644 index 000000000..8a4de7274 --- /dev/null +++ b/src/app/features/analytics/models/node-analytics.model.ts @@ -0,0 +1,31 @@ +export interface NodeAnalyticsModel { + id: string; + type: string; + popularPages: PopularPageModel[]; + uniqueVisits: UniqueVisitModel[]; + timeOfDay: TimeOfDayModel[]; + refererDomain: RefererDomainModel[]; + lastFetched?: number; +} + +export interface PopularPageModel { + path: string; + route: string; + title: string; + count: number; +} + +export interface UniqueVisitModel { + date: string; + count: number; +} + +export interface TimeOfDayModel { + hour: number; + count: number; +} + +export interface RefererDomainModel { + refererDomain: string; + count: number; +} diff --git a/src/app/features/analytics/services/analytics.service.ts b/src/app/features/analytics/services/analytics.service.ts index d621488a9..207a82e70 100644 --- a/src/app/features/analytics/services/analytics.service.ts +++ b/src/app/features/analytics/services/analytics.service.ts @@ -4,11 +4,10 @@ import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { ResourceType } from '@osf/shared/enums'; -import { JsonApiResponse } from '@osf/shared/models'; import { JsonApiService } from '@osf/shared/services'; import { AnalyticsMetricsMapper, RelatedCountsMapper } from '../mappers'; -import { AnalyticsMetricsGetResponse, AnalyticsMetricsModel, RelatedCountsGetResponse } from '../models'; +import { NodeAnalyticsModel, NodeAnalyticsResponseJsonApi, RelatedCountsGetResponse } from '../models'; @Injectable({ providedIn: 'root', @@ -26,11 +25,11 @@ export class AnalyticsService { [ResourceType.Registration, 'registrations'], ]); - getMetrics(resourceId: string, dateRange: string): Observable { + getMetrics(resourceId: string, dateRange: string): Observable { const baseUrl = `${this.apiDomainUrl}/_/metrics/query/node_analytics`; return this.jsonApiService - .get>(`${baseUrl}/${resourceId}/${dateRange}/`) + .get(`${baseUrl}/${resourceId}/${dateRange}/`) .pipe(map((response) => AnalyticsMetricsMapper.fromResponse(response.data))); } diff --git a/src/app/features/analytics/store/analytics.model.ts b/src/app/features/analytics/store/analytics.model.ts index 8f40c81ba..5bf841e7c 100644 --- a/src/app/features/analytics/store/analytics.model.ts +++ b/src/app/features/analytics/store/analytics.model.ts @@ -1,9 +1,9 @@ import { AsyncStateModel } from '@osf/shared/models/store'; -import { AnalyticsMetricsModel, RelatedCountsModel } from '../models'; +import { NodeAnalyticsModel, RelatedCountsModel } from '../models'; export interface AnalyticsStateModel { - metrics: AsyncStateModel; + metrics: AsyncStateModel; relatedCounts: AsyncStateModel; } diff --git a/src/app/features/analytics/store/analytics.state.ts b/src/app/features/analytics/store/analytics.state.ts index e491e688d..fa4ed078f 100644 --- a/src/app/features/analytics/store/analytics.state.ts +++ b/src/app/features/analytics/store/analytics.state.ts @@ -7,7 +7,7 @@ import { inject, Injectable } from '@angular/core'; import { handleSectionError } from '@osf/shared/helpers'; -import { AnalyticsMetricsModel, RelatedCountsModel } from '../models'; +import { NodeAnalyticsModel, RelatedCountsModel } from '../models'; import { AnalyticsService } from '../services'; import { ClearAnalytics, GetMetrics, GetRelatedCounts } from './analytics.actions'; @@ -52,8 +52,8 @@ export class AnalyticsState { ctx.patchState({ metrics: { data: exists - ? updateItem((m) => m.id === metrics.id, metrics)(state.metrics.data) - : insertItem(metrics)(state.metrics.data), + ? updateItem((m) => m.id === metrics.id, metrics)(state.metrics.data) + : insertItem(metrics)(state.metrics.data), isLoading: false, error: null, }, diff --git a/src/app/features/preprints/pages/preprint-details/preprint-details.component.html b/src/app/features/preprints/pages/preprint-details/preprint-details.component.html index 3fe079bf1..9285ba573 100644 --- a/src/app/features/preprints/pages/preprint-details/preprint-details.component.html +++ b/src/app/features/preprints/pages/preprint-details/preprint-details.component.html @@ -7,10 +7,13 @@
} @else { -
+ Provider Logo

{{ preprint()!.title }}

-
+ } @if (moderationMode()) { diff --git a/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts b/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts index 97b968a90..2e44cfc24 100644 --- a/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts +++ b/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts @@ -20,7 +20,7 @@ import { OnInit, } from '@angular/core'; import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { HelpScoutService } from '@core/services/help-scout.service'; @@ -71,6 +71,7 @@ import { PreprintWarningBannerComponent } from '../../components/preprint-detail PreprintWarningBannerComponent, ModerationStatusBannerComponent, MakeDecisionComponent, + RouterLink, ], templateUrl: './preprint-details.component.html', styleUrl: './preprint-details.component.scss', diff --git a/src/app/features/registries/components/confirm-registration-dialog/confirm-registration-dialog.component.html b/src/app/features/registries/components/confirm-registration-dialog/confirm-registration-dialog.component.html index f4df946e2..033bacab6 100644 --- a/src/app/features/registries/components/confirm-registration-dialog/confirm-registration-dialog.component.html +++ b/src/app/features/registries/components/confirm-registration-dialog/confirm-registration-dialog.component.html @@ -4,15 +4,19 @@ {{ 'registries.review.confirmation.text2' | translate }}

+

{{ 'registries.review.confirmation.text3' | translate }}

+

{{ 'registries.review.confirmation.text4' | translate }}

- ( - - {{ 'common.labels.learnMore' | translate }} - - ) + ({{ 'common.labels.learnMore' | translate }})

@@ -23,19 +27,22 @@ [inputId]="SubmitType.Public" [value]="SubmitType.Public" > - + + +
- + +
@if (showDateControl) { diff --git a/src/app/features/registries/components/registries-metadata-step/registries-license/registries-license.component.html b/src/app/features/registries/components/registries-metadata-step/registries-license/registries-license.component.html index 3f94d45df..da782b1e3 100644 --- a/src/app/features/registries/components/registries-metadata-step/registries-license/registries-license.component.html +++ b/src/app/features/registries/components/registries-metadata-step/registries-license/registries-license.component.html @@ -4,7 +4,8 @@

{{ 'shared.license.title' | translate }}

{{ 'shared.license.description' | translate }}

{{ 'shared.license.helpText' | translate }} - {{ 'common.links.helpGuide' | translate }} + {{ 'common.links.helpGuide' | translate }}.

{{ title() | translate }} @if (isLoading()) { } @else { -
-
- @if (data() && options() && labels().length) { - - } -
+
+ @if (data() && options() && labels().length) { + + } @if (showExpandedSection()) {
diff --git a/src/app/shared/components/doughnut-chart/doughnut-chart.component.html b/src/app/shared/components/doughnut-chart/doughnut-chart.component.html index e8c487bfc..b66fe02b4 100644 --- a/src/app/shared/components/doughnut-chart/doughnut-chart.component.html +++ b/src/app/shared/components/doughnut-chart/doughnut-chart.component.html @@ -6,7 +6,7 @@

{{ title() | translate }}

} @else {
-
+
@if (data() && options() && labels().length) { } diff --git a/src/app/shared/components/files-tree/files-tree.component.ts b/src/app/shared/components/files-tree/files-tree.component.ts index 7c0a86c40..d30868421 100644 --- a/src/app/shared/components/files-tree/files-tree.component.ts +++ b/src/app/shared/components/files-tree/files-tree.component.ts @@ -258,7 +258,7 @@ export class FilesTreeComponent implements OnDestroy, AfterViewInit { if (file.kind === 'file') { this.downloadFile(file.links.download); } else { - this.downloadFolder(file.id, false); + this.downloadFolder(file.links.download); } } @@ -347,17 +347,10 @@ export class FilesTreeComponent implements OnDestroy, AfterViewInit { window.open(link, '_blank', 'noopener,noreferrer'); } - downloadFolder(folderId: string, rootFolder: boolean): void { - const resourceId = this.resourceId(); - const storageLink = this.currentFolder()?.links?.download ?? ''; - if (resourceId && folderId) { - if (rootFolder) { - const link = this.filesService.getFolderDownloadLink(storageLink, '', true); - window.open(link, '_blank')?.focus(); - } else { - const link = this.filesService.getFolderDownloadLink(storageLink, folderId, false); - window.open(link, '_blank')?.focus(); - } + downloadFolder(downloadLink: string): void { + if (downloadLink) { + const link = this.filesService.getFolderDownloadLink(downloadLink, '', false); + window.open(link, '_blank')?.focus(); } } diff --git a/src/app/shared/mocks/analytics.mock.ts b/src/app/shared/mocks/analytics.mock.ts index 75fddfd5a..f74f1eba3 100644 --- a/src/app/shared/mocks/analytics.mock.ts +++ b/src/app/shared/mocks/analytics.mock.ts @@ -1,6 +1,6 @@ -import { AnalyticsMetricsModel, RelatedCountsModel } from '@osf/features/analytics/models'; +import { NodeAnalyticsModel, RelatedCountsModel } from '@osf/features/analytics/models'; -export const MOCK_ANALYTICS_METRICS: AnalyticsMetricsModel = { +export const MOCK_ANALYTICS_METRICS: NodeAnalyticsModel = { id: 'rid', type: 'analytics', uniqueVisits: [