Browse Source

Feature/add asset profile count to data providers management of admin control (#4707)

* Extend admin settings columns

* assetProfileCount
* status

* Update changelog
pull/4724/head
Thomas Kaul 1 month ago
committed by GitHub
parent
commit
af79888cd6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 201
      apps/client/src/app/components/admin-platform/admin-platform.component.html
  3. 42
      apps/client/src/app/components/admin-settings/admin-settings.component.html
  4. 12
      apps/client/src/app/components/admin-settings/admin-settings.component.scss
  5. 2
      apps/client/src/app/components/admin-settings/admin-settings.component.ts
  6. 2
      apps/client/src/app/components/admin-settings/admin-settings.module.ts
  7. 187
      apps/client/src/app/components/admin-tag/admin-tag.component.html

1
CHANGELOG.md

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Harmonized the data providers management style of the admin control panel - Harmonized the data providers management style of the admin control panel
- Extended the data providers management of the admin control panel by the asset profile count
- Restricted the permissions of the demo user - Restricted the permissions of the demo user
- Renamed `Order` to `activities` in the `User` database schema - Renamed `Order` to `activities` in the `User` database schema
- Improved the language localization for Catalan (`ca`) - Improved the language localization for Catalan (`ca`)

201
apps/client/src/app/components/admin-platform/admin-platform.component.html

@ -1,115 +1,94 @@
<div class="container"> <div class="d-flex justify-content-end">
<div class="row"> <a
<div class="col"> color="primary"
<div class="d-flex justify-content-end"> i18n
<a mat-flat-button
color="primary" [queryParams]="{ createPlatformDialog: true }"
i18n [routerLink]="[]"
mat-flat-button >
[queryParams]="{ createPlatformDialog: true }" Add Platform
[routerLink]="[]" </a>
> </div>
Add Platform <table
</a> class="gf-table w-100"
</div> mat-table
<table matSort
class="gf-table w-100" matSortActive="name"
mat-table matSortDirection="asc"
matSort [dataSource]="dataSource"
matSortActive="name" >
matSortDirection="asc" <ng-container matColumnDef="name">
[dataSource]="dataSource" <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header="name">
> <ng-container i18n>Name</ng-container>
<ng-container matColumnDef="name"> </th>
<th <td *matCellDef="let element" class="px-1" mat-cell>
*matHeaderCellDef @if (element.url) {
class="px-1" <gf-asset-profile-icon
mat-header-cell class="d-inline mr-1"
mat-sort-header="name" [tooltip]="element.name"
> [url]="element.url"
<ng-container i18n>Name</ng-container> />
</th> }
<td *matCellDef="let element" class="px-1" mat-cell> <span>{{ element.name }}</span>
@if (element.url) { </td></ng-container
<gf-asset-profile-icon >
class="d-inline mr-1"
[tooltip]="element.name"
[url]="element.url"
/>
}
<span>{{ element.name }}</span>
</td></ng-container
>
<ng-container matColumnDef="url"> <ng-container matColumnDef="url">
<th <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header="url">
*matHeaderCellDef <ng-container i18n>Url</ng-container>
class="px-1" </th>
mat-header-cell <td *matCellDef="let element" class="px-1" mat-cell>
mat-sort-header="url" {{ element.url }}
> </td>
<ng-container i18n>Url</ng-container> </ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
{{ element.url }}
</td>
</ng-container>
<ng-container matColumnDef="accounts"> <ng-container matColumnDef="accounts">
<th <th
*matHeaderCellDef *matHeaderCellDef
class="px-1" class="px-1"
mat-header-cell mat-header-cell
mat-sort-header="accountCount" mat-sort-header="accountCount"
> >
<ng-container i18n>Accounts</ng-container> <ng-container i18n>Accounts</ng-container>
</th> </th>
<td *matCellDef="let element" class="px-1" mat-cell> <td *matCellDef="let element" class="px-1 text-right" mat-cell>
{{ element.accountCount }} {{ element.accountCount }}
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions" stickyEnd> <ng-container matColumnDef="actions" stickyEnd>
<th <th *matHeaderCellDef class="px-1 text-center" i18n mat-header-cell></th>
*matHeaderCellDef <td *matCellDef="let element" class="px-1 text-center" mat-cell>
class="px-1 text-center" <button
i18n class="mx-1 no-min-width px-2"
mat-header-cell mat-button
></th> [matMenuTriggerFor]="platformMenu"
<td *matCellDef="let element" class="px-1 text-center" mat-cell> (click)="$event.stopPropagation()"
<button >
class="mx-1 no-min-width px-2" <ion-icon name="ellipsis-horizontal" />
mat-button </button>
[matMenuTriggerFor]="platformMenu" <mat-menu #platformMenu="matMenu" xPosition="before">
(click)="$event.stopPropagation()" <button mat-menu-item (click)="onUpdatePlatform(element)">
> <span class="align-items-center d-flex">
<ion-icon name="ellipsis-horizontal" /> <ion-icon class="mr-2" name="create-outline" />
</button> <span i18n>Edit</span>
<mat-menu #platformMenu="matMenu" xPosition="before"> </span>
<button mat-menu-item (click)="onUpdatePlatform(element)"> </button>
<span class="align-items-center d-flex"> <hr class="m-0" />
<ion-icon class="mr-2" name="create-outline" /> <button
<span i18n>Edit</span> mat-menu-item
</span> [disabled]="element.accountCount > 0"
</button> (click)="onDeletePlatform(element.id)"
<hr class="m-0" /> >
<button <span class="align-items-center d-flex">
mat-menu-item <ion-icon class="mr-2" name="trash-outline" />
[disabled]="element.accountCount > 0" <span i18n>Delete</span>
(click)="onDeletePlatform(element.id)" </span>
> </button>
<span class="align-items-center d-flex"> </mat-menu>
<ion-icon class="mr-2" name="trash-outline" /> </td>
<span i18n>Delete</span> </ng-container>
</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
</table> </table>
</div>
</div>
</div>

42
apps/client/src/app/components/admin-settings/admin-settings.component.html

@ -38,14 +38,6 @@
}} }}
</small> </small>
</div> </div>
<div class="line-height-1 mt-1">
<small class="text-muted">
{{ ghostfolioApiStatus.dailyRequests }}
<ng-container i18n>of</ng-container>
{{ ghostfolioApiStatus.dailyRequestsMax }}
<ng-container i18n>daily requests</ng-container>
</small>
</div>
} }
} @else { } @else {
{{ element.name }} {{ element.name }}
@ -55,6 +47,40 @@
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="assetProfileCount">
<th *matHeaderCellDef class="px-1 py-2 text-right" mat-header-cell>
<ng-container i18n>Asset Profiles</ng-container>
</th>
<td *matCellDef="let element" class="px-1 py-2 text-right" mat-cell>
{{ element.assetProfileCount }}
</td>
</ng-container>
<ng-container matColumnDef="status">
<th *matHeaderCellDef class="px-1 py-2" mat-header-cell></th>
<td *matCellDef="let element" class="px-1 py-2" mat-cell>
@if (isGhostfolioDataProvider(element)) {
@if (isGhostfolioApiKeyValid === true) {
<mat-progress-bar
mode="determinate"
[value]="
100 -
(ghostfolioApiStatus.dailyRequests /
ghostfolioApiStatus.dailyRequestsMax) *
100
"
/>
<small class="text-muted">
{{ ghostfolioApiStatus.dailyRequests }}
<ng-container i18n>of</ng-container>
{{ ghostfolioApiStatus.dailyRequestsMax }}
<ng-container i18n>daily requests</ng-container>
</small>
}
}
</td>
</ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th *matHeaderCellDef class="px-1 py-2" mat-header-cell></th> <th *matHeaderCellDef class="px-1 py-2" mat-header-cell></th>

12
apps/client/src/app/components/admin-settings/admin-settings.component.scss

@ -1,3 +1,15 @@
:host { :host {
display: block; display: block;
.mat-mdc-progress-bar {
--mdc-linear-progress-active-indicator-height: 0.5rem;
--mdc-linear-progress-track-height: 0.5rem;
border-radius: 0.25rem;
::ng-deep {
.mdc-linear-progress__buffer-bar {
background-color: rgb(var(--palette-background-unselected-chip));
}
}
}
} }

2
apps/client/src/app/components/admin-settings/admin-settings.component.ts

@ -39,7 +39,7 @@ import { GhostfolioPremiumApiDialogParams } from './ghostfolio-premium-api-dialo
export class AdminSettingsComponent implements OnDestroy, OnInit { export class AdminSettingsComponent implements OnDestroy, OnInit {
public dataSource = new MatTableDataSource<DataProviderInfo>(); public dataSource = new MatTableDataSource<DataProviderInfo>();
public defaultDateFormat: string; public defaultDateFormat: string;
public displayedColumns = ['name', 'actions']; public displayedColumns = ['name', 'assetProfileCount', 'status', 'actions'];
public ghostfolioApiStatus: DataProviderGhostfolioStatusResponse; public ghostfolioApiStatus: DataProviderGhostfolioStatusResponse;
public isGhostfolioApiKeyValid: boolean; public isGhostfolioApiKeyValid: boolean;
public isLoading = false; public isLoading = false;

2
apps/client/src/app/components/admin-settings/admin-settings.module.ts

@ -7,6 +7,7 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@ -23,6 +24,7 @@ import { AdminSettingsComponent } from './admin-settings.component';
GfPremiumIndicatorComponent, GfPremiumIndicatorComponent,
MatButtonModule, MatButtonModule,
MatMenuModule, MatMenuModule,
MatProgressBarModule,
MatTableModule, MatTableModule,
NgxSkeletonLoaderModule, NgxSkeletonLoaderModule,
RouterModule RouterModule

187
apps/client/src/app/components/admin-tag/admin-tag.component.html

@ -1,108 +1,87 @@
<div class="container"> <div class="d-flex justify-content-end">
<div class="row"> <a
<div class="col"> color="primary"
<div class="d-flex justify-content-end"> i18n
<a mat-flat-button
color="primary" [queryParams]="{ createTagDialog: true }"
i18n [routerLink]="[]"
mat-flat-button >
[queryParams]="{ createTagDialog: true }" Add Tag
[routerLink]="[]" </a>
> </div>
Add Tag <table
</a> class="gf-table w-100"
</div> mat-table
<table matSort
class="gf-table w-100" matSortActive="name"
mat-table matSortDirection="asc"
matSort [dataSource]="dataSource"
matSortActive="name" >
matSortDirection="asc" <ng-container matColumnDef="name">
[dataSource]="dataSource" <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header="name">
> <ng-container i18n>Name</ng-container>
<ng-container matColumnDef="name"> </th>
<th <td *matCellDef="let element" class="px-1" mat-cell>
*matHeaderCellDef {{ element.name }}
class="px-1" </td>
mat-header-cell </ng-container>
mat-sort-header="name"
>
<ng-container i18n>Name</ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
{{ element.name }}
</td>
</ng-container>
<ng-container matColumnDef="userId"> <ng-container matColumnDef="userId">
<th <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header="userId">
*matHeaderCellDef <ng-container i18n>User</ng-container>
class="px-1" </th>
mat-header-cell <td *matCellDef="let element" class="px-1" mat-cell>
mat-sort-header="userId" <span class="text-monospace">{{ element.userId }}</span>
> </td>
<ng-container i18n>User</ng-container> </ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
<span class="text-monospace">{{ element.userId }}</span>
</td>
</ng-container>
<ng-container matColumnDef="activities"> <ng-container matColumnDef="activities">
<th <th
*matHeaderCellDef *matHeaderCellDef
class="px-1" class="px-1"
mat-header-cell mat-header-cell
mat-sort-header="activityCount" mat-sort-header="activityCount"
> >
<ng-container i18n>Activities</ng-container> <ng-container i18n>Activities</ng-container>
</th> </th>
<td *matCellDef="let element" class="px-1" mat-cell> <td *matCellDef="let element" class="px-1 text-right" mat-cell>
{{ element.activityCount }} {{ element.activityCount }}
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions" stickyEnd> <ng-container matColumnDef="actions" stickyEnd>
<th <th *matHeaderCellDef class="px-1 text-center" i18n mat-header-cell></th>
*matHeaderCellDef <td *matCellDef="let element" class="px-1 text-center" mat-cell>
class="px-1 text-center" <button
i18n class="mx-1 no-min-width px-2"
mat-header-cell mat-button
></th> [matMenuTriggerFor]="tagMenu"
<td *matCellDef="let element" class="px-1 text-center" mat-cell> (click)="$event.stopPropagation()"
<button >
class="mx-1 no-min-width px-2" <ion-icon name="ellipsis-horizontal" />
mat-button </button>
[matMenuTriggerFor]="tagMenu" <mat-menu #tagMenu="matMenu" xPosition="before">
(click)="$event.stopPropagation()" <button mat-menu-item (click)="onUpdateTag(element)">
> <span class="align-items-center d-flex">
<ion-icon name="ellipsis-horizontal" /> <ion-icon class="mr-2" name="create-outline" />
</button> <span i18n>Edit</span>
<mat-menu #tagMenu="matMenu" xPosition="before"> </span>
<button mat-menu-item (click)="onUpdateTag(element)"> </button>
<span class="align-items-center d-flex"> <hr class="m-0" />
<ion-icon class="mr-2" name="create-outline" /> <button
<span i18n>Edit</span> mat-menu-item
</span> [disabled]="element.activityCount > 0"
</button> (click)="onDeleteTag(element.id)"
<hr class="m-0" /> >
<button <span class="align-items-center d-flex">
mat-menu-item <ion-icon class="mr-2" name="trash-outline" />
[disabled]="element.activityCount > 0" <span i18n>Delete</span>
(click)="onDeleteTag(element.id)" </span>
> </button>
<span class="align-items-center d-flex"> </mat-menu>
<ion-icon class="mr-2" name="trash-outline" /> </td>
<span i18n>Delete</span> </ng-container>
</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
</table> </table>
</div>
</div>
</div>

Loading…
Cancel
Save