|
|
@ -3,11 +3,15 @@ import { UpdateAccessDto } from '@ghostfolio/api/app/access/update-access.dto'; |
|
|
import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; |
|
|
import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; |
|
|
import { DataService } from '@ghostfolio/client/services/data.service'; |
|
|
import { DataService } from '@ghostfolio/client/services/data.service'; |
|
|
import { validateObjectForForm } from '@ghostfolio/client/util/form.util'; |
|
|
import { validateObjectForForm } from '@ghostfolio/client/util/form.util'; |
|
|
|
|
|
import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces'; |
|
|
|
|
|
import { AccountWithPlatform } from '@ghostfolio/common/types'; |
|
|
|
|
|
import { GfPortfolioFilterFormComponent } from '@ghostfolio/ui/portfolio-filter-form'; |
|
|
|
|
|
|
|
|
import { |
|
|
import { |
|
|
ChangeDetectionStrategy, |
|
|
ChangeDetectionStrategy, |
|
|
ChangeDetectorRef, |
|
|
ChangeDetectorRef, |
|
|
Component, |
|
|
Component, |
|
|
|
|
|
CUSTOM_ELEMENTS_SCHEMA, |
|
|
Inject, |
|
|
Inject, |
|
|
OnDestroy, |
|
|
OnDestroy, |
|
|
OnInit |
|
|
OnInit |
|
|
@ -28,7 +32,10 @@ import { |
|
|
import { MatFormFieldModule } from '@angular/material/form-field'; |
|
|
import { MatFormFieldModule } from '@angular/material/form-field'; |
|
|
import { MatInputModule } from '@angular/material/input'; |
|
|
import { MatInputModule } from '@angular/material/input'; |
|
|
import { MatSelectModule } from '@angular/material/select'; |
|
|
import { MatSelectModule } from '@angular/material/select'; |
|
|
|
|
|
import { IonIcon } from '@ionic/angular/standalone'; |
|
|
import { StatusCodes } from 'http-status-codes'; |
|
|
import { StatusCodes } from 'http-status-codes'; |
|
|
|
|
|
import { addIcons } from 'ionicons'; |
|
|
|
|
|
import { chevronUpOutline, optionsOutline } from 'ionicons/icons'; |
|
|
import { EMPTY, Subject, catchError, takeUntil } from 'rxjs'; |
|
|
import { EMPTY, Subject, catchError, takeUntil } from 'rxjs'; |
|
|
|
|
|
|
|
|
import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; |
|
|
import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; |
|
|
@ -38,6 +45,8 @@ import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; |
|
|
host: { class: 'h-100' }, |
|
|
host: { class: 'h-100' }, |
|
|
imports: [ |
|
|
imports: [ |
|
|
FormsModule, |
|
|
FormsModule, |
|
|
|
|
|
GfPortfolioFilterFormComponent, |
|
|
|
|
|
IonIcon, |
|
|
MatButtonModule, |
|
|
MatButtonModule, |
|
|
MatDialogModule, |
|
|
MatDialogModule, |
|
|
MatFormFieldModule, |
|
|
MatFormFieldModule, |
|
|
@ -45,6 +54,7 @@ import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; |
|
|
MatSelectModule, |
|
|
MatSelectModule, |
|
|
ReactiveFormsModule |
|
|
ReactiveFormsModule |
|
|
], |
|
|
], |
|
|
|
|
|
schemas: [CUSTOM_ELEMENTS_SCHEMA], |
|
|
selector: 'gf-create-or-update-access-dialog', |
|
|
selector: 'gf-create-or-update-access-dialog', |
|
|
styleUrls: ['./create-or-update-access-dialog.scss'], |
|
|
styleUrls: ['./create-or-update-access-dialog.scss'], |
|
|
templateUrl: 'create-or-update-access-dialog.html' |
|
|
templateUrl: 'create-or-update-access-dialog.html' |
|
|
@ -54,6 +64,14 @@ export class GfCreateOrUpdateAccessDialogComponent |
|
|
{ |
|
|
{ |
|
|
public accessForm: FormGroup; |
|
|
public accessForm: FormGroup; |
|
|
public mode: 'create' | 'update'; |
|
|
public mode: 'create' | 'update'; |
|
|
|
|
|
public showFilterPanel = false; |
|
|
|
|
|
public filterPanelExpanded = false; |
|
|
|
|
|
|
|
|
|
|
|
// Datos para el filtro
|
|
|
|
|
|
public accounts: AccountWithPlatform[] = []; |
|
|
|
|
|
public assetClasses: Filter[] = []; |
|
|
|
|
|
public holdings: PortfolioPosition[] = []; |
|
|
|
|
|
public tags: Filter[] = []; |
|
|
|
|
|
|
|
|
private unsubscribeSubject = new Subject<void>(); |
|
|
private unsubscribeSubject = new Subject<void>(); |
|
|
|
|
|
|
|
|
@ -66,6 +84,8 @@ export class GfCreateOrUpdateAccessDialogComponent |
|
|
private notificationService: NotificationService |
|
|
private notificationService: NotificationService |
|
|
) { |
|
|
) { |
|
|
this.mode = this.data.access?.id ? 'update' : 'create'; |
|
|
this.mode = this.data.access?.id ? 'update' : 'create'; |
|
|
|
|
|
|
|
|
|
|
|
addIcons({ chevronUpOutline, optionsOutline }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public ngOnInit() { |
|
|
public ngOnInit() { |
|
|
@ -73,6 +93,7 @@ export class GfCreateOrUpdateAccessDialogComponent |
|
|
|
|
|
|
|
|
this.accessForm = this.formBuilder.group({ |
|
|
this.accessForm = this.formBuilder.group({ |
|
|
alias: [this.data.access.alias], |
|
|
alias: [this.data.access.alias], |
|
|
|
|
|
filter: [null], |
|
|
granteeUserId: [ |
|
|
granteeUserId: [ |
|
|
this.data.access.grantee, |
|
|
this.data.access.grantee, |
|
|
isPublic ? null : Validators.required |
|
|
isPublic ? null : Validators.required |
|
|
@ -87,19 +108,30 @@ export class GfCreateOrUpdateAccessDialogComponent |
|
|
this.accessForm.get('type').valueChanges.subscribe((accessType) => { |
|
|
this.accessForm.get('type').valueChanges.subscribe((accessType) => { |
|
|
const granteeUserIdControl = this.accessForm.get('granteeUserId'); |
|
|
const granteeUserIdControl = this.accessForm.get('granteeUserId'); |
|
|
const permissionsControl = this.accessForm.get('permissions'); |
|
|
const permissionsControl = this.accessForm.get('permissions'); |
|
|
|
|
|
const filterControl = this.accessForm.get('filter'); |
|
|
|
|
|
|
|
|
if (accessType === 'PRIVATE') { |
|
|
if (accessType === 'PRIVATE') { |
|
|
granteeUserIdControl.setValidators(Validators.required); |
|
|
granteeUserIdControl.setValidators(Validators.required); |
|
|
|
|
|
this.showFilterPanel = false; |
|
|
|
|
|
filterControl.setValue(null); |
|
|
} else { |
|
|
} else { |
|
|
granteeUserIdControl.clearValidators(); |
|
|
granteeUserIdControl.clearValidators(); |
|
|
granteeUserIdControl.setValue(null); |
|
|
granteeUserIdControl.setValue(null); |
|
|
permissionsControl.setValue(this.data.access.permissions[0]); |
|
|
permissionsControl.setValue(this.data.access.permissions[0]); |
|
|
|
|
|
this.showFilterPanel = true; |
|
|
|
|
|
this.loadFilterData(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
granteeUserIdControl.updateValueAndValidity(); |
|
|
granteeUserIdControl.updateValueAndValidity(); |
|
|
|
|
|
|
|
|
this.changeDetectorRef.markForCheck(); |
|
|
this.changeDetectorRef.markForCheck(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Si ya es público al iniciar, mostrar el panel y cargar datos
|
|
|
|
|
|
if (isPublic) { |
|
|
|
|
|
this.showFilterPanel = true; |
|
|
|
|
|
this.loadFilterData(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public onCancel() { |
|
|
public onCancel() { |
|
|
@ -119,6 +151,54 @@ export class GfCreateOrUpdateAccessDialogComponent |
|
|
this.unsubscribeSubject.complete(); |
|
|
this.unsubscribeSubject.complete(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private loadFilterData() { |
|
|
|
|
|
// Cargar cuentas
|
|
|
|
|
|
this.dataService |
|
|
|
|
|
.fetchAccounts() |
|
|
|
|
|
.pipe(takeUntil(this.unsubscribeSubject)) |
|
|
|
|
|
.subscribe((response) => { |
|
|
|
|
|
this.accounts = response.accounts; |
|
|
|
|
|
this.changeDetectorRef.markForCheck(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Cargar holdings y asset classes
|
|
|
|
|
|
this.dataService |
|
|
|
|
|
.fetchPortfolioDetails({}) |
|
|
|
|
|
.pipe(takeUntil(this.unsubscribeSubject)) |
|
|
|
|
|
.subscribe((response) => { |
|
|
|
|
|
if (response.holdings) { |
|
|
|
|
|
this.holdings = Object.values(response.holdings); |
|
|
|
|
|
|
|
|
|
|
|
// Extraer asset classes únicas
|
|
|
|
|
|
const assetClassesSet = new Set<string>(); |
|
|
|
|
|
Object.values(response.holdings).forEach((holding) => { |
|
|
|
|
|
if (holding.assetClass) { |
|
|
|
|
|
assetClassesSet.add(holding.assetClass); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
this.assetClasses = Array.from(assetClassesSet).map((ac) => ({ |
|
|
|
|
|
id: ac, |
|
|
|
|
|
label: ac, |
|
|
|
|
|
type: 'ASSET_CLASS' as const |
|
|
|
|
|
})); |
|
|
|
|
|
} |
|
|
|
|
|
this.changeDetectorRef.markForCheck(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Cargar tags
|
|
|
|
|
|
this.dataService |
|
|
|
|
|
.fetchTags() |
|
|
|
|
|
.pipe(takeUntil(this.unsubscribeSubject)) |
|
|
|
|
|
.subscribe((response) => { |
|
|
|
|
|
this.tags = response.map((tag) => ({ |
|
|
|
|
|
id: tag.id, |
|
|
|
|
|
label: tag.name, |
|
|
|
|
|
type: 'TAG' as const |
|
|
|
|
|
})); |
|
|
|
|
|
this.changeDetectorRef.markForCheck(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private async createAccess() { |
|
|
private async createAccess() { |
|
|
const access: CreateAccessDto = { |
|
|
const access: CreateAccessDto = { |
|
|
alias: this.accessForm.get('alias').value, |
|
|
alias: this.accessForm.get('alias').value, |
|
|
|