|
|
@ -1,10 +1,6 @@ |
|
|
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|
|
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|
|
import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos'; |
|
|
import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos'; |
|
|
import { |
|
|
import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces'; |
|
|
AssetProfileIdentifier, |
|
|
|
|
|
Filter, |
|
|
|
|
|
PortfolioPosition |
|
|
|
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
|
|
|
import { AccountWithPlatform } from '@ghostfolio/common/types'; |
|
|
import { AccountWithPlatform } from '@ghostfolio/common/types'; |
|
|
import { validateObjectForForm } from '@ghostfolio/common/utils'; |
|
|
import { validateObjectForForm } from '@ghostfolio/common/utils'; |
|
|
import { NotificationService } from '@ghostfolio/ui/notifications'; |
|
|
import { NotificationService } from '@ghostfolio/ui/notifications'; |
|
|
@ -65,7 +61,7 @@ import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; |
|
|
templateUrl: 'create-or-update-access-dialog.html' |
|
|
templateUrl: 'create-or-update-access-dialog.html' |
|
|
}) |
|
|
}) |
|
|
export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
public showFilterPanel = false; |
|
|
public hasExperimentalFeatures = false; |
|
|
|
|
|
|
|
|
public accounts: AccountWithPlatform[] = []; |
|
|
public accounts: AccountWithPlatform[] = []; |
|
|
public assetClasses: Filter[] = []; |
|
|
public assetClasses: Filter[] = []; |
|
|
@ -111,6 +107,26 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
] |
|
|
] |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
this.userService |
|
|
|
|
|
.get() |
|
|
|
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
|
|
|
.subscribe(({ accounts, settings, tags }) => { |
|
|
|
|
|
this.accounts = accounts; |
|
|
|
|
|
this.hasExperimentalFeatures = settings.isExperimentalFeatures ?? false; |
|
|
|
|
|
|
|
|
|
|
|
this.tags = tags |
|
|
|
|
|
.filter(({ isUsed }) => isUsed) |
|
|
|
|
|
.map(({ id, name }) => ({ |
|
|
|
|
|
id, |
|
|
|
|
|
label: name, |
|
|
|
|
|
type: 'TAG' as const |
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
this.updateFiltersFormControl(this.data.access?.settings?.filters); |
|
|
|
|
|
|
|
|
|
|
|
this.changeDetectorRef.markForCheck(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
this.accessForm |
|
|
this.accessForm |
|
|
.get('type') |
|
|
.get('type') |
|
|
?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
@ -122,7 +138,6 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
granteeUserIdControl?.setValidators([ |
|
|
granteeUserIdControl?.setValidators([ |
|
|
(control: AbstractControl) => Validators.required(control) |
|
|
(control: AbstractControl) => Validators.required(control) |
|
|
]); |
|
|
]); |
|
|
this.showFilterPanel = false; |
|
|
|
|
|
this.accessForm.get('filters')?.setValue(null); |
|
|
this.accessForm.get('filters')?.setValue(null); |
|
|
} else { |
|
|
} else { |
|
|
granteeUserIdControl?.clearValidators(); |
|
|
granteeUserIdControl?.clearValidators(); |
|
|
@ -130,8 +145,10 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
permissionsControl?.setValue( |
|
|
permissionsControl?.setValue( |
|
|
access?.permissions[0] ?? AccessPermission.READ_RESTRICTED |
|
|
access?.permissions[0] ?? AccessPermission.READ_RESTRICTED |
|
|
); |
|
|
); |
|
|
this.showFilterPanel = true; |
|
|
|
|
|
this.loadFilterData(); |
|
|
if (this.hasExperimentalFeatures) { |
|
|
|
|
|
this.loadHoldings(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
granteeUserIdControl?.updateValueAndValidity(); |
|
|
granteeUserIdControl?.updateValueAndValidity(); |
|
|
@ -139,9 +156,8 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
this.changeDetectorRef.markForCheck(); |
|
|
this.changeDetectorRef.markForCheck(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if (isPublic) { |
|
|
if (isPublic && this.hasExperimentalFeatures) { |
|
|
this.showFilterPanel = true; |
|
|
this.loadHoldings(); |
|
|
this.loadFilterData(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -157,76 +173,45 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private buildFilterObject(): |
|
|
private buildFilters(): Filter[] { |
|
|
| { |
|
|
|
|
|
accountIds?: string[]; |
|
|
|
|
|
assetClasses?: string[]; |
|
|
|
|
|
holdings?: AssetProfileIdentifier[]; |
|
|
|
|
|
tagIds?: string[]; |
|
|
|
|
|
} |
|
|
|
|
|
| undefined { |
|
|
|
|
|
const filterValue = this.accessForm.get('filters') |
|
|
const filterValue = this.accessForm.get('filters') |
|
|
?.value as PortfolioFilterFormValue | null; |
|
|
?.value as PortfolioFilterFormValue | null; |
|
|
|
|
|
|
|
|
if ( |
|
|
if (!filterValue) { |
|
|
!filterValue || |
|
|
return []; |
|
|
(!filterValue.account && |
|
|
|
|
|
!filterValue.assetClass && |
|
|
|
|
|
!filterValue.holding && |
|
|
|
|
|
!filterValue.tag) |
|
|
|
|
|
) { |
|
|
|
|
|
return undefined; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const filter: { |
|
|
const filters: Filter[] = []; |
|
|
accountIds?: string[]; |
|
|
|
|
|
assetClasses?: string[]; |
|
|
|
|
|
holdings?: AssetProfileIdentifier[]; |
|
|
|
|
|
tagIds?: string[]; |
|
|
|
|
|
} = {}; |
|
|
|
|
|
|
|
|
|
|
|
if (filterValue.account) { |
|
|
if (filterValue.account) { |
|
|
filter.accountIds = [filterValue.account]; |
|
|
filters.push({ id: filterValue.account, type: 'ACCOUNT' }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (filterValue.assetClass) { |
|
|
if (filterValue.assetClass) { |
|
|
filter.assetClasses = [filterValue.assetClass]; |
|
|
filters.push({ id: filterValue.assetClass, type: 'ASSET_CLASS' }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (filterValue.holding) { |
|
|
if (filterValue.holding) { |
|
|
filter.holdings = [ |
|
|
filters.push( |
|
|
{ |
|
|
{ |
|
|
dataSource: filterValue.holding.assetProfile.dataSource, |
|
|
id: filterValue.holding.assetProfile.dataSource, |
|
|
symbol: filterValue.holding.assetProfile.symbol |
|
|
type: 'DATA_SOURCE' |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
id: filterValue.holding.assetProfile.symbol, |
|
|
|
|
|
type: 'SYMBOL' |
|
|
} |
|
|
} |
|
|
]; |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (filterValue.tag) { |
|
|
if (filterValue.tag) { |
|
|
filter.tagIds = [filterValue.tag]; |
|
|
filters.push({ id: filterValue.tag, type: 'TAG' }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return filter; |
|
|
return filters; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private loadFilterData() { |
|
|
private loadHoldings() { |
|
|
const existingFilter = this.data.access?.settings?.filter; |
|
|
|
|
|
|
|
|
|
|
|
this.userService |
|
|
|
|
|
.get() |
|
|
|
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
|
|
|
.subscribe((user) => { |
|
|
|
|
|
this.accounts = user.accounts; |
|
|
|
|
|
this.tags = user.tags |
|
|
|
|
|
.filter(({ isUsed }) => isUsed) |
|
|
|
|
|
.map(({ id, name }) => ({ |
|
|
|
|
|
id, |
|
|
|
|
|
label: name, |
|
|
|
|
|
type: 'TAG' as const |
|
|
|
|
|
})); |
|
|
|
|
|
this.updateFiltersFormControl(existingFilter); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
this.dataService |
|
|
this.dataService |
|
|
.fetchPortfolioDetails({}) |
|
|
.fetchPortfolioDetails({}) |
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
@ -246,50 +231,56 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
type: 'ASSET_CLASS' as const |
|
|
type: 'ASSET_CLASS' as const |
|
|
})); |
|
|
})); |
|
|
|
|
|
|
|
|
this.updateFiltersFormControl(existingFilter); |
|
|
this.updateFiltersFormControl(this.data.access?.settings?.filters); |
|
|
} |
|
|
} |
|
|
this.changeDetectorRef.markForCheck(); |
|
|
this.changeDetectorRef.markForCheck(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private updateFiltersFormControl( |
|
|
private updateFiltersFormControl(existingFilters: Filter[] | undefined) { |
|
|
existingFilter: |
|
|
if (!existingFilters?.length) { |
|
|
| { |
|
|
|
|
|
accountIds?: string[]; |
|
|
|
|
|
assetClasses?: string[]; |
|
|
|
|
|
holdings?: AssetProfileIdentifier[]; |
|
|
|
|
|
tagIds?: string[]; |
|
|
|
|
|
} |
|
|
|
|
|
| undefined |
|
|
|
|
|
) { |
|
|
|
|
|
if (!existingFilter) { |
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const filterValue: Partial<PortfolioFilterFormValue> = {}; |
|
|
const filterValue: Partial<PortfolioFilterFormValue> = {}; |
|
|
|
|
|
|
|
|
if (existingFilter.accountIds?.[0] && this.accounts.length > 0) { |
|
|
const accountFilter = existingFilters.find(({ type }) => { |
|
|
filterValue.account = existingFilter.accountIds[0]; |
|
|
return type === 'ACCOUNT'; |
|
|
|
|
|
}); |
|
|
|
|
|
if (accountFilter && this.accounts.length > 0) { |
|
|
|
|
|
filterValue.account = accountFilter.id; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (existingFilter.assetClasses?.[0] && this.assetClasses.length > 0) { |
|
|
const assetClassFilter = existingFilters.find(({ type }) => { |
|
|
filterValue.assetClass = existingFilter.assetClasses[0]; |
|
|
return type === 'ASSET_CLASS'; |
|
|
|
|
|
}); |
|
|
|
|
|
if (assetClassFilter && this.assetClasses.length > 0) { |
|
|
|
|
|
filterValue.assetClass = assetClassFilter.id; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (existingFilter.holdings?.[0] && this.holdings.length > 0) { |
|
|
const dataSourceFilter = existingFilters.find(({ type }) => { |
|
|
const holdingData = existingFilter.holdings[0]; |
|
|
return type === 'DATA_SOURCE'; |
|
|
const holding = this.holdings.find( |
|
|
}); |
|
|
(h) => |
|
|
const symbolFilter = existingFilters.find(({ type }) => { |
|
|
h.assetProfile.dataSource === holdingData.dataSource && |
|
|
return type === 'SYMBOL'; |
|
|
h.assetProfile.symbol === holdingData.symbol |
|
|
}); |
|
|
); |
|
|
if (dataSourceFilter && symbolFilter && this.holdings.length > 0) { |
|
|
|
|
|
const holding = this.holdings.find(({ assetProfile }) => { |
|
|
|
|
|
return ( |
|
|
|
|
|
assetProfile.dataSource === dataSourceFilter.id && |
|
|
|
|
|
assetProfile.symbol === symbolFilter.id |
|
|
|
|
|
); |
|
|
|
|
|
}); |
|
|
if (holding) { |
|
|
if (holding) { |
|
|
filterValue.holding = holding; |
|
|
filterValue.holding = holding; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (existingFilter.tagIds?.[0] && this.tags.length > 0) { |
|
|
const tagFilter = existingFilters.find(({ type }) => { |
|
|
filterValue.tag = existingFilter.tagIds[0]; |
|
|
return type === 'TAG'; |
|
|
|
|
|
}); |
|
|
|
|
|
if (tagFilter && this.tags.length > 0) { |
|
|
|
|
|
filterValue.tag = tagFilter.id; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (Object.keys(filterValue).length > 0) { |
|
|
if (Object.keys(filterValue).length > 0) { |
|
|
@ -299,11 +290,11 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private async createAccess() { |
|
|
private async createAccess() { |
|
|
const filter = this.showFilterPanel ? this.buildFilterObject() : undefined; |
|
|
const filters = this.buildFilters(); |
|
|
|
|
|
|
|
|
const access: CreateAccessDto = { |
|
|
const access: CreateAccessDto = { |
|
|
alias: this.accessForm.get('alias')?.value, |
|
|
alias: this.accessForm.get('alias')?.value, |
|
|
filter, |
|
|
filters: filters.length > 0 ? filters : undefined, |
|
|
granteeUserId: this.accessForm.get('granteeUserId')?.value, |
|
|
granteeUserId: this.accessForm.get('granteeUserId')?.value, |
|
|
permissions: [this.accessForm.get('permissions')?.value] |
|
|
permissions: [this.accessForm.get('permissions')?.value] |
|
|
}; |
|
|
}; |
|
|
@ -344,11 +335,11 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const filter = this.showFilterPanel ? this.buildFilterObject() : undefined; |
|
|
const filters = this.buildFilters(); |
|
|
|
|
|
|
|
|
const access: UpdateAccessDto = { |
|
|
const access: UpdateAccessDto = { |
|
|
alias: this.accessForm.get('alias')?.value, |
|
|
alias: this.accessForm.get('alias')?.value, |
|
|
filter, |
|
|
filters: filters.length > 0 ? filters : undefined, |
|
|
granteeUserId: this.accessForm.get('granteeUserId')?.value, |
|
|
granteeUserId: this.accessForm.get('granteeUserId')?.value, |
|
|
id: accessId, |
|
|
id: accessId, |
|
|
permissions: [this.accessForm.get('permissions')?.value] |
|
|
permissions: [this.accessForm.get('permissions')?.value] |
|
|
|