Feature/restructure holding detail dialog (#5058)

* Restructure holding detail dialog

* Update changelog
This commit is contained in:
csehatt741
2025-06-30 20:08:40 +02:00
committed by GitHub
parent dcf40367c1
commit aca2fe1654
2 changed files with 286 additions and 269 deletions

View File

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Moved the main content of the holding detail dialog to a new overview tab
- Introduced fuzzy search for the holdings of the assistant - Introduced fuzzy search for the holdings of the assistant
- Introduced fuzzy search for the quick links of the assistant - Introduced fuzzy search for the quick links of the assistant
- Improved the search results of the assistant to only display categories with content - Improved the search results of the assistant to only display categories with content

View File

@ -35,284 +35,300 @@
[symbol]="data.symbol" [symbol]="data.symbol"
/> />
<div class="row"> <mat-tab-group
<div class="col-6 mb-3"> animationDuration="0ms"
<gf-value class="mb-4"
i18n [mat-stretch-tabs]="false"
size="medium" >
[colorizeSign]="true" <mat-tab>
[isCurrency]="true" <ng-template mat-tab-label>
[locale]="data.locale" <ion-icon name="reader-outline" />
[precision]="netPerformanceWithCurrencyEffectPrecision" <div class="d-none d-sm-block ml-2" i18n>Overview</div>
[unit]="data.baseCurrency" </ng-template>
[value]="netPerformanceWithCurrencyEffect" <div class="container mt-3 p-0">
> <div class="row w-100">
@if ( <div class="col-6 mb-3">
SymbolProfile?.currency && <gf-value
data.baseCurrency !== SymbolProfile?.currency i18n
) { size="medium"
Change with currency effect [colorizeSign]="true"
} @else { [isCurrency]="true"
Change [locale]="data.locale"
} [precision]="netPerformanceWithCurrencyEffectPrecision"
</gf-value> [unit]="data.baseCurrency"
</div> [value]="netPerformanceWithCurrencyEffect"
<div class="col-6 mb-3"> >
<gf-value @if (
i18n SymbolProfile?.currency &&
size="medium" data.baseCurrency !== SymbolProfile?.currency
[colorizeSign]="true" ) {
[isPercent]="true" Change with currency effect
[locale]="data.locale" } @else {
[value]="netPerformancePercentWithCurrencyEffect" Change
> }
@if ( </gf-value>
SymbolProfile?.currency && </div>
data.baseCurrency !== SymbolProfile?.currency <div class="col-6 mb-3">
) { <gf-value
Performance with currency effect i18n
} @else { size="medium"
Performance [colorizeSign]="true"
} [isPercent]="true"
</gf-value> [locale]="data.locale"
</div> [value]="netPerformancePercentWithCurrencyEffect"
<div class="col-6 mb-3"> >
<gf-value @if (
i18n SymbolProfile?.currency &&
size="medium" data.baseCurrency !== SymbolProfile?.currency
[isCurrency]="true" ) {
[locale]="data.locale" Performance with currency effect
[unit]="SymbolProfile?.currency" } @else {
[value]="averagePrice" Performance
>Average Unit Price</gf-value }
> </gf-value>
</div> </div>
<div class="col-6 mb-3"> <div class="col-6 mb-3">
<gf-value <gf-value
i18n i18n
size="medium" size="medium"
[isCurrency]="true" [isCurrency]="true"
[locale]="data.locale" [locale]="data.locale"
[unit]="SymbolProfile?.currency" [unit]="SymbolProfile?.currency"
[value]="marketPrice" [value]="averagePrice"
>Market Price</gf-value >Average Unit Price</gf-value
> >
</div> </div>
<div class="col-6 mb-3"> <div class="col-6 mb-3">
<gf-value <gf-value
i18n i18n
size="medium" size="medium"
[isCurrency]="true" [isCurrency]="true"
[locale]="data.locale" [locale]="data.locale"
[ngClass]="{ [unit]="SymbolProfile?.currency"
'text-danger': [value]="marketPrice"
marketPriceMin?.toFixed(2) === marketPrice?.toFixed(2) && >Market Price</gf-value
marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2) >
}" </div>
[unit]="SymbolProfile?.currency" <div class="col-6 mb-3">
[value]="marketPriceMin" <gf-value
>Minimum Price</gf-value i18n
> size="medium"
</div> [isCurrency]="true"
<div class="col-6 mb-3"> [locale]="data.locale"
<gf-value [ngClass]="{
i18n 'text-danger':
size="medium" marketPriceMin?.toFixed(2) === marketPrice?.toFixed(2) &&
[isCurrency]="true" marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2)
[locale]="data.locale" }"
[ngClass]="{ [unit]="SymbolProfile?.currency"
'text-success': [value]="marketPriceMin"
marketPriceMax?.toFixed(2) === marketPrice?.toFixed(2) && >Minimum Price</gf-value
marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2) >
}" </div>
[unit]="SymbolProfile?.currency" <div class="col-6 mb-3">
[value]="marketPriceMax" <gf-value
>Maximum Price</gf-value i18n
> size="medium"
</div> [isCurrency]="true"
<div class="col-6 mb-3"> [locale]="data.locale"
<gf-value [ngClass]="{
i18n 'text-success':
size="medium" marketPriceMax?.toFixed(2) === marketPrice?.toFixed(2) &&
[locale]="data.locale" marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2)
[precision]="quantityPrecision" }"
[value]="quantity" [unit]="SymbolProfile?.currency"
>Quantity</gf-value [value]="marketPriceMax"
> >Maximum Price</gf-value
</div> >
<div class="col-6 mb-3"> </div>
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[precision]="investmentInBaseCurrencyWithCurrencyEffectPrecision"
[unit]="data.baseCurrency"
[value]="investmentInBaseCurrencyWithCurrencyEffect"
>Investment</gf-value
>
</div>
@if (dividendInBaseCurrency && user?.settings?.isExperimentalFeatures) {
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[precision]="dividendInBaseCurrencyPrecision"
[unit]="data.baseCurrency"
[value]="dividendInBaseCurrency"
>Dividend</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isPercent]="true"
[locale]="data.locale"
[value]="dividendYieldPercentWithCurrencyEffect"
>Dividend Yield</gf-value
>
</div>
}
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[unit]="data.baseCurrency"
[value]="feeInBaseCurrency"
>Fees</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isDate]="true"
[locale]="data.locale"
[value]="firstBuyDate"
>First Activity</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
size="medium"
[locale]="data.locale"
[value]="transactionCount"
>
@if (transactionCount === 1) {
<ng-container i18n>Activity</ng-container>
} @else {
<ng-container i18n>Activities</ng-container>
}
</gf-value>
</div>
<div class="col-6 mb-3"></div>
<div class="col-6 mb-3">
<gf-value i18n size="medium" [hidden]="!assetClass" [value]="assetClass"
>Asset Class</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[hidden]="!assetSubClass"
[value]="assetSubClass"
>Asset Sub Class</gf-value
>
</div>
@if (
SymbolProfile?.countries?.length > 0 ||
SymbolProfile?.sectors?.length > 0
) {
@if (
SymbolProfile?.countries?.length === 1 &&
SymbolProfile?.sectors?.length === 1
) {
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.sectors[0].name"
>Sector</gf-value
>
</div>
@if (SymbolProfile?.countries?.length === 1) {
<div class="col-6 mb-3"> <div class="col-6 mb-3">
<gf-value <gf-value
i18n i18n
size="medium" size="medium"
[locale]="data.locale" [locale]="data.locale"
[value]="SymbolProfile.countries[0].name" [precision]="quantityPrecision"
>Country</gf-value [value]="quantity"
>Quantity</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[precision]="
investmentInBaseCurrencyWithCurrencyEffectPrecision
"
[unit]="data.baseCurrency"
[value]="investmentInBaseCurrencyWithCurrencyEffect"
>Investment</gf-value
>
</div>
@if (
dividendInBaseCurrency && user?.settings?.isExperimentalFeatures
) {
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[precision]="dividendInBaseCurrencyPrecision"
[unit]="data.baseCurrency"
[value]="dividendInBaseCurrency"
>Dividend</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isPercent]="true"
[locale]="data.locale"
[value]="dividendYieldPercentWithCurrencyEffect"
>Dividend Yield</gf-value
>
</div>
}
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[unit]="data.baseCurrency"
[value]="feeInBaseCurrency"
>Fees</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isDate]="true"
[locale]="data.locale"
[value]="firstBuyDate"
>First Activity</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
size="medium"
[locale]="data.locale"
[value]="transactionCount"
>
@if (transactionCount === 1) {
<ng-container i18n>Activity</ng-container>
} @else {
<ng-container i18n>Activities</ng-container>
}
</gf-value>
</div>
<div class="col-6 mb-3"></div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[hidden]="!assetClass"
[value]="assetClass"
>Asset Class</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[hidden]="!assetSubClass"
[value]="assetSubClass"
>Asset Sub Class</gf-value
>
</div>
@if (
SymbolProfile?.countries?.length > 0 ||
SymbolProfile?.sectors?.length > 0
) {
@if (
SymbolProfile?.countries?.length === 1 &&
SymbolProfile?.sectors?.length === 1
) {
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.sectors[0].name"
>Sector</gf-value
>
</div>
@if (SymbolProfile?.countries?.length === 1) {
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.countries[0].name"
>Country</gf-value
>
</div>
}
} @else {
<div class="col-md-6 mb-3">
<div class="h5" i18n>Sectors</div>
<gf-portfolio-proportion-chart
[baseCurrency]="data.baseCurrency"
[colorScheme]="data.colorScheme"
[data]="sectors"
[isInPercent]="true"
[keys]="['name']"
[locale]="data.locale"
[maxItems]="10"
/>
</div>
<div class="col-md-6 mb-3">
<div class="h5" i18n>Countries</div>
<gf-portfolio-proportion-chart
[baseCurrency]="data.baseCurrency"
[colorScheme]="data.colorScheme"
[data]="countries"
[isInPercent]="true"
[keys]="['name']"
[locale]="data.locale"
[maxItems]="10"
/>
</div>
}
}
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[hidden]="!SymbolProfile?.symbol"
[value]="SymbolProfile?.symbol"
>Symbol</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
size="medium"
[hidden]="!SymbolProfile?.isin"
[value]="SymbolProfile?.isin"
>ISIN</gf-value
> >
</div> </div>
}
} @else {
<div class="col-md-6 mb-3">
<div class="h5" i18n>Sectors</div>
<gf-portfolio-proportion-chart
[baseCurrency]="data.baseCurrency"
[colorScheme]="data.colorScheme"
[data]="sectors"
[isInPercent]="true"
[keys]="['name']"
[locale]="data.locale"
[maxItems]="10"
/>
</div>
<div class="col-md-6 mb-3">
<div class="h5" i18n>Countries</div>
<gf-portfolio-proportion-chart
[baseCurrency]="data.baseCurrency"
[colorScheme]="data.colorScheme"
[data]="countries"
[isInPercent]="true"
[keys]="['name']"
[locale]="data.locale"
[maxItems]="10"
/>
</div>
}
}
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[hidden]="!SymbolProfile?.symbol"
[value]="SymbolProfile?.symbol"
>Symbol</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
size="medium"
[hidden]="!SymbolProfile?.isin"
[value]="SymbolProfile?.isin"
>ISIN</gf-value
>
</div>
@if (dataProviderInfo) { @if (dataProviderInfo) {
<div class="col-md-12 mb-3 text-center"> <div class="col-md-12 mb-3 text-center">
<hr /> <hr />
<gf-data-provider-credits [dataProviderInfos]="[dataProviderInfo]" /> <gf-data-provider-credits
<hr /> [dataProviderInfos]="[dataProviderInfo]"
/>
<hr />
</div>
}
</div>
</div> </div>
} </mat-tab>
</div>
<mat-tab-group
animationDuration="0ms"
class="mb-5"
[mat-stretch-tabs]="false"
[ngClass]="{ 'd-none': !dataSource?.data.length }"
>
<mat-tab> <mat-tab>
<ng-template mat-tab-label> <ng-template mat-tab-label>
<ion-icon name="swap-vertical-outline" /> <ion-icon name="swap-vertical-outline" />