mirror of https://github.com/ghostfolio/ghostfolio
committed by
GitHub
298 changed files with 35561 additions and 117107 deletions
@ -1,4 +1,5 @@ |
|||||
/.nx/cache |
/.nx/cache |
||||
|
/.nx/workspace-data |
||||
/apps/client/src/polyfills.ts |
/apps/client/src/polyfills.ts |
||||
/dist |
/dist |
||||
/test/import |
/test/import |
||||
|
@ -0,0 +1,29 @@ |
|||||
|
import { AdminService } from '@ghostfolio/api/app/admin/admin.service'; |
||||
|
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; |
||||
|
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; |
||||
|
import type { AdminMarketDataDetails } from '@ghostfolio/common/interfaces'; |
||||
|
|
||||
|
import { Controller, Get, Param, UseInterceptors } from '@nestjs/common'; |
||||
|
import { DataSource } from '@prisma/client'; |
||||
|
import { pick } from 'lodash'; |
||||
|
|
||||
|
@Controller('asset') |
||||
|
export class AssetController { |
||||
|
public constructor(private readonly adminService: AdminService) {} |
||||
|
|
||||
|
@Get(':dataSource/:symbol') |
||||
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
||||
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
||||
|
public async getAsset( |
||||
|
@Param('dataSource') dataSource: DataSource, |
||||
|
@Param('symbol') symbol: string |
||||
|
): Promise<AdminMarketDataDetails> { |
||||
|
const { assetProfile, marketData } = |
||||
|
await this.adminService.getMarketDataBySymbol({ dataSource, symbol }); |
||||
|
|
||||
|
return { |
||||
|
marketData, |
||||
|
assetProfile: pick(assetProfile, ['dataSource', 'name', 'symbol']) |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
import { AdminModule } from '@ghostfolio/api/app/admin/admin.module'; |
||||
|
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; |
||||
|
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; |
||||
|
|
||||
|
import { Module } from '@nestjs/common'; |
||||
|
|
||||
|
import { AssetController } from './asset.controller'; |
||||
|
|
||||
|
@Module({ |
||||
|
controllers: [AssetController], |
||||
|
imports: [ |
||||
|
AdminModule, |
||||
|
TransformDataSourceInRequestModule, |
||||
|
TransformDataSourceInResponseModule |
||||
|
] |
||||
|
}) |
||||
|
export class AssetModule {} |
@ -0,0 +1,6 @@ |
|||||
|
import { IsString } from 'class-validator'; |
||||
|
|
||||
|
export class DeleteOwnUserDto { |
||||
|
@IsString() |
||||
|
accessToken: string; |
||||
|
} |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,4 @@ |
|||||
|
import { Module } from '@nestjs/common'; |
||||
|
|
||||
|
@Module({}) |
||||
|
export class RedactValuesInResponseModule {} |
@ -0,0 +1,11 @@ |
|||||
|
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; |
||||
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; |
||||
|
|
||||
|
import { Module } from '@nestjs/common'; |
||||
|
|
||||
|
@Module({ |
||||
|
exports: [ConfigurationService], |
||||
|
imports: [ConfigurationModule], |
||||
|
providers: [ConfigurationService] |
||||
|
}) |
||||
|
export class TransformDataSourceInRequestModule {} |
@ -0,0 +1,11 @@ |
|||||
|
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; |
||||
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; |
||||
|
|
||||
|
import { Module } from '@nestjs/common'; |
||||
|
|
||||
|
@Module({ |
||||
|
exports: [ConfigurationService], |
||||
|
imports: [ConfigurationModule], |
||||
|
providers: [ConfigurationService] |
||||
|
}) |
||||
|
export class TransformDataSourceInResponseModule {} |
@ -0,0 +1,44 @@ |
|||||
|
import { DERIVED_CURRENCIES } from '@ghostfolio/common/config'; |
||||
|
|
||||
|
import { |
||||
|
registerDecorator, |
||||
|
ValidationOptions, |
||||
|
ValidatorConstraint, |
||||
|
ValidatorConstraintInterface, |
||||
|
ValidationArguments |
||||
|
} from 'class-validator'; |
||||
|
import { isISO4217CurrencyCode } from 'class-validator'; |
||||
|
|
||||
|
export function IsCurrencyCode(validationOptions?: ValidationOptions) { |
||||
|
return function (object: Object, propertyName: string) { |
||||
|
registerDecorator({ |
||||
|
propertyName, |
||||
|
constraints: [], |
||||
|
options: validationOptions, |
||||
|
target: object.constructor, |
||||
|
validator: IsExtendedCurrencyConstraint |
||||
|
}); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
@ValidatorConstraint({ async: false }) |
||||
|
export class IsExtendedCurrencyConstraint |
||||
|
implements ValidatorConstraintInterface |
||||
|
{ |
||||
|
public defaultMessage(args: ValidationArguments) { |
||||
|
return '$value must be a valid ISO4217 currency code'; |
||||
|
} |
||||
|
|
||||
|
public validate(currency: any) { |
||||
|
// Return true if currency is a standard ISO 4217 code or a derived currency
|
||||
|
return ( |
||||
|
isISO4217CurrencyCode(currency) || |
||||
|
[ |
||||
|
...DERIVED_CURRENCIES.map((derivedCurrency) => { |
||||
|
return derivedCurrency.currency; |
||||
|
}), |
||||
|
'USX' |
||||
|
].includes(currency) |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
-----BEGIN CERTIFICATE----- |
||||
|
MIIC5TCCAc2gAwIBAgIJAJAMHOFnJ6oyMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV |
||||
|
BAMMCWxvY2FsaG9zdDAeFw0yNDAyMjcxNTQ2MzFaFw0yNDAzMjgxNTQ2MzFaMBQx |
||||
|
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC |
||||
|
ggEBAJ0hRjViikEKVIyukXR4CfuYVvFEFzB6AwAQ9Jrz2MseqpLacLTXFFAS54mp |
||||
|
iDuqPBzs9ta40mlSrqSBuAWKikpW5kTNnmqUnDZ6iSJezbYWx9YyULGqqb1q3C4/ |
||||
|
5pH9m6NHJ+2uaUNKlDxYNKbntqs3drQEdxH9yv672Z53nvogTcf9jz6zjutEQGSV |
||||
|
HgVkCTTQmzf3+3st+VJ5D8JeYFR+tpZ6yleqgXFaTMtPZRfKLvTkQ+KeyCJLnsUJ |
||||
|
BQvdCKI0PGsG6d6ygXFmSePolD9KW3VTKKDPCsndID89vAnRWDj9UhzvycxmKpcF |
||||
|
GrUPH5+Pis1PM1R7OnAvnFygnyECAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo |
||||
|
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B |
||||
|
AQsFAAOCAQEAOdzrY3RTAPnBVAd3/GKIEkielYyOgKPnvd+RcOB+je8cXZY+vaxX |
||||
|
uEFP0526G00+kRZ2Tx9t0SmjoSpwg3lHUPMko0dIxgRlqISDAohdrEptHpcVujsD |
||||
|
ak88LLnAurr60JNjWX2wbEoJ18KLtqGSnATdmCgKwDPIN5a7+ssp44BGyzH6VYCg |
||||
|
wV3VjJl0pp4C5M0Jfu0p1FrQjzIVhgqR7JFYmvqIogWrGwYAQK/3XRXq8t48J5X3 |
||||
|
IsfWiLAA2ZdCoWAnZ6PAGBOoGivtkJm967pHjd/28qYY6mQo4sN2ksEOjx6/YslF |
||||
|
2mOJdLV/DzqoggUsTpPEG0dRhzQLTGHKDQ== |
||||
|
-----END CERTIFICATE----- |
@ -0,0 +1,28 @@ |
|||||
|
-----BEGIN PRIVATE KEY----- |
||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCdIUY1YopBClSM |
||||
|
rpF0eAn7mFbxRBcwegMAEPSa89jLHqqS2nC01xRQEueJqYg7qjwc7PbWuNJpUq6k |
||||
|
gbgFiopKVuZEzZ5qlJw2eokiXs22FsfWMlCxqqm9atwuP+aR/ZujRyftrmlDSpQ8 |
||||
|
WDSm57arN3a0BHcR/cr+u9med576IE3H/Y8+s47rREBklR4FZAk00Js39/t7LflS |
||||
|
eQ/CXmBUfraWespXqoFxWkzLT2UXyi705EPinsgiS57FCQUL3QiiNDxrBunesoFx |
||||
|
Zknj6JQ/Slt1UyigzwrJ3SA/PbwJ0Vg4/VIc78nMZiqXBRq1Dx+fj4rNTzNUezpw |
||||
|
L5xcoJ8hAgMBAAECggEAPU5YOEgELTA8oM8TjV+wdWuQsH2ilpVkSkhTR4nQkh+a |
||||
|
6cU0qDoqgLt/fySYNL9MyPRjso9V+SX7YdAC3paZMjwJh9q57lehQ1g33SMkG+Fz |
||||
|
gs0K0ucFZxQkaB8idN+ANAp1N7UO+ORGRe0cTeqmSNNRCxea5XgiFZVxaPS/IFOR |
||||
|
vVdXS1DulgwHh4H0ljKmkj7jc9zPBSc9ccW5Ml2q4a26Atu4IC/Mlp/DF4GNELbD |
||||
|
ebi9ZOZG33ip2bdhj3WX7NW9GJaaViKtVUpcpR6u+6BfvTXQ6xrqdoxXk9fnPzzf |
||||
|
sSoLPTt8yO4RavP1zQU22PhgIcWudhCiy/2Nv+uLqQKBgQDMPh1/xwdFl8yES8dy |
||||
|
f0xJyCDWPiB+xzGwcOAC90FrNZaqG0WWs3VHE4cilaWjCflvdR6aAEDEY68sZJhl |
||||
|
h+ChT/g61QLMOI+VIDQ1kJXKYgfS/B+BE1PZ0EkuymKFOvbNO8agHodB8CqnZaQh |
||||
|
bLuZaDnZ0JLK4im3KPt70+aKYwKBgQDE8s6xl0SLu+yJLo3VklCRD67Z8/jlvx2t |
||||
|
h3DF6NG8pB3QmvKdJWFKuLAWLGflJwbUW9Pt3hXkc0649KQrtiIYC0ZMh9KMaVCk |
||||
|
WmjS/n2eIUQZ7ZUlwFesi4p4iGynVBavIY8TJ6Y+K3TvsJgXP3IZ96r689PQJo8E |
||||
|
KbSeyYzFqwKBgGQTS4EAlJ+U8bEhMGj51veQCAbyChoUoFRD+n95h6RwbZKMKlzd |
||||
|
MenRt7VKfg6VJJNoX8Y1uYaBEaQ+5i1Zlsdz1718AhLu4+u+C9bzMXIo9ox63TTx |
||||
|
s3RWioVSxVNiwOtvDrQGQWAdvcioFPQLwyA34aDIgiTHDImimxbhjWThAoGAWOqW |
||||
|
Tq9QjxWk0Lpn5ohMP3GpK1VuhasnJvUDARb/uf8ORuPtrOz3Y9jGBvy9W0OnXbCn |
||||
|
mbiugZldbTtl8yYjdl+AuYSIlkPl2I3IzZl/9Shnqp0MvSJ9crT9KzXMeC8Knr6z |
||||
|
7Z30/BR6ksxTngtS5E5grzPt6Qe/gc2ich3kpEkCgYBfBHUhVIKVrDW/8a7U2679 |
||||
|
Wj4i9us/M3iPMxcTv7/ZAg08TEvNBQYtvVQLu0NfDKXx8iGKJJ6evIYgNXVm2sPq |
||||
|
VzSgwGCALi1X0443amZU+mnX+/9RnBqyM+PJU8570mM83jqKlY/BEsi0aqxTioFG |
||||
|
an3xbjjN+Rq9iKLzmPxIMg== |
||||
|
-----END PRIVATE KEY----- |
@ -1,67 +1,71 @@ |
|||||
<table class="gf-table w-100" mat-table [dataSource]="dataSource"> |
<div class="overflow-x-auto"> |
||||
<ng-container matColumnDef="alias"> |
<table class="gf-table w-100" mat-table [dataSource]="dataSource"> |
||||
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Alias</th> |
<ng-container matColumnDef="alias"> |
||||
<td *matCellDef="let element" class="px-1" mat-cell> |
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Alias</th> |
||||
{{ element.alias }} |
<td *matCellDef="let element" class="px-1" mat-cell> |
||||
</td> |
{{ element.alias }} |
||||
</ng-container> |
</td> |
||||
|
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="grantee"> |
<ng-container matColumnDef="grantee"> |
||||
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Grantee</th> |
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Grantee</th> |
||||
<td *matCellDef="let element" class="px-1" mat-cell> |
<td *matCellDef="let element" class="px-1" mat-cell> |
||||
{{ element.grantee }} |
{{ element.grantee }} |
||||
</td> |
</td> |
||||
</ng-container> |
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="type"> |
<ng-container matColumnDef="type"> |
||||
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Permission</th> |
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Permission</th> |
||||
<td *matCellDef="let element" class="px-1 text-nowrap" mat-cell> |
<td *matCellDef="let element" class="px-1 text-nowrap" mat-cell> |
||||
<div class="align-items-center d-flex"> |
<div class="align-items-center d-flex"> |
||||
@if (element.permissions.includes('READ')) { |
@if (element.permissions.includes('READ')) { |
||||
<ion-icon class="mr-1" name="lock-open-outline" /> |
<ion-icon class="mr-1" name="lock-open-outline" /> |
||||
<ng-container i18n>View</ng-container> |
<ng-container i18n>View</ng-container> |
||||
} @else if (element.permissions.includes('READ_RESTRICTED')) { |
} @else if (element.permissions.includes('READ_RESTRICTED')) { |
||||
<ion-icon class="mr-1" name="lock-closed-outline" /> |
<ion-icon class="mr-1" name="lock-closed-outline" /> |
||||
<ng-container i18n>Restricted view</ng-container> |
<ng-container i18n>Restricted view</ng-container> |
||||
} |
} |
||||
</div> |
</div> |
||||
</td> |
</td> |
||||
</ng-container> |
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="details"> |
<ng-container matColumnDef="details"> |
||||
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Details</th> |
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Details</th> |
||||
<td *matCellDef="let element" class="px-1 text-nowrap" mat-cell> |
<td *matCellDef="let element" class="px-1 text-nowrap" mat-cell> |
||||
<div *ngIf="element.type === 'PUBLIC'" class="align-items-center d-flex"> |
@if (element.type === 'PUBLIC') { |
||||
<ion-icon class="mr-1" name="link-outline" /> |
<div class="align-items-center d-flex"> |
||||
<a |
<ion-icon class="mr-1" name="link-outline" /> |
||||
href="{{ baseUrl }}/{{ defaultLanguageCode }}/p/{{ element.id }}" |
<a |
||||
target="_blank" |
href="{{ baseUrl }}/{{ defaultLanguageCode }}/p/{{ element.id }}" |
||||
>{{ baseUrl }}/{{ defaultLanguageCode }}/p/{{ element.id }}</a |
target="_blank" |
||||
> |
>{{ baseUrl }}/{{ defaultLanguageCode }}/p/{{ element.id }}</a |
||||
</div> |
> |
||||
</td> |
</div> |
||||
</ng-container> |
} |
||||
|
</td> |
||||
|
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="actions" stickyEnd> |
<ng-container matColumnDef="actions" stickyEnd> |
||||
<th *matHeaderCellDef class="px-1 text-center" mat-header-cell></th> |
<th *matHeaderCellDef class="px-1 text-center" mat-header-cell></th> |
||||
|
|
||||
<td *matCellDef="let element" class="px-1 text-center" mat-cell> |
<td *matCellDef="let element" class="px-1 text-center" mat-cell> |
||||
<button |
<button |
||||
class="mx-1 no-min-width px-2" |
class="mx-1 no-min-width px-2" |
||||
mat-button |
mat-button |
||||
[matMenuTriggerFor]="transactionMenu" |
[matMenuTriggerFor]="transactionMenu" |
||||
(click)="$event.stopPropagation()" |
(click)="$event.stopPropagation()" |
||||
> |
> |
||||
<ion-icon name="ellipsis-horizontal" /> |
<ion-icon name="ellipsis-horizontal" /> |
||||
</button> |
|
||||
<mat-menu #transactionMenu="matMenu" xPosition="before"> |
|
||||
<button mat-menu-item (click)="onDeleteAccess(element.id)"> |
|
||||
<ng-container i18n>Revoke</ng-container> |
|
||||
</button> |
</button> |
||||
</mat-menu> |
<mat-menu #transactionMenu="matMenu" xPosition="before"> |
||||
</td> |
<button mat-menu-item (click)="onDeleteAccess(element.id)"> |
||||
</ng-container> |
<ng-container i18n>Revoke</ng-container> |
||||
|
</button> |
||||
|
</mat-menu> |
||||
|
</td> |
||||
|
</ng-container> |
||||
|
|
||||
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> |
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> |
||||
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr> |
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr> |
||||
</table> |
</table> |
||||
|
</div> |
||||
|
@ -1,296 +1,322 @@ |
|||||
<div *ngIf="showActions" class="d-flex justify-content-end"> |
@if (showActions) { |
||||
<button |
<div class="d-flex justify-content-end"> |
||||
class="align-items-center d-flex" |
<button |
||||
mat-stroked-button |
class="align-items-center d-flex" |
||||
[disabled]="dataSource?.data.length < 2" |
mat-stroked-button |
||||
(click)="onTransferBalance()" |
[disabled]="dataSource?.data.length < 2" |
||||
> |
(click)="onTransferBalance()" |
||||
<ion-icon class="mr-2" name="arrow-redo-outline" /> |
> |
||||
<ng-container i18n>Transfer Cash Balance</ng-container>... |
<ion-icon class="mr-2" name="arrow-redo-outline" /> |
||||
</button> |
<ng-container i18n>Transfer Cash Balance</ng-container>... |
||||
</div> |
</button> |
||||
|
</div> |
||||
<table class="gf-table w-100" mat-table matSort [dataSource]="dataSource"> |
} |
||||
<ng-container matColumnDef="status"> |
|
||||
<th |
|
||||
*matHeaderCellDef |
|
||||
class="d-none d-lg-table-cell px-1" |
|
||||
mat-header-cell |
|
||||
></th> |
|
||||
<td *matCellDef="let element" class="d-none d-lg-table-cell px-1" mat-cell> |
|
||||
<div class="d-flex justify-content-center"> |
|
||||
<ion-icon *ngIf="element.isExcluded" name="eye-off-outline" /> |
|
||||
</div> |
|
||||
</td> |
|
||||
<td |
|
||||
*matFooterCellDef |
|
||||
class="d-none d-lg-table-cell px-1" |
|
||||
mat-footer-cell |
|
||||
></td> |
|
||||
</ng-container> |
|
||||
|
|
||||
<ng-container matColumnDef="account"> |
<div class="overflow-x-auto"> |
||||
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header="name"> |
<table class="gf-table w-100" mat-table matSort [dataSource]="dataSource"> |
||||
<ng-container i18n>Name</ng-container> |
<ng-container matColumnDef="status"> |
||||
</th> |
<th |
||||
<td *matCellDef="let element" class="px-1" mat-cell> |
*matHeaderCellDef |
||||
<gf-asset-profile-icon |
class="d-none d-lg-table-cell px-1" |
||||
*ngIf="element.Platform?.url" |
mat-header-cell |
||||
class="d-inline d-sm-none mr-1" |
></th> |
||||
[tooltip]="element.Platform?.name" |
<td |
||||
[url]="element.Platform?.url" |
*matCellDef="let element" |
||||
/> |
class="d-none d-lg-table-cell px-1" |
||||
<span>{{ element.name }}</span> |
mat-cell |
||||
</td> |
> |
||||
<td *matFooterCellDef class="px-1" i18n mat-footer-cell>Total</td> |
<div class="d-flex justify-content-center"> |
||||
</ng-container> |
@if (element.isExcluded) { |
||||
|
<ion-icon name="eye-off-outline" /> |
||||
|
} |
||||
|
</div> |
||||
|
</td> |
||||
|
<td |
||||
|
*matFooterCellDef |
||||
|
class="d-none d-lg-table-cell px-1" |
||||
|
mat-footer-cell |
||||
|
></td> |
||||
|
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="currency"> |
<ng-container matColumnDef="account"> |
||||
<th |
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header="name"> |
||||
*matHeaderCellDef |
<ng-container i18n>Name</ng-container> |
||||
class="d-none d-lg-table-cell px-1" |
</th> |
||||
mat-header-cell |
<td *matCellDef="let element" class="px-1" mat-cell> |
||||
mat-sort-header |
@if (element.Platform?.url) { |
||||
> |
<gf-asset-profile-icon |
||||
<ng-container i18n>Currency</ng-container> |
class="d-inline d-sm-none mr-1" |
||||
</th> |
[tooltip]="element.Platform?.name" |
||||
<td *matCellDef="let element" class="d-none d-lg-table-cell px-1" mat-cell> |
[url]="element.Platform?.url" |
||||
{{ element.currency }} |
/> |
||||
</td> |
} |
||||
<td *matFooterCellDef class="d-none d-lg-table-cell px-1" mat-footer-cell> |
<span>{{ element.name }}</span> |
||||
{{ baseCurrency }} |
</td> |
||||
</td> |
<td *matFooterCellDef class="px-1" i18n mat-footer-cell>Total</td> |
||||
</ng-container> |
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="platform"> |
<ng-container matColumnDef="currency"> |
||||
<th |
<th |
||||
*matHeaderCellDef |
*matHeaderCellDef |
||||
class="d-none d-lg-table-cell px-1" |
class="d-none d-lg-table-cell px-1" |
||||
mat-header-cell |
mat-header-cell |
||||
mat-sort-header="Platform.name" |
mat-sort-header |
||||
> |
> |
||||
<ng-container i18n>Platform</ng-container> |
<ng-container i18n>Currency</ng-container> |
||||
</th> |
</th> |
||||
<td *matCellDef="let element" class="d-none d-lg-table-cell px-1" mat-cell> |
<td |
||||
<div class="d-flex"> |
*matCellDef="let element" |
||||
<gf-asset-profile-icon |
class="d-none d-lg-table-cell px-1" |
||||
*ngIf="element.Platform?.url" |
mat-cell |
||||
class="mr-1" |
> |
||||
[tooltip]="element.Platform?.name" |
{{ element.currency }} |
||||
[url]="element.Platform?.url" |
</td> |
||||
/> |
<td *matFooterCellDef class="d-none d-lg-table-cell px-1" mat-footer-cell> |
||||
<span>{{ element.Platform?.name }}</span> |
{{ baseCurrency }} |
||||
</div> |
</td> |
||||
</td> |
</ng-container> |
||||
<td |
|
||||
*matFooterCellDef |
|
||||
class="d-none d-lg-table-cell px-1" |
|
||||
mat-footer-cell |
|
||||
></td> |
|
||||
</ng-container> |
|
||||
|
|
||||
<ng-container matColumnDef="transactions"> |
<ng-container matColumnDef="platform"> |
||||
<th |
<th |
||||
*matHeaderCellDef |
*matHeaderCellDef |
||||
class="justify-content-end px-1" |
class="d-none d-lg-table-cell px-1" |
||||
mat-header-cell |
mat-header-cell |
||||
mat-sort-header="transactionCount" |
mat-sort-header="Platform.name" |
||||
> |
> |
||||
<span class="d-block d-sm-none">#</span> |
<ng-container i18n>Platform</ng-container> |
||||
<span class="d-none d-sm-block" i18n>Activities</span> |
</th> |
||||
</th> |
<td |
||||
<td *matCellDef="let element" class="px-1 text-right" mat-cell> |
*matCellDef="let element" |
||||
{{ element.transactionCount }} |
class="d-none d-lg-table-cell px-1" |
||||
</td> |
mat-cell |
||||
<td *matFooterCellDef class="px-1 text-right" mat-footer-cell> |
> |
||||
{{ transactionCount }} |
<div class="d-flex"> |
||||
</td> |
@if (element.Platform?.url) { |
||||
</ng-container> |
<gf-asset-profile-icon |
||||
|
class="mr-1" |
||||
|
[tooltip]="element.Platform?.name" |
||||
|
[url]="element.Platform?.url" |
||||
|
/> |
||||
|
} |
||||
|
<span>{{ element.Platform?.name }}</span> |
||||
|
</div> |
||||
|
</td> |
||||
|
<td |
||||
|
*matFooterCellDef |
||||
|
class="d-none d-lg-table-cell px-1" |
||||
|
mat-footer-cell |
||||
|
></td> |
||||
|
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="balance"> |
<ng-container matColumnDef="transactions"> |
||||
<th |
<th |
||||
*matHeaderCellDef |
*matHeaderCellDef |
||||
class="d-none d-lg-table-cell justify-content-end px-1" |
class="justify-content-end px-1" |
||||
mat-header-cell |
mat-header-cell |
||||
mat-sort-header |
mat-sort-header="transactionCount" |
||||
> |
> |
||||
<ng-container i18n>Cash Balance</ng-container> |
<span class="d-block d-sm-none">#</span> |
||||
</th> |
<span class="d-none d-sm-block" i18n>Activities</span> |
||||
<td |
</th> |
||||
*matCellDef="let element" |
<td *matCellDef="let element" class="px-1 text-right" mat-cell> |
||||
class="d-none d-lg-table-cell px-1 text-right" |
{{ element.transactionCount }} |
||||
mat-cell |
</td> |
||||
> |
<td *matFooterCellDef class="px-1 text-right" mat-footer-cell> |
||||
<gf-value |
{{ transactionCount }} |
||||
class="d-inline-block justify-content-end" |
</td> |
||||
[isCurrency]="true" |
</ng-container> |
||||
[locale]="locale" |
|
||||
[value]="element.balance" |
|
||||
/> |
|
||||
</td> |
|
||||
<td |
|
||||
*matFooterCellDef |
|
||||
class="d-none d-lg-table-cell px-1 text-right" |
|
||||
mat-footer-cell |
|
||||
> |
|
||||
<gf-value |
|
||||
class="d-inline-block justify-content-end" |
|
||||
[isCurrency]="true" |
|
||||
[locale]="locale" |
|
||||
[value]="totalBalanceInBaseCurrency" |
|
||||
/> |
|
||||
</td> |
|
||||
</ng-container> |
|
||||
|
|
||||
<ng-container matColumnDef="value"> |
<ng-container matColumnDef="balance"> |
||||
<th |
<th |
||||
*matHeaderCellDef |
*matHeaderCellDef |
||||
class="d-none d-lg-table-cell justify-content-end px-1" |
class="d-none d-lg-table-cell justify-content-end px-1" |
||||
mat-header-cell |
mat-header-cell |
||||
mat-sort-header |
mat-sort-header |
||||
> |
> |
||||
<ng-container i18n>Value</ng-container> |
<ng-container i18n>Cash Balance</ng-container> |
||||
</th> |
</th> |
||||
<td |
<td |
||||
*matCellDef="let element" |
*matCellDef="let element" |
||||
class="d-none d-lg-table-cell px-1 text-right" |
class="d-none d-lg-table-cell px-1 text-right" |
||||
mat-cell |
mat-cell |
||||
> |
> |
||||
<gf-value |
<gf-value |
||||
class="d-inline-block justify-content-end" |
class="d-inline-block justify-content-end" |
||||
[isCurrency]="true" |
[isCurrency]="true" |
||||
[locale]="locale" |
[locale]="locale" |
||||
[value]="element.value" |
[value]="element.balance" |
||||
/> |
/> |
||||
</td> |
</td> |
||||
<td |
<td |
||||
*matFooterCellDef |
*matFooterCellDef |
||||
class="d-none d-lg-table-cell px-1 text-right" |
class="d-none d-lg-table-cell px-1 text-right" |
||||
mat-footer-cell |
mat-footer-cell |
||||
> |
> |
||||
<gf-value |
<gf-value |
||||
class="d-inline-block justify-content-end" |
class="d-inline-block justify-content-end" |
||||
[isCurrency]="true" |
[isCurrency]="true" |
||||
[locale]="locale" |
[locale]="locale" |
||||
[value]="totalValueInBaseCurrency" |
[value]="totalBalanceInBaseCurrency" |
||||
/> |
/> |
||||
</td> |
</td> |
||||
</ng-container> |
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="valueInBaseCurrency"> |
<ng-container matColumnDef="value"> |
||||
<th |
<th |
||||
*matHeaderCellDef |
*matHeaderCellDef |
||||
class="d-lg-none d-xl-none px-1 text-right" |
class="d-none d-lg-table-cell justify-content-end px-1" |
||||
mat-header-cell |
mat-header-cell |
||||
mat-sort-header |
mat-sort-header |
||||
> |
> |
||||
<ng-container i18n>Value</ng-container> |
<ng-container i18n>Value</ng-container> |
||||
</th> |
</th> |
||||
<td |
<td |
||||
*matCellDef="let element" |
*matCellDef="let element" |
||||
class="d-lg-none d-xl-none px-1 text-right" |
class="d-none d-lg-table-cell px-1 text-right" |
||||
mat-cell |
mat-cell |
||||
> |
> |
||||
<gf-value |
<gf-value |
||||
class="d-inline-block justify-content-end" |
class="d-inline-block justify-content-end" |
||||
[isCurrency]="true" |
[isCurrency]="true" |
||||
[locale]="locale" |
[locale]="locale" |
||||
[value]="element.valueInBaseCurrency" |
[value]="element.value" |
||||
/> |
/> |
||||
</td> |
</td> |
||||
<td |
<td |
||||
*matFooterCellDef |
*matFooterCellDef |
||||
class="d-lg-none d-xl-none px-1 text-right" |
class="d-none d-lg-table-cell px-1 text-right" |
||||
mat-footer-cell |
mat-footer-cell |
||||
> |
> |
||||
<gf-value |
<gf-value |
||||
class="d-inline-block justify-content-end" |
class="d-inline-block justify-content-end" |
||||
[isCurrency]="true" |
[isCurrency]="true" |
||||
[locale]="locale" |
[locale]="locale" |
||||
[value]="totalValueInBaseCurrency" |
[value]="totalValueInBaseCurrency" |
||||
/> |
/> |
||||
</td> |
</td> |
||||
</ng-container> |
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="comment"> |
<ng-container matColumnDef="valueInBaseCurrency"> |
||||
<th |
<th |
||||
*matHeaderCellDef |
*matHeaderCellDef |
||||
class="d-none d-lg-table-cell px-1" |
class="d-lg-none d-xl-none px-1 text-right" |
||||
mat-header-cell |
mat-header-cell |
||||
></th> |
mat-sort-header |
||||
<td *matCellDef="let element" class="d-none d-lg-table-cell px-1" mat-cell> |
> |
||||
<button |
<ng-container i18n>Value</ng-container> |
||||
*ngIf="element.comment" |
</th> |
||||
class="mx-1 no-min-width px-2" |
<td |
||||
mat-button |
*matCellDef="let element" |
||||
title="Note" |
class="d-lg-none d-xl-none px-1 text-right" |
||||
(click)="onOpenComment(element.comment); $event.stopPropagation()" |
mat-cell |
||||
> |
> |
||||
<ion-icon name="document-text-outline" /> |
<gf-value |
||||
</button> |
class="d-inline-block justify-content-end" |
||||
</td> |
[isCurrency]="true" |
||||
<td |
[locale]="locale" |
||||
*matFooterCellDef |
[value]="element.valueInBaseCurrency" |
||||
class="d-none d-lg-table-cell px-1" |
/> |
||||
mat-footer-cell |
</td> |
||||
></td> |
<td |
||||
</ng-container> |
*matFooterCellDef |
||||
|
class="d-lg-none d-xl-none px-1 text-right" |
||||
|
mat-footer-cell |
||||
|
> |
||||
|
<gf-value |
||||
|
class="d-inline-block justify-content-end" |
||||
|
[isCurrency]="true" |
||||
|
[locale]="locale" |
||||
|
[value]="totalValueInBaseCurrency" |
||||
|
/> |
||||
|
</td> |
||||
|
</ng-container> |
||||
|
|
||||
<ng-container matColumnDef="actions" stickyEnd> |
<ng-container matColumnDef="comment"> |
||||
<th *matHeaderCellDef class="px-1 text-center" i18n mat-header-cell></th> |
<th |
||||
<td *matCellDef="let element" class="px-1 text-center" mat-cell> |
*matHeaderCellDef |
||||
<button |
class="d-none d-lg-table-cell px-1" |
||||
class="mx-1 no-min-width px-2" |
mat-header-cell |
||||
mat-button |
></th> |
||||
[matMenuTriggerFor]="accountMenu" |
<td |
||||
(click)="$event.stopPropagation()" |
*matCellDef="let element" |
||||
|
class="d-none d-lg-table-cell px-1" |
||||
|
mat-cell |
||||
> |
> |
||||
<ion-icon name="ellipsis-horizontal" /> |
@if (element.comment) { |
||||
</button> |
<button |
||||
<mat-menu #accountMenu="matMenu" xPosition="before"> |
class="mx-1 no-min-width px-2" |
||||
<button mat-menu-item (click)="onUpdateAccount(element)"> |
mat-button |
||||
<span class="align-items-center d-flex"> |
title="Note" |
||||
<ion-icon class="mr-2" name="create-outline" /> |
(click)="onOpenComment(element.comment); $event.stopPropagation()" |
||||
<span i18n>Edit</span> |
> |
||||
</span> |
<ion-icon name="document-text-outline" /> |
||||
</button> |
</button> |
||||
|
} |
||||
|
</td> |
||||
|
<td |
||||
|
*matFooterCellDef |
||||
|
class="d-none d-lg-table-cell px-1" |
||||
|
mat-footer-cell |
||||
|
></td> |
||||
|
</ng-container> |
||||
|
|
||||
|
<ng-container matColumnDef="actions" stickyEnd> |
||||
|
<th *matHeaderCellDef class="px-1 text-center" i18n mat-header-cell></th> |
||||
|
<td *matCellDef="let element" class="px-1 text-center" mat-cell> |
||||
<button |
<button |
||||
mat-menu-item |
class="mx-1 no-min-width px-2" |
||||
[disabled]="element.transactionCount > 0" |
mat-button |
||||
(click)="onDeleteAccount(element.id)" |
[matMenuTriggerFor]="accountMenu" |
||||
|
(click)="$event.stopPropagation()" |
||||
> |
> |
||||
<span class="align-items-center d-flex"> |
<ion-icon name="ellipsis-horizontal" /> |
||||
<ion-icon class="mr-2" name="trash-outline" /> |
|
||||
<span i18n>Delete</span> |
|
||||
</span> |
|
||||
</button> |
</button> |
||||
</mat-menu> |
<mat-menu #accountMenu="matMenu" xPosition="before"> |
||||
</td> |
<button mat-menu-item (click)="onUpdateAccount(element)"> |
||||
<td *matFooterCellDef class="px-1" mat-footer-cell></td> |
<span class="align-items-center d-flex"> |
||||
</ng-container> |
<ion-icon class="mr-2" name="create-outline" /> |
||||
|
<span i18n>Edit</span> |
||||
|
</span> |
||||
|
</button> |
||||
|
<button |
||||
|
mat-menu-item |
||||
|
[disabled]="element.transactionCount > 0" |
||||
|
(click)="onDeleteAccount(element.id)" |
||||
|
> |
||||
|
<span class="align-items-center d-flex"> |
||||
|
<ion-icon class="mr-2" name="trash-outline" /> |
||||
|
<span i18n>Delete</span> |
||||
|
</span> |
||||
|
</button> |
||||
|
</mat-menu> |
||||
|
</td> |
||||
|
<td *matFooterCellDef class="px-1" mat-footer-cell></td> |
||||
|
</ng-container> |
||||
|
|
||||
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> |
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> |
||||
<tr |
<tr |
||||
*matRowDef="let row; columns: displayedColumns" |
*matRowDef="let row; columns: displayedColumns" |
||||
mat-row |
mat-row |
||||
[ngClass]="{ |
[ngClass]="{ |
||||
'cursor-pointer': hasPermissionToOpenDetails |
'cursor-pointer': hasPermissionToOpenDetails |
||||
}" |
}" |
||||
(click)="onOpenAccountDetailDialog(row.id)" |
(click)="onOpenAccountDetailDialog(row.id)" |
||||
></tr> |
></tr> |
||||
<tr |
<tr |
||||
*matFooterRowDef="displayedColumns" |
*matFooterRowDef="displayedColumns" |
||||
mat-footer-row |
mat-footer-row |
||||
[ngClass]="{ 'd-none': isLoading || !showFooter }" |
[ngClass]="{ 'd-none': isLoading || !showFooter }" |
||||
></tr> |
></tr> |
||||
</table> |
</table> |
||||
|
</div> |
||||
|
|
||||
<ngx-skeleton-loader |
@if (isLoading) { |
||||
*ngIf="isLoading" |
<ngx-skeleton-loader |
||||
animation="pulse" |
animation="pulse" |
||||
class="px-4 py-3" |
class="px-4 py-3" |
||||
[theme]="{ |
[theme]="{ |
||||
height: '1.5rem', |
height: '1.5rem', |
||||
width: '100%' |
width: '100%' |
||||
}" |
}" |
||||
/> |
/> |
||||
|
} |
||||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue