Browse Source

Feature/move tags from info to user service (#3859)

* Move tags from info to user service

* Update changelog
pull/3902/head
Matej Gerek 3 months ago
committed by GitHub
parent
commit
98957d282e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 2
      apps/api/src/app/info/info.module.ts
  3. 9
      apps/api/src/app/info/info.service.ts
  4. 10
      apps/api/src/app/user/user.service.ts
  5. 40
      apps/api/src/services/tag/tag.service.ts
  6. 17
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  7. 16
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  8. 3
      libs/common/src/lib/interfaces/info-item.interface.ts
  9. 2
      libs/common/src/lib/interfaces/user.interface.ts
  10. 27
      libs/ui/src/lib/assistant/assistant.component.ts

1
CHANGELOG.md

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Moved the tags from the info to the user service
- Switched the `prefer-const` rule from `warn` to `error` in the `eslint` configuration
## 2.113.0 - 2024-10-06

2
apps/api/src/app/info/info.module.ts

@ -9,7 +9,6 @@ import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-d
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { TagModule } from '@ghostfolio/api/services/tag/tag.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
@ -33,7 +32,6 @@ import { InfoService } from './info.service';
PropertyModule,
RedisCacheModule,
SymbolProfileModule,
TagModule,
TransformDataSourceInResponseModule,
UserModule
],

9
apps/api/src/app/info/info.service.ts

@ -5,7 +5,6 @@ import { UserService } from '@ghostfolio/api/app/user/user.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { TagService } from '@ghostfolio/api/services/tag/tag.service';
import {
DEFAULT_CURRENCY,
PROPERTY_BETTER_UPTIME_MONITOR_ID,
@ -47,7 +46,6 @@ export class InfoService {
private readonly platformService: PlatformService,
private readonly propertyService: PropertyService,
private readonly redisCacheService: RedisCacheService,
private readonly tagService: TagService,
private readonly userService: UserService
) {}
@ -103,8 +101,7 @@ export class InfoService {
isUserSignupEnabled,
platforms,
statistics,
subscriptions,
tags
subscriptions
] = await Promise.all([
this.benchmarkService.getBenchmarkAssetProfiles(),
this.getDemoAuthToken(),
@ -113,8 +110,7 @@ export class InfoService {
orderBy: { name: 'asc' }
}),
this.getStatistics(),
this.getSubscriptions(),
this.tagService.getPublic()
this.getSubscriptions()
]);
if (isUserSignupEnabled) {
@ -130,7 +126,6 @@ export class InfoService {
platforms,
statistics,
subscriptions,
tags,
baseCurrency: DEFAULT_CURRENCY,
currencies: this.exchangeRateDataService.getCurrencies()
};

10
apps/api/src/app/user/user.service.ts

@ -56,7 +56,7 @@ export class UserService {
{ Account, id, permissions, Settings, subscription }: UserWithSettings,
aLocale = locale
): Promise<IUser> {
const accessesResult = await Promise.all([
const userData = await Promise.all([
this.prismaService.access.findMany({
include: {
User: true
@ -70,11 +70,11 @@ export class UserService {
},
where: { userId: id }
}),
this.tagService.getInUseByUser(id)
this.tagService.getTagsForUser(id)
]);
const access = accessesResult[0];
const firstActivity = accessesResult[1];
let tags = accessesResult[2];
const access = userData[0];
const firstActivity = userData[1];
let tags = userData[2];
let systemMessage: SystemMessage;

40
apps/api/src/services/tag/tag.service.ts

@ -6,29 +6,39 @@ import { Injectable } from '@nestjs/common';
export class TagService {
public constructor(private readonly prismaService: PrismaService) {}
public async getPublic() {
return this.prismaService.tag.findMany({
orderBy: {
name: 'asc'
public async getTagsForUser(userId: string) {
const tags = await this.prismaService.tag.findMany({
include: {
_count: {
select: {
orders: {
where: {
userId
}
}
}
}
},
where: {
userId: null
}
});
}
public async getInUseByUser(userId: string) {
return this.prismaService.tag.findMany({
orderBy: {
name: 'asc'
},
where: {
orders: {
some: {
OR: [
{
userId
},
{
userId: null
}
}
]
}
});
return tags.map(({ _count, id, name, userId }) => ({
id,
name,
userId,
isUsed: _count.orders > 0
}));
}
}

17
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -147,8 +147,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
) {}
public ngOnInit() {
const { tags } = this.dataService.fetchInfo();
this.activityForm = this.formBuilder.group({
tags: <string[]>[]
});
@ -158,13 +156,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
{ id: this.data.symbol, type: 'SYMBOL' }
];
this.tagsAvailable = tags.map((tag) => {
return {
...tag,
name: translate(tag.name)
};
});
this.activityForm
.get('tags')
.valueChanges.pipe(takeUntil(this.unsubscribeSubject))
@ -434,6 +425,14 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
if (state?.user) {
this.user = state.user;
this.tagsAvailable =
this.user?.tags?.map((tag) => {
return {
...tag,
name: translate(tag.name)
};
}) ?? [];
this.changeDetectorRef.markForCheck();
}
});

16
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts

@ -76,17 +76,19 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.locale = this.data.user?.settings?.locale;
this.dateAdapter.setLocale(this.locale);
const { currencies, platforms, tags } = this.dataService.fetchInfo();
const { currencies, platforms } = this.dataService.fetchInfo();
this.currencies = currencies;
this.defaultDateFormat = getDateFormatString(this.locale);
this.platforms = platforms;
this.tagsAvailable = tags.map((tag) => {
return {
...tag,
name: translate(tag.name)
};
});
this.tagsAvailable =
this.data.user?.tags?.map((tag) => {
return {
...tag,
name: translate(tag.name)
};
}) ?? [];
Object.keys(Type).forEach((type) => {
this.typesTranslationMap[Type[type]] = translate(Type[type]);

3
libs/common/src/lib/interfaces/info-item.interface.ts

@ -1,6 +1,6 @@
import { SubscriptionOffer } from '@ghostfolio/common/types';
import { Platform, SymbolProfile, Tag } from '@prisma/client';
import { Platform, SymbolProfile } from '@prisma/client';
import { Statistics } from './statistics.interface';
import { Subscription } from './subscription.interface';
@ -19,5 +19,4 @@ export interface InfoItem {
statistics: Statistics;
stripePublicKey?: string;
subscriptions: { [offer in SubscriptionOffer]: Subscription };
tags: Tag[];
}

2
libs/common/src/lib/interfaces/user.interface.ts

@ -23,5 +23,5 @@ export interface User {
offer: SubscriptionOffer;
type: SubscriptionType;
};
tags: Tag[];
tags: (Tag & { isUsed: boolean })[];
}

27
libs/ui/src/lib/assistant/assistant.component.ts

@ -156,7 +156,6 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
) {}
public ngOnInit() {
this.accounts = this.user?.accounts;
this.assetClasses = Object.keys(AssetClass).map((assetClass) => {
return {
id: assetClass,
@ -164,13 +163,6 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
type: 'ASSET_CLASS'
};
});
this.tags = this.user?.tags.map(({ id, name }) => {
return {
id,
label: translate(name),
type: 'TAG'
};
});
this.searchFormControl.valueChanges
.pipe(
@ -212,6 +204,8 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
}
public ngOnChanges() {
this.accounts = this.user?.accounts ?? [];
this.dateRangeOptions = [
{ label: $localize`Today`, value: '1d' },
{
@ -279,6 +273,23 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
emitEvent: false
}
);
this.tags =
this.user?.tags
?.filter(({ isUsed }) => {
return isUsed;
})
.map(({ id, name }) => {
return {
id,
label: translate(name),
type: 'TAG'
};
}) ?? [];
if (this.tags.length === 0) {
this.filterForm.get('tag').disable({ emitEvent: false });
}
}
public hasFilter(aFormValue: { [key: string]: string }) {

Loading…
Cancel
Save