Skip to content

Commit

Permalink
feat: differentiate data offer UI for on request asset (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
kulgg authored Jul 22, 2024
1 parent ff5b37f commit dd9d814
Show file tree
Hide file tree
Showing 18 changed files with 224 additions and 60 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ MDS 2.2 intermediate release

- Changed Broker to Catalog crawler on the dashboard and in the system stability report
- Data offer amounts now differentiate "On Request" Data Offers
- Differentiate live and on request data offers in card and detail dialog UI

#### Patch

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package de.sovity.authorityportal.api.model.catalog

import de.sovity.edc.ext.wrapper.api.common.model.DataSourceAvailability
import io.swagger.v3.oas.annotations.media.Schema
import java.time.OffsetDateTime

Expand All @@ -24,6 +25,12 @@ data class CatalogDataOffer(
@field:Schema(description = "Asset Title", requiredMode = Schema.RequiredMode.REQUIRED)
val assetTitle: String,

@field:Schema(
description = "Asset Datasource Availability (there are 'LIVE' and 'ON_REQUEST' Assets)",
requiredMode = Schema.RequiredMode.REQUIRED
)
val assetDataSourceAvailability: DataSourceAvailability,

@field:Schema(
description = "Asset Description Short Text generated from description. Contains no markdown.",
requiredMode = Schema.RequiredMode.NOT_REQUIRED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class CatalogQueryDataOfferFetcher(
val query = DSL.select(
d.ASSET_ID.`as`("assetId"),
d.ASSET_TITLE.`as`("assetTitle"),
fields.dataSourceAvailability.`as`("dataSourceAvailability"),
d.SHORT_DESCRIPTION_NO_MARKDOWN.`as`("shortDescriptionNoMarkdown"),
d.VERSION.`as`("version"),
d.KEYWORDS.`as`("keywords"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ class CatalogQueryFields(
dataSpace = buildDataSpaceField(connectorTable, dataSpaceConfigCatalog)
}

private fun buildDataSpaceField(connectorTable: Connector, dataSpaceConfigCatalog: CatalogDataspaceConfig): Field<String> {
return connectorTable.CONNECTOR_ID.mapInline(dataSpaceConfigCatalog.namesByConnectorId, dataSpaceConfigCatalog.defaultName)
private fun buildDataSpaceField(
connectorTable: Connector,
dataSpaceConfigCatalog: CatalogDataspaceConfig
): Field<String> {
return connectorTable.CONNECTOR_ID.mapInline(
dataSpaceConfigCatalog.namesByConnectorId,
dataSpaceConfigCatalog.defaultName
)
}

fun withSuffix(additionalSuffix: String): CatalogQueryFields {
Expand Down Expand Up @@ -80,11 +86,13 @@ class CatalogQueryFields(
return subquery.asField()
}

val dataSourceAvailability: Field<String> =
val dataSourceAvailabilityLabel: Field<String> =
DSL.case_(getAssetStringProperty("dataSourceAvailability"))
.`when`("ON_REQUEST", "On Request")
.else_("Available")

val dataSourceAvailability: Field<String> = getAssetStringProperty("dataSourceAvailability")

fun getAssetStringProperty(name: String): Field<String> {
return JsonbDSL.fieldByKeyText(dataOfferTable.UI_ASSET_JSON, name)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
package de.sovity.authorityportal.broker.dao.pages.catalog.models

import de.sovity.authorityportal.db.jooq.enums.ConnectorOnlineStatus
import de.sovity.edc.ext.wrapper.api.common.model.DataSourceAvailability
import java.time.OffsetDateTime

data class DataOfferListEntryRs(
val assetId: String,
val assetTitle: String,
val dataSourceAvailability: DataSourceAvailability,
val shortDescriptionNoMarkdown: String,
val version: String,
val keywords: List<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@
*/
package de.sovity.authorityportal.broker.services.api

import de.sovity.authorityportal.api.model.catalog.CatalogDataOffer
import de.sovity.authorityportal.api.model.catalog.CatalogPageQuery
import de.sovity.authorityportal.api.model.catalog.CatalogPageResult
import de.sovity.authorityportal.api.model.catalog.CatalogPageSortingItem
import de.sovity.authorityportal.api.model.catalog.CatalogPageSortingType
import de.sovity.authorityportal.api.model.catalog.ConnectorOnlineStatusDto
import de.sovity.authorityportal.api.model.catalog.*
import de.sovity.authorityportal.broker.dao.pages.catalog.CatalogQueryService
import de.sovity.authorityportal.broker.dao.pages.catalog.models.DataOfferListEntryRs
import de.sovity.authorityportal.broker.services.api.filtering.CatalogFilterService
Expand All @@ -34,7 +29,7 @@ class CatalogApiService(
val catalogQueryService: CatalogQueryService,
val catalogFilterService: CatalogFilterService,
val dsl: DSLContext,
val deploymentEnvironmentService: DeploymentEnvironmentService
val deploymentEnvironmentService: DeploymentEnvironmentService,
) {

fun catalogPage(environment: String, query: CatalogPageQuery): CatalogPageResult {
Expand Down Expand Up @@ -82,20 +77,19 @@ class CatalogApiService(
}
}

private fun buildCatalogDataOffer(dataOfferRs: DataOfferListEntryRs): CatalogDataOffer {
return CatalogDataOffer(
assetId = dataOfferRs.assetId,
assetTitle = dataOfferRs.assetTitle,
descriptionShortText = dataOfferRs.shortDescriptionNoMarkdown,
version = dataOfferRs.version,
keywords = dataOfferRs.keywords,
connectorId = dataOfferRs.connectorId,
organizationId = dataOfferRs.organizationId,
organizationName = dataOfferRs.organizationName,
connectorOnlineStatus = getOnlineStatus(dataOfferRs),
connectorOfflineSinceOrLastUpdatedAt = dataOfferRs.connectorOfflineSinceOrLastUpdatedAt
)
}
private fun buildCatalogDataOffer(dataOfferRs: DataOfferListEntryRs): CatalogDataOffer = CatalogDataOffer(
assetId = dataOfferRs.assetId,
assetTitle = dataOfferRs.assetTitle,
assetDataSourceAvailability = dataOfferRs.dataSourceAvailability,
descriptionShortText = dataOfferRs.shortDescriptionNoMarkdown,
version = dataOfferRs.version,
keywords = dataOfferRs.keywords,
connectorId = dataOfferRs.connectorId,
organizationId = dataOfferRs.organizationId,
organizationName = dataOfferRs.organizationName,
connectorOnlineStatus = getOnlineStatus(dataOfferRs),
connectorOfflineSinceOrLastUpdatedAt = dataOfferRs.connectorOfflineSinceOrLastUpdatedAt
)

private fun getOnlineStatus(dataOfferRs: DataOfferListEntryRs): ConnectorOnlineStatusDto {
return when (dataOfferRs.connectorOnlineStatus) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class CatalogFilterService(
*/
get() = listOf(
catalogFilterAttributeDefinitionService.forField(
{ fields: CatalogQueryFields -> fields.dataSourceAvailability },
{ fields: CatalogQueryFields -> fields.dataSourceAvailabilityLabel },
"dataSourceAvailability",
"Data Offer Type"
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class CatalogApiTest {
it.assetId = dummyDevAssetId(0)
it.title = "Data Offer 0"
it.description = "Data Offer 0 Description"
it.dataSourceAvailability = DataSourceAvailability.LIVE
it.dataSourceAvailability = DataSourceAvailability.ON_REQUEST
}

ScenarioData().apply {
Expand Down Expand Up @@ -265,11 +265,12 @@ class CatalogApiTest {
)

// assert
assertThat(result.dataOffers).hasSize(1)
assertThat(result.dataOffers.first().assetId).isEqualTo(dummyDevAssetId(0))
assertThat(result.dataOffers.first().assetTitle).isEqualTo("Data Offer 0")
assertThat(result.dataOffers.first().descriptionShortText).isEqualTo("shortDescription")
assertThat(result.dataOffers.first().connectorOnlineStatus).isEqualTo(ConnectorOnlineStatusDto.ONLINE)
val dataOffer = result.dataOffers.single()
assertThat(dataOffer.assetId).isEqualTo(dummyDevAssetId(0))
assertThat(dataOffer.assetTitle).isEqualTo("Data Offer 0")
assertThat(dataOffer.descriptionShortText).isEqualTo("shortDescription")
assertThat(dataOffer.connectorOnlineStatus).isEqualTo(ConnectorOnlineStatusDto.ONLINE)
assertThat(dataOffer.assetDataSourceAvailability).isEqualTo(DataSourceAvailability.ON_REQUEST)
}

@Test
Expand Down Expand Up @@ -485,9 +486,10 @@ class CatalogApiTest {
)

// assert
assertThat(result.dataOffers).hasSize(1)
assertThat(result.dataOffers.first().assetId).isEqualTo(dummyDevAssetId(0))
assertThat(result.dataOffers.first().assetTitle).isEqualTo("Hello")
val dataOffer = result.dataOffers.single()
assertThat(dataOffer.assetId).isEqualTo(dummyDevAssetId(0))
assertThat(dataOffer.assetTitle).isEqualTo("Hello")
assertThat(dataOffer.assetDataSourceAvailability).isEqualTo(DataSourceAvailability.LIVE)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
CatalogPageResult,
DataOfferDetailPageQuery,
DataOfferDetailPageResult,
DataSourceAvailability,
} from '@sovity.de/authority-portal-client';
import {subDays, subMinutes} from 'date-fns';
import {TestAssets} from './data/test-assets';
Expand Down Expand Up @@ -70,6 +71,25 @@ const DATA_OFFERS: DataOfferDetailPageResult[] = [
},
],
},
{
assetId: TestAssets.onRequestAsset.assetId,
assetTitle: TestAssets.onRequestAsset.title,
asset: TestAssets.onRequestAsset,
...myConnector,
viewCount: 55,
connectorOfflineSinceOrLastUpdatedAt: subMinutes(new Date(), 30),
updatedAt: subMinutes(new Date(), 5),
createdAt: subDays(new Date(), 30),
connectorOnlineStatus: 'ONLINE',
contractOffers: [
{
contractOfferId: 'on-request-contract-offer-1',
updatedAt: subMinutes(new Date(), 20),
createdAt: subDays(new Date(), 20),
contractPolicy: TestPolicies.failedMapping,
},
],
},
{
assetId: TestAssets.boring.assetId,
assetTitle: TestAssets.boring.title,
Expand Down Expand Up @@ -188,6 +208,7 @@ const buildCatalogDataOffer = (
): CatalogDataOffer => ({
assetId: it.assetId,
assetTitle: it.asset.title,
assetDataSourceAvailability: it.asset.dataSourceAvailability,
descriptionShortText: it.asset.descriptionShortText,
keywords: it.asset.keywords ?? [],
version: it.asset.version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ export namespace TestAssets {
This is a short description text that should be fully rendered without being **collapsed**. No *show more* button should be visible.
`;

export const onRequestAsset: UiAsset = {
dataSourceAvailability: 'ON_REQUEST',
assetId: 'comfee-or',
title: 'Comfee OR',
description: '',
descriptionShortText: '',
connectorEndpoint: 'https://my-other-connector/api/dsp',
participantId: 'MDSL1234XX.C1234XX',
creatorOrganizationName: 'my-org',
temporalCoverageFrom: new Date('2024-01-01'),
onRequestContactEmail: '[email protected]',
onRequestContactEmailSubject: "Request for asset 'comfee-or'",
isOwnConnector: false,
};

export const boring: UiAsset = {
assetId: 'data-sample-ckd-skd-demands-2023-Jan',
title: 'data-sample-ckd-skd-demands-2023-Jan',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,17 @@
* Contributors:
* sovity GmbH - initial implementation
*/
import { formatNumber } from '@angular/common';
import { Inject, Injectable, LOCALE_ID } from '@angular/core';

import {formatNumber} from '@angular/common';
import {Inject, Injectable, LOCALE_ID} from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class FormatService {

constructor(@Inject(LOCALE_ID) private locale: string) {}

formatNumber(value: number | null | undefined, digitsInfo?: string): string {
return value == null ? "" : formatNumber(value, this.locale, digitsInfo);
return value == null ? '' : formatNumber(value, this.locale, digitsInfo);
}

formatInteger(value: number | null | undefined): string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {Injectable} from '@angular/core';
import {removeUndefinedValues} from '../utils/record-utils';

@Injectable({providedIn: 'root'})
export class MailtoLinkBuilder {
private readonly MAILTO = 'mailto:';

constructor() {}

buildMailtoUrl(
email: string,
subject?: string,
body?: string,
cc?: string,
bcc?: string,
): string {
const queryParams = new URLSearchParams(
removeUndefinedValues({
subject,
body,
cc,
bcc,
}),
);
// URLSearchParams replaces spaces with '+', so we need to replace them with '%20' for the mail scenario
const queryParamsStr = queryParams.toString().replaceAll('+', '%20');
const queryStr = queryParamsStr ? `?${queryParamsStr}` : '';

return `${this.MAILTO}${email}${queryStr}`;
}
}
12 changes: 12 additions & 0 deletions authority-portal-frontend/src/app/core/utils/record-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export function removeNullValues(
);
}

/**
* Remove fields with undefined values from property records
* @param obj object / record
*/
export function removeUndefinedValues(
obj: Record<string, string | undefined>,
): Record<string, string> {
return Object.fromEntries(
Object.entries(obj).filter(([_, v]) => v != null) as [string, string][],
);
}

/**
* Maps keys of a given object
* @param obj object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,25 @@ export class AssetDetailDialogDataService {
...this.assetPropertyGridGroupBuilder.buildAdditionalPropertiesGroups(
dataOffer,
),
...dataOffer.contractOffers.map((contractOffer, i) =>
this.assetPropertyGridGroupBuilder.buildContractOfferGroup(
dataOffer,
contractOffer,
i,
dataOffer.contractOffers.length,
),
),
...(this.isOnRequestAsset(dataOffer)
? []
: dataOffer.contractOffers.map((contractOffer, i) =>
this.assetPropertyGridGroupBuilder.buildContractOfferGroup(
dataOffer,
contractOffer,
i,
dataOffer.contractOffers.length,
),
)),
].filter((it) => it.properties.length);

return {
dataOffer,
propertyGridGroups,
};
}

private isOnRequestAsset(dataOffer: DataOfferDetailPageResult): boolean {
return dataOffer.asset.dataSourceAvailability === 'ON_REQUEST';
}
}
Loading

0 comments on commit dd9d814

Please sign in to comment.