From 3bc2e0812572c8d7c02c00f43ee0f3d4cd2191e0 Mon Sep 17 00:00:00 2001 From: AyushMishraa Date: Mon, 1 Jun 2026 09:37:39 +0530 Subject: [PATCH] Feature/support migrating an existing asset profile to manual data source --- apps/api/src/app/admin/admin.service.ts | 50 +++++++++++++++++- .../asset-profile-dialog.component.scss | 4 ++ .../asset-profile-dialog.component.ts | 51 +++++++++++++++++++ .../asset-profile-dialog.html | 10 ++++ 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 0bf5c3925..9458361b7 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -599,10 +599,58 @@ export class AdminService { ) ]); + // Apply field updates after renaming + const finalDataSource = DataSource[newDataSource.toString()]; + const symbolProfileOverrides = { + assetClass: assetClass as AssetClass, + assetSubClass: assetSubClass as AssetSubClass, + countries: countries as Prisma.JsonArray, + name: name as string, + sectors: sectors as Prisma.JsonArray, + url: url as string + }; + + const updatedSymbolProfile: Prisma.SymbolProfileUpdateInput = { + comment, + currency, + holdings, + isActive, + scraperConfiguration, + symbolMapping, + ...(finalDataSource === 'MANUAL' + ? { + assetClass, + assetSubClass, + countries, + name, + sectors, + url, + SymbolProfileOverrides: { + delete: true + } + } + : { + SymbolProfileOverrides: { + upsert: { + create: symbolProfileOverrides, + update: symbolProfileOverrides + } + } + }) + }; + + await this.symbolProfileService.updateSymbolProfile( + { + dataSource: finalDataSource, + symbol: newSymbol as string + }, + updatedSymbolProfile + ); + const [updatedAssetProfile] = await this.symbolProfileService.getSymbolProfiles([ { - dataSource: DataSource[newDataSource.toString()], + dataSource: finalDataSource, symbol: newSymbol as string } ]); diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss index 73c0c0d74..d03c8c885 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss @@ -13,5 +13,9 @@ right: 1rem; top: 0; } + + .text-muted { + margin: 1rem 0; + } } } diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index 560a00164..299087d25 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -73,6 +73,7 @@ import { IonIcon } from '@ionic/angular/standalone'; import { AssetClass, AssetSubClass, + DataSource, MarketData, Prisma, SymbolProfile @@ -704,6 +705,56 @@ export class GfAssetProfileDialogComponent implements OnInit { }); } + protected onConvertToManual() { + const uuid = crypto.randomUUID(); + + this.adminService + .patchAssetProfile( + { + dataSource: this.data.dataSource, + symbol: this.data.symbol + }, + { + assetClass: + this.assetProfileForm.controls.assetClass.value ?? undefined, + assetSubClass: + this.assetProfileForm.controls.assetSubClass.value ?? undefined, + countries: JSON.parse( + this.assetProfileForm.controls.countries.value ?? '[]' + ) as Prisma.InputJsonArray, + dataSource: 'MANUAL' as DataSource, + name: this.assetProfileForm.controls.name.value || undefined, + sectors: JSON.parse( + this.assetProfileForm.controls.sectors.value ?? '[]' + ) as Prisma.InputJsonArray, + symbol: uuid, + url: this.assetProfileForm.controls.url.value || undefined + } + ) + .pipe( + catchError(() => { + this.snackBar.open( + $localize`An error occurred while converting to MANUAL.`, + undefined, + { + duration: ms('3 seconds') + } + ); + + return EMPTY; + }), + takeUntilDestroyed(this.destroyRef) + ) + .subscribe(() => { + const newAssetProfileIdentifier = { + dataSource: 'MANUAL', + symbol: uuid + }; + + this.dialogRef.close(newAssetProfileIdentifier); + }); + } + protected onTestMarketData() { this.adminService .testMarketData({ diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index b2a7e0a05..451344909 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -162,6 +162,16 @@ Cancel +

or

+ } @else {