Browse Source

feat #1970: introduced stepper to import activities

pull/1990/head
visrut 2 years ago
parent
commit
551a79815c
  1. 7
      apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts
  2. 216
      apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html
  3. 2
      apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.module.ts
  4. 12
      apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.scss

7
apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts

@ -19,6 +19,11 @@ import { Subject, takeUntil } from 'rxjs';
import { ImportActivitiesDialogParams } from './interfaces/interfaces'; import { ImportActivitiesDialogParams } from './interfaces/interfaces';
enum FileStatus {
SELECT = 0,
UPLOADED
}
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-import-activities-dialog', selector: 'gf-import-activities-dialog',
@ -36,6 +41,7 @@ export class ImportActivitiesDialog implements OnDestroy {
public mode: 'DIVIDEND'; public mode: 'DIVIDEND';
public selectedActivities: Activity[] = []; public selectedActivities: Activity[] = [];
public uniqueAssetForm: FormGroup; public uniqueAssetForm: FormGroup;
public fileStatus: FileStatus = FileStatus.SELECT;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -228,6 +234,7 @@ export class ImportActivitiesDialog implements OnDestroy {
this.isFileSelected = true; this.isFileSelected = true;
this.snackBar.dismiss(); this.snackBar.dismiss();
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
this.fileStatus = FileStatus.UPLOADED;
} }
}; };
}; };

216
apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html

@ -4,112 +4,122 @@
[title]="errorMessages.length === 0 ? 'Import Activities' : 'Import Activities Error'" [title]="errorMessages.length === 0 ? 'Import Activities' : 'Import Activities Error'"
(closeButtonClicked)="onCancel()" (closeButtonClicked)="onCancel()"
></gf-dialog-header> ></gf-dialog-header>
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
<div class="flex-grow-1 py-3" mat-dialog-content> <div class="flex-grow-1 py-3" mat-dialog-content>
<ng-container *ngIf="!isFileSelected"> <mat-stepper #stepper [linear]="true" [selectedIndex]="fileStatus">
<ng-container *ngIf="mode === 'DIVIDEND'; else selectFile"> <mat-step editable="false" label="Select File">
<form [formGroup]="uniqueAssetForm" (ngSubmit)="onLoadDividends()"> <ng-container *ngIf="!isFileSelected">
<mat-form-field appearance="outline" class="w-100"> <ng-container *ngIf="mode === 'DIVIDEND'; else selectFile">
<mat-label i18n>Holding</mat-label> <form [formGroup]="uniqueAssetForm" (ngSubmit)="onLoadDividends()">
<mat-select formControlName="uniqueAsset"> <mat-form-field appearance="outline" class="w-100">
<mat-option <mat-label i18n>Holding</mat-label>
*ngFor="let holding of holdings" <mat-select formControlName="uniqueAsset">
[value]="{dataSource: holding.dataSource, symbol: holding.symbol}" <mat-option
>{{ holding.name }}</mat-option *ngFor="let holding of holdings"
[value]="{dataSource: holding.dataSource, symbol: holding.symbol}"
>{{ holding.name }}</mat-option
>
</mat-select>
</mat-form-field>
<div class="d-flex justify-content-center flex-column">
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!uniqueAssetForm.valid"
>
<span i18n>Load Dividends</span>
</button>
</div>
</form>
</ng-container>
<ng-template #selectFile>
<div class="d-flex justify-content-center flex-column">
<button
class="py-4"
color="primary"
mat-stroked-button
(click)="onSelectFile()"
> >
</mat-select> <ion-icon class="mr-2" name="cloud-upload-outline"></ion-icon>
</mat-form-field> <span i18n>Choose File</span>
<div class="d-flex justify-content-center flex-column"> </button>
<button <p class="mb-0 mt-4 text-center">
color="primary" <span class="mr-1" i18n
mat-flat-button >The following file formats are supported:</span
type="submit" >
[disabled]="!uniqueAssetForm.valid" <a
> href="https://github.com/ghostfolio/ghostfolio/blob/main/test/import/ok.csv"
<span i18n>Load Dividends</span> target="_blank"
</button> >CSV</a
</div> >
</form> <span class="mx-1" i18n>or</span>
</ng-container> <a
<ng-template #selectFile> href="https://github.com/ghostfolio/ghostfolio/blob/main/test/import/ok.json"
<div class="d-flex justify-content-center flex-column"> target="_blank"
<button >JSON</a
class="py-4" >
color="primary" </p>
mat-stroked-button </div>
(click)="onSelectFile()" </ng-template>
> </ng-container>
<ion-icon class="mr-2" name="cloud-upload-outline"></ion-icon> </mat-step>
<span i18n>Choose File</span> <mat-step editable="false" label="Select Activities">
</button> <ng-container *ngIf="isFileSelected">
<p class="mb-0 mt-4 text-center"> <ng-container *ngIf="errorMessages.length === 0; else errorMessage">
<span class="mr-1" i18n <gf-activities-table
>The following file formats are supported:</span [activities]="activities"
> [baseCurrency]="data?.user?.settings?.baseCurrency"
<a [deviceType]="data?.deviceType"
href="https://github.com/ghostfolio/ghostfolio/blob/main/test/import/ok.csv" [hasPermissionToCreateActivity]="false"
target="_blank" [hasPermissionToExportActivities]="false"
>CSV</a [hasPermissionToFilter]="false"
> [hasPermissionToOpenDetails]="false"
<span class="mx-1" i18n>or</span> [locale]="data?.user?.settings?.locale"
<a [pageSize]="maxSafeInteger"
href="https://github.com/ghostfolio/ghostfolio/blob/main/test/import/ok.json" [showActions]="false"
target="_blank" [showCheckbox]="true"
>JSON</a [showFooter]="false"
> [showSymbolColumn]="false"
</p> (selectedActivities)="updateSelection($event)"
</div> ></gf-activities-table>
</ng-template> </ng-container>
</ng-container> <ng-template #errorMessage>
<ng-container *ngIf="isFileSelected"> <mat-accordion displayMode="flat">
<ng-container *ngIf="errorMessages.length === 0; else errorMessage"> <mat-expansion-panel
<gf-activities-table *ngFor="let message of errorMessages; let i = index"
[activities]="activities" [disabled]="!details[i]"
[baseCurrency]="data?.user?.settings?.baseCurrency" >
[deviceType]="data?.deviceType" <mat-expansion-panel-header class="pl-1">
[hasPermissionToCreateActivity]="false" <mat-panel-title>
[hasPermissionToExportActivities]="false" <div class="d-flex">
[hasPermissionToFilter]="false" <div class="align-items-center d-flex mr-2">
[hasPermissionToOpenDetails]="false" <ion-icon name="warning-outline"></ion-icon>
[locale]="data?.user?.settings?.locale" </div>
[pageSize]="maxSafeInteger" <div>{{ message }}</div>
[showActions]="false" </div>
[showCheckbox]="true" </mat-panel-title>
[showFooter]="false" </mat-expansion-panel-header>
[showSymbolColumn]="false" <pre
(selectedActivities)="updateSelection($event)" *ngIf="details[i]"
></gf-activities-table> class="m-0"
</ng-container> ><code>{{ details[i] | json }}</code></pre>
<ng-template #errorMessage> </mat-expansion-panel>
<mat-accordion displayMode="flat"> </mat-accordion>
<mat-expansion-panel <div class="mt-2">
*ngFor="let message of errorMessages; let i = index" <button mat-button (click)="onReset()">
[disabled]="!details[i]" <ion-icon class="mr-2" name="arrow-back-outline"></ion-icon>
> <span i18n>Back</span>
<mat-expansion-panel-header class="pl-1"> </button>
<mat-panel-title> </div>
<div class="d-flex"> </ng-template>
<div class="align-items-center d-flex mr-2"> </ng-container>
<ion-icon name="warning-outline"></ion-icon> </mat-step>
</div> </mat-stepper>
<div>{{ message }}</div>
</div>
</mat-panel-title>
</mat-expansion-panel-header>
<pre
*ngIf="details[i]"
class="m-0"
><code>{{ details[i] | json }}</code></pre>
</mat-expansion-panel>
</mat-accordion>
<div class="mt-2">
<button mat-button (click)="onReset()">
<ion-icon class="mr-2" name="arrow-back-outline"></ion-icon>
<span i18n>Back</span>
</button>
</div>
</ng-template>
</ng-container>
</div> </div>
<div *ngIf="isFileSelected" class="justify-content-end" mat-dialog-actions> <div *ngIf="isFileSelected" class="justify-content-end" mat-dialog-actions>

2
apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.module.ts

@ -9,6 +9,7 @@ import { MatSelectModule } from '@angular/material/select';
import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module'; import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module';
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module'; import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module'; import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
import { MatStepperModule } from '@angular/material/stepper';
import { ImportActivitiesDialog } from './import-activities-dialog.component'; import { ImportActivitiesDialog } from './import-activities-dialog.component';
@ -25,6 +26,7 @@ import { ImportActivitiesDialog } from './import-activities-dialog.component';
MatExpansionModule, MatExpansionModule,
MatFormFieldModule, MatFormFieldModule,
MatSelectModule, MatSelectModule,
MatStepperModule,
ReactiveFormsModule ReactiveFormsModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]

12
apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.scss

@ -17,4 +17,16 @@
} }
} }
} }
.mat-stepper-horizontal {
margin-top: 8px;
}
.mat-mdc-form-field {
margin-top: 16px;
}
::ng-deep .mat-horizontal-stepper-header {
pointer-events: none !important;
}
} }

Loading…
Cancel
Save