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

* Move tags from info to user service

* Update changelog
pull/3902/head
Matej Gerek 2 weeks ago committed by GitHub
parent fc5ed887ff
commit 98957d282e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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

@ -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
],

@ -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()
};

@ -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;

@ -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
}));
}
}

@ -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();
}
});

@ -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]);

@ -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[];
}

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

@ -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