Browse Source

Merge branch 'main' into feature/upgrade-bootstrap-to-version-5

pull/8131/head
Thomas Kaul 2 days ago
committed by GitHub
parent
commit
50847aff2b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      CHANGELOG.md
  2. 61
      apps/api/src/app/activities/activities.service.spec.ts
  3. 7
      apps/api/src/app/activities/activities.service.ts
  4. 4
      apps/api/src/app/import/import.service.ts
  5. 1
      apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html
  6. 11
      apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.scss
  7. 340
      apps/client/src/locales/messages.ca.xlf
  8. 340
      apps/client/src/locales/messages.de.xlf
  9. 340
      apps/client/src/locales/messages.es.xlf
  10. 340
      apps/client/src/locales/messages.fr.xlf
  11. 340
      apps/client/src/locales/messages.it.xlf
  12. 340
      apps/client/src/locales/messages.ja.xlf
  13. 340
      apps/client/src/locales/messages.ko.xlf
  14. 340
      apps/client/src/locales/messages.nl.xlf
  15. 340
      apps/client/src/locales/messages.pl.xlf
  16. 340
      apps/client/src/locales/messages.pt.xlf
  17. 340
      apps/client/src/locales/messages.tr.xlf
  18. 340
      apps/client/src/locales/messages.uk.xlf
  19. 335
      apps/client/src/locales/messages.xlf
  20. 340
      apps/client/src/locales/messages.zh.xlf
  21. 4
      package-lock.json
  22. 2
      package.json

10
CHANGELOG.md

@ -7,18 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Changed
- Upgraded `bootstrap` from version `4.6.2` to `5.3.8`
## 3.86.0 - 2026-10-13
### Added ### Added
- Added support to paste a file in the import activities dialog - Added support to paste a file in the import activities dialog
### Changed ### Changed
- Improved the style of the stepper in the user account registration dialog
- Improved the labels of the client of the last request in the users section of the admin control panel - Improved the labels of the client of the last request in the users section of the admin control panel
- Upgraded `bootstrap` from version `4.6.2` to `5.3.8` - Improved the language localization for German (`de`)
### Fixed ### Fixed
- Fixed the missing platform icon in the preview step of the activities import - Fixed the missing platform icon in the preview step of the activities import
- Fixed the start date of the date range filter on the activities page and in the dividend timeline chart on the analysis page
- Fixed the link of the _Manage Asset Profile_ button in the holding detail dialog before the holding has loaded - Fixed the link of the _Manage Asset Profile_ button in the holding detail dialog before the holding has loaded
## 3.85.0 - 2026-10-12 ## 3.85.0 - 2026-10-12

61
apps/api/src/app/activities/activities.service.spec.ts

@ -9,12 +9,14 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service';
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { import {
INVESTMENT_ACTIVITY_TYPES, INVESTMENT_ACTIVITY_TYPES,
NON_INVESTMENT_ACTIVITY_TYPES NON_INVESTMENT_ACTIVITY_TYPES
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { parseDate } from '@ghostfolio/common/helper'; import { parseDate } from '@ghostfolio/common/helper';
import { Activity, Filter } from '@ghostfolio/common/interfaces'; import { Activity, Filter } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { import {
@ -27,6 +29,7 @@ import {
} from '@prisma/client'; } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { isUUID } from 'class-validator'; import { isUUID } from 'class-validator';
import { endOfDay } from 'date-fns';
import { ActivitiesService } from './activities.service'; import { ActivitiesService } from './activities.service';
@ -148,6 +151,10 @@ describe('ActivitiesService', () => {
}); });
describe('getActivities', () => { describe('getActivities', () => {
afterEach(() => {
jest.useRealTimers();
});
it('returns the activities with the asset profile but without the relation to the symbol profile', async () => { it('returns the activities with the asset profile but without the relation to the symbol profile', async () => {
const assetProfile = { const assetProfile = {
...assetProfileDummyData, ...assetProfileDummyData,
@ -224,6 +231,60 @@ describe('ActivitiesService', () => {
expect(activities[0]).not.toHaveProperty('SymbolProfile'); expect(activities[0]).not.toHaveProperty('SymbolProfile');
expect(activities[0].assetProfile).toBe(assetProfile); expect(activities[0].assetProfile).toBe(assetProfile);
}); });
it('excludes the activities of the start date of a date range', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2024-06-15').getTime());
expect(await getDateConditions('ytd')).toEqual(
expect.arrayContaining([
{ date: { gt: endOfDay(parseDate('2023-12-31')) } },
{ date: { lte: endOfDay(parseDate('2024-06-15')) } }
])
);
});
it('keeps the start date of the date range max', async () => {
expect(await getDateConditions('max')).toEqual(
expect.arrayContaining([{ date: { gt: new Date(0) } }])
);
});
async function getDateConditions(dateRange: DateRange) {
const findMany = jest.fn().mockResolvedValue([]);
const service = new ActivitiesService(
null,
null,
null,
null,
null,
null,
null,
null,
null,
{
order: {
findMany,
count: jest.fn().mockResolvedValue(0)
}
} as unknown as PrismaService,
{
getSymbolProfiles: jest.fn().mockResolvedValue([])
} as unknown as SymbolProfileService,
null
);
const { endDate, startDate } = getIntervalFromDateRange({ dateRange });
await service.getActivities({
endDate,
startDate,
userCurrency: 'USD',
userId: 'user-id'
});
return findMany.mock.calls[0][0].where.AND;
}
}); });
describe('getActivitiesForPortfolioCalculator', () => { describe('getActivitiesForPortfolioCalculator', () => {

7
apps/api/src/app/activities/activities.service.ts

@ -61,6 +61,7 @@ import {
Type as ActivityType Type as ActivityType
} from '@prisma/client'; } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { endOfDay, isAfter } from 'date-fns';
import { groupBy, omit, uniqBy } from 'lodash-es'; import { groupBy, omit, uniqBy } from 'lodash-es';
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
@ -1042,7 +1043,11 @@ export class ActivitiesService {
} }
if (startDate) { if (startDate) {
andConditions.push({ date: { gt: startDate } }); andConditions.push({
date: {
gt: isAfter(startDate, new Date(0)) ? endOfDay(startDate) : startDate
}
});
} }
const { const {

4
apps/api/src/app/import/import.service.ts

@ -48,7 +48,7 @@ import { Injectable } from '@nestjs/common';
import { Account, DataSource, Prisma } from '@prisma/client'; import { Account, DataSource, Prisma } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { isISIN } from 'class-validator'; import { isISIN } from 'class-validator';
import { isSameSecond, parseISO } from 'date-fns'; import { isSameSecond, parseISO, subDays } from 'date-fns';
import { omit, uniqBy } from 'lodash-es'; import { omit, uniqBy } from 'lodash-es';
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
@ -112,7 +112,7 @@ export class ImportService {
userCurrency, userCurrency,
userId, userId,
includeDrafts: true, includeDrafts: true,
startDate: parseDate(dateOfFirstActivity), startDate: subDays(parseDate(dateOfFirstActivity), 1),
withExcludedAccountsAndActivities: true withExcludedAccountsAndActivities: true
}), }),
this.symbolProfileService.getSymbolProfiles([ this.symbolProfileService.getSymbolProfiles([

1
apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html

@ -8,6 +8,7 @@
<mat-stepper <mat-stepper
#stepper #stepper
animationDuration="0ms" animationDuration="0ms"
[disableRipple]="true"
[linear]="true" [linear]="true"
[orientation]="data.deviceType === 'mobile' ? 'vertical' : 'horizontal'" [orientation]="data.deviceType === 'mobile' ? 'vertical' : 'horizontal'"
> >

11
apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.scss

@ -1,3 +1,5 @@
@use '@angular/material' as mat;
:host { :host {
--mat-dialog-with-actions-content-padding: 0; --mat-dialog-with-actions-content-padding: 0;
@ -10,6 +12,15 @@
} }
} }
mat-stepper {
@include mat.stepper-overrides(
(
header-focus-state-layer-color: transparent,
header-hover-state-layer-color: transparent
)
);
}
.mat-mdc-dialog-actions { .mat-mdc-dialog-actions {
padding: 0 !important; padding: 0 !important;
} }

340
apps/client/src/locales/messages.ca.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.de.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.es.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.fr.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.it.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.ja.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.ko.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.nl.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.pl.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.pt.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.tr.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.uk.xlf

File diff suppressed because it is too large

335
apps/client/src/locales/messages.xlf

File diff suppressed because it is too large

340
apps/client/src/locales/messages.zh.xlf

File diff suppressed because it is too large

4
package-lock.json

@ -1,12 +1,12 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "3.85.0", "version": "3.86.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ghostfolio", "name": "ghostfolio",
"version": "3.85.0", "version": "3.86.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "3.85.0", "version": "3.86.0",
"homepage": "https://ghostfol.io", "homepage": "https://ghostfol.io",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio", "repository": "https://github.com/ghostfolio/ghostfolio",

Loading…
Cancel
Save