Browse Source

Implemented platform creation

pull/1922/head
Fabio Azevedo (CTW) 2 years ago
parent
commit
4a382f8eb8
  1. 2
      apps/api/src/app/app.module.ts
  2. 40
      apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-account-platform.component.ts
  3. 29
      apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html
  4. 26
      apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-platform-dialog.module.ts
  5. 7
      apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-platform-dialog.scss
  6. 5
      apps/client/src/app/components/platform/create-or-update-platform-dialog/interfaces/interfaces.ts
  7. 18
      apps/client/src/app/components/platform/platform.component.html
  8. 10
      apps/client/src/app/components/platform/platform.component.scss
  9. 85
      apps/client/src/app/components/platform/platform.component.ts
  10. 4
      apps/client/src/app/components/platform/platform.module.ts
  11. 11
      apps/client/src/app/services/data.service.ts
  12. 16
      libs/common/src/lib/interfaces/admin-platforms.interface.ts

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

@ -34,6 +34,7 @@ import { RedisCacheModule } from './redis-cache/redis-cache.module';
import { SubscriptionModule } from './subscription/subscription.module';
import { SymbolModule } from './symbol/symbol.module';
import { UserModule } from './user/user.module';
import { PlatformModule } from './platform/platform.module';
@Module({
imports: [
@ -66,6 +67,7 @@ import { UserModule } from './user/user.module';
PortfolioModule,
PrismaModule,
RedisCacheModule,
PlatformModule,
ScheduleModule.forRoot(),
ServeStaticModule.forRoot({
serveStaticOptions: {

40
apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-account-platform.component.ts

@ -0,0 +1,40 @@
import {
ChangeDetectionStrategy,
Component,
Inject,
OnDestroy
} from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Subject } from 'rxjs';
import { CreateOrUpdatePlatformDialogParams } from './interfaces/interfaces';
@Component({
host: { class: 'h-100' },
selector: 'gf-create-or-update-platform-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./create-or-update-platform-dialog.scss'],
templateUrl: 'create-or-update-platform-dialog.html'
})
export class CreateOrUpdatePlatformDialog implements OnDestroy {
public currencies: string[] = [];
public platforms: { id: string; name: string }[];
private unsubscribeSubject = new Subject<void>();
public constructor(
public dialogRef: MatDialogRef<CreateOrUpdatePlatformDialog>,
@Inject(MAT_DIALOG_DATA) public data: CreateOrUpdatePlatformDialogParams
) {}
ngOnInit() {}
public onCancel() {
this.dialogRef.close();
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
}

29
apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html

@ -0,0 +1,29 @@
<form #addPlatformtForm="ngForm" class="d-flex flex-column h-100">
<h1 *ngIf="data.platform.id" i18n mat-dialog-title>Update platform</h1>
<h1 *ngIf="!data.platform.id" i18n mat-dialog-title>Add platform</h1>
<div class="flex-grow-1 py-3" mat-dialog-content>
<div>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Name</mat-label>
<input matInput name="name" required [(ngModel)]="data.platform.name" />
</mat-form-field>
</div>
<div>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Url</mat-label>
<input matInput name="name" required [(ngModel)]="data.platform.url" />
</mat-form-field>
</div>
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button (click)="onCancel()">Cancel</button>
<button
color="primary"
mat-flat-button
[disabled]="!addPlatformtForm.form.valid"
[mat-dialog-close]="data"
>
<ng-container i18n>Save</ng-container>
</button>
</div>
</form>

26
apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-platform-dialog.module.ts

@ -0,0 +1,26 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialogModule } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { CreateOrUpdatePlatformDialog } from './create-or-update-account-platform.component';
@NgModule({
declarations: [CreateOrUpdatePlatformDialog],
imports: [
CommonModule,
FormsModule,
MatButtonModule,
MatCheckboxModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
ReactiveFormsModule
]
})
export class GfCreateOrUpdatePlatformDialogModule {}

7
apps/client/src/app/components/platform/create-or-update-platform-dialog/create-or-update-platform-dialog.scss

@ -0,0 +1,7 @@
:host {
display: block;
.mat-mdc-dialog-content {
max-height: unset;
}
}

5
apps/client/src/app/components/platform/create-or-update-platform-dialog/interfaces/interfaces.ts

@ -0,0 +1,5 @@
import { Platform } from '@prisma/client';
export interface CreateOrUpdatePlatformDialogParams {
platform: Platform;
}

18
apps/client/src/app/components/platform/platform.component.html

@ -14,7 +14,11 @@
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Id</ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
<td
*matCellDef="let element"
class="d-none d-lg-table-cell px-1"
mat-cell
>
{{ element.id }}
</td>
</ng-container>
@ -23,7 +27,11 @@
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Name</ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
<td
*matCellDef="let element"
class="d-none d-lg-table-cell px-1"
mat-cell
>
{{ element.name }}
</td>
</ng-container>
@ -32,7 +40,11 @@
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Url</ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
<td
*matCellDef="let element"
class="d-none d-lg-table-cell px-1"
mat-cell
>
{{ element.url }}
</td>
</ng-container>

10
apps/client/src/app/components/platform/platform.component.scss

@ -11,4 +11,14 @@
bottom: 4rem;
z-index: 999;
}
.mat-mdc-table {
th {
::ng-deep {
.mat-sort-header-container {
justify-content: inherit;
}
}
}
}
}

85
apps/client/src/app/components/platform/platform.component.ts

@ -1,41 +1,55 @@
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import {
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { CreatePlatformDto } from '@ghostfolio/api/app/platform/create-platform.dto';
import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces';
import { AdminPlatformsItem } from '@ghostfolio/common/interfaces/admin-platforms.interface';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Platform as PlatformModel } from '@prisma/client';
import { Platform, Platform as PlatformModel } from '@prisma/client';
import { Subject, takeUntil } from 'rxjs';
import { CreateOrUpdatePlatformDialog } from './create-or-update-platform-dialog/create-or-update-account-platform.component';
import { MatDialog } from '@angular/material/dialog';
import { DeviceDetectorService } from 'ngx-device-detector';
import { DataService } from '@ghostfolio/client/services/data.service';
@Component({
selector: 'gf-platform-overview',
styleUrls: ['./platform.component.scss'],
templateUrl: './platform.component.html'
})
export class AdminPlatformComponent implements OnInit {
export class AdminPlatformComponent implements OnInit, OnDestroy {
@ViewChild(MatSort) sort: MatSort;
public displayedColumns = ['id', 'name', 'url'];
public platforms: PlatformModel[];
public deviceType: string;
public hasPermissionToCreatePlatform: boolean;
public hasPermissionToDeletePlatform: boolean;
public hasImpersonationId: boolean;
public user: User;
public dataSource: MatTableDataSource<AdminPlatformsItem> =
new MatTableDataSource();
public dataSource: MatTableDataSource<Platform> = new MatTableDataSource();
private unsubscribeSubject = new Subject<void>();
public constructor(
private dataService: DataService,
private changeDetectorRef: ChangeDetectorRef,
private userService: UserService,
private deviceService: DeviceDetectorService,
private impersonationStorageService: ImpersonationStorageService,
private dialog: MatDialog,
private route: ActivatedRoute,
private router: Router
) {
@ -48,7 +62,7 @@ export class AdminPlatformComponent implements OnInit {
params['createDialog'] &&
this.hasPermissionToCreatePlatform
) {
//this.openCreateAccountDialog();
this.openCreatePlatformDialog();
} else if (params['editDialog']) {
if (this.platforms) {
const platform = this.platforms.find(({ id }) => {
@ -64,6 +78,8 @@ export class AdminPlatformComponent implements OnInit {
}
public ngOnInit() {
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
this.impersonationStorageService
.onChangeHasImpersonation()
.pipe(takeUntil(this.unsubscribeSubject))
@ -93,5 +109,58 @@ export class AdminPlatformComponent implements OnInit {
this.fetchPlatforms();
}
private fetchPlatforms() {}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
private fetchPlatforms() {
this.dataService
.fetchPlatforms()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((platforms) => {
this.platforms = platforms;
this.dataSource = new MatTableDataSource(platforms);
this.changeDetectorRef.markForCheck();
});
}
private openCreatePlatformDialog() {
const dialogRef = this.dialog.open(CreateOrUpdatePlatformDialog, {
data: {
platform: {
name: null,
url: null
}
},
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh',
width: this.deviceType === 'mobile' ? '100vw' : '50rem'
});
dialogRef
.afterClosed()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((data) => {
const platform: CreatePlatformDto = data?.platform;
if (platform) {
this.dataService
.postPlatform(platform)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => {
this.userService
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe();
this.fetchPlatforms();
}
});
}
this.router.navigate(['.'], { relativeTo: this.route });
});
}
}

4
apps/client/src/app/components/platform/platform.module.ts

@ -5,6 +5,7 @@ import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { GfCreateOrUpdatePlatformDialogModule } from './create-or-update-platform-dialog/create-or-update-platform-dialog.module';
@NgModule({
declarations: [AdminPlatformComponent],
@ -13,7 +14,8 @@ import { MatTableModule } from '@angular/material/table';
RouterModule,
MatButtonModule,
MatSortModule,
MatTableModule
MatTableModule,
GfCreateOrUpdatePlatformDialogModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})

11
apps/client/src/app/services/data.service.ts

@ -6,6 +6,7 @@ import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { Activities } from '@ghostfolio/api/app/order/interfaces/activities.interface';
import { UpdateOrderDto } from '@ghostfolio/api/app/order/update-order.dto';
import { CreatePlatformDto } from '@ghostfolio/api/app/platform/create-platform.dto';
import { PortfolioPositionDetail } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-position-detail.interface';
import { PortfolioPositions } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-positions.interface';
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
@ -39,7 +40,7 @@ import {
import { filterGlobalPermissions } from '@ghostfolio/common/permissions';
import { AccountWithValue, DateRange, GroupBy } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { DataSource, Order as OrderModel } from '@prisma/client';
import { DataSource, Order as OrderModel, Platform } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { cloneDeep, groupBy, isNumber } from 'lodash';
import { Observable } from 'rxjs';
@ -72,6 +73,10 @@ export class DataService {
return this.http.get<Accounts>('/api/v1/account');
}
public fetchPlatforms() {
return this.http.get<Platform[]>('/api/v1/platform');
}
public fetchActivities({
filters
}: {
@ -405,6 +410,10 @@ export class DataService {
return this.http.post<OrderModel>(`/api/v1/account`, aAccount);
}
public postPlatform(aPlatform: CreatePlatformDto) {
return this.http.post<OrderModel>(`/api/v1/platform`, aPlatform);
}
public postOrder(aOrder: CreateOrderDto) {
return this.http.post<OrderModel>(`/api/v1/order`, aOrder);
}

16
libs/common/src/lib/interfaces/admin-platforms.interface.ts

@ -1,16 +0,0 @@
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
export interface AdminPlatforms {
platforms: AdminPlatformsItem[];
}
export interface AdminPlatformsItem {
assetClass?: AssetClass;
assetSubClass?: AssetSubClass;
countriesCount: number;
dataSource: DataSource;
date?: Date;
marketDataItemCount: number;
sectorsCount: number;
symbol: string;
}
Loading…
Cancel
Save