RED-3800: some fixes

This commit is contained in:
Dan Percic 2023-03-02 12:22:20 +02:00
parent 697acb44db
commit d1ad17bc5d
7 changed files with 52 additions and 78 deletions

View File

@ -1,39 +1,31 @@
# Redaction
## To Create a new Stack in rancher
### To Create a new Stack in rancher check [this Wiki page](https://wiki.iqser.com/pages/viewpage.action?spaceKey=RED&title=Work+with+kubectl)
Goto rancher.iqser.com: Select Cluster `Development`, go to apps, click launch and select `Redaction` from the `dev`
section. Add a new name and a new namespace. Select `answers-development.yaml` and add it to answers `Edit as yaml`.
## Code style
For HTTPS / Cloudflare domain go to `workloads` -> `Loadbalancing` -> `select your stack`
Add cloudflare certificate and specify a hostname to use `timo-redaction-dev.iqser.cloud`
* Always use `trackBy` in `*ngFor` loops (see shorthand below)
```typescript
readonly trackBy = trackByFactory();
```
* Don't use `setInterval` without calling `clearInterval` in `ngOnDestroy`
## Keycloak Staging Config
- keycloak:
- authServerUrl: 'https://redkc-staging.iqser.cloud/auth'
- client:
- secret: 'a4e8aa56-03b0-4e6b-b822-8ac1f41280c4'
- keycloak:
- authServerUrl: 'https://redkc-staging.iqser.cloud/auth'
- client:
- secret: 'a4e8aa56-03b0-4e6b-b822-8ac1f41280c4'
## Default Testing URL
## Default Testing URLs
`https://dev-04.iqser.cloud/`
## Known errors
- In case of CORS or redirect_uri errors follow these steps:
- Go to `<HOST>.iqser.cloud/auth/admin/master/console`
- Login with `admin` and `admin1234`
- In the left menu go to `Clients`
- In the table click `redaction`
- Find `Valid Redirect URIs` input
- Under `/ui/*` add new value `http://localhost:4200/*`
- **Save**
* `https://dev-04.iqser.cloud/`
* `https://dev-08.iqser.cloud/`
## Test Users
| username | role | comment |
| ------------ | ------------------------------ | -------------------------- |
|--------------|--------------------------------|----------------------------|
| guest | | cannot use the application |
| user | RED_USER | |
| red_manager | RED_MANAGER | |
@ -44,12 +36,11 @@ Password for all users is `OsloImWinter!23`
### Running the app locally
Requirements:
Requirements:
* node 16 or newer installed ( https://nodejs.org/en/download/ )
* yarn ( execute `npm install -g yarn` in any terminal after installing node )
In the root folder simply execute `yarn install` followed by `yarn start`.
The file `apps/red-ui/src/assets/config.config.json` contains the configuration for local development. All properties defined here are later available via env variables.
The file `apps/red-ui/src/assets/config.config.json` contains the configuration for local development. All properties
defined here are later available via env variables.

View File

@ -198,8 +198,7 @@ export const appModuleFactory = (config: AppConfig) => {
},
{
provide: MAX_RETRIES_ON_SERVER_ERROR,
useFactory: (configService: ConfigService) => configService.values.MAX_RETRIES_ON_SERVER_ERROR,
deps: [ConfigService],
useFactory: () => config.MAX_RETRIES_ON_SERVER_ERROR,
},
{
provide: SERVER_ERROR_SKIP_PATHS,

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, OnDestroy } from '@angular/core';
import { FileDownloadService } from '@upload-download/services/file-download.service';
import { DownloadStatus } from '@red/domain';
import { CircleButtonTypes, ListingComponent, listingProvidersFactory, LoadingService, TableColumnConfig } from '@iqser/common-ui';
@ -7,7 +7,6 @@ import { RouterHistoryService } from '@services/router-history.service';
import { firstValueFrom } from 'rxjs';
@Component({
selector: 'redaction-downloads-list-screen',
templateUrl: './downloads-list-screen.component.html',
styleUrls: ['./downloads-list-screen.component.scss'],
providers: listingProvidersFactory<DownloadStatus>({
@ -15,7 +14,7 @@ import { firstValueFrom } from 'rxjs';
component: DownloadsListScreenComponent,
}),
})
export class DownloadsListScreenComponent extends ListingComponent<DownloadStatus> {
export class DownloadsListScreenComponent extends ListingComponent<DownloadStatus> implements OnDestroy {
readonly circleButtonTypes = CircleButtonTypes;
readonly tableHeaderLabel = _('downloads-list.table-header.title');
readonly tableColumnConfigs: TableColumnConfig<DownloadStatus>[] = [
@ -24,6 +23,7 @@ export class DownloadsListScreenComponent extends ListingComponent<DownloadStatu
{ label: _('downloads-list.table-col-names.date') },
{ label: _('downloads-list.table-col-names.status') },
];
readonly #interval: NodeJS.Timer;
constructor(
private readonly _loadingService: LoadingService,
@ -32,7 +32,11 @@ export class DownloadsListScreenComponent extends ListingComponent<DownloadStatu
) {
super();
this._loadingService.loadWhile(this._loadData());
setInterval(() => this._loadData(), 5000);
this.#interval = setInterval(() => this._loadData(), 5000);
}
ngOnDestroy() {
clearInterval(this.#interval);
}
downloadItem(download: DownloadStatus) {

View File

@ -2,16 +2,15 @@
<div class="container">
<div
[translateParams]="{ name: currentUser.firstName || currentUser.name }"
[translate]="'dashboard.greeting.title'"
[innerHTML]="'dashboard.greeting.title' | translate : { name: currentUser.firstName || currentUser.name }"
class="heading-xl mb-8"
></div>
<div class="mb-32" translate="dashboard.greeting.subtitle"></div>
<redaction-template-stats
*ngFor="let dossierTemplate of stats$ | async; let index = index"
*ngFor="let dossierTemplate of stats$ | async; trackBy: trackBy"
[id]="'dossier-template-stats-' + dossierTemplate.id"
[stats]="dossierTemplate"
[id]="'dossier-template-card-' + index"
></redaction-template-stats>
</div>

View File

@ -1,23 +1,19 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { UserService } from '@users/user.service';
import { Component, inject, OnInit } from '@angular/core';
import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service';
import { UserPreferenceService } from '@users/user-preference.service';
import { getCurrentUser, trackByFactory } from '@iqser/common-ui';
import { User } from '@red/domain';
@Component({
selector: 'redaction-dashboard-screen',
templateUrl: './dashboard-screen.component.html',
styleUrls: ['./dashboard-screen.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardScreenComponent implements OnInit {
readonly currentUser = this._userService.currentUser;
readonly stats$ = this._dashboardStatsService.all$;
readonly currentUser = getCurrentUser<User>();
readonly stats$ = inject(DashboardStatsService).all$;
readonly trackBy = trackByFactory();
constructor(
private readonly _userService: UserService,
private readonly _dashboardStatsService: DashboardStatsService,
private readonly _userPreferenceService: UserPreferenceService,
) {}
constructor(private readonly _userPreferenceService: UserPreferenceService) {}
async ngOnInit(): Promise<void> {
await this._userPreferenceService.saveLastDossierTemplate(null);

View File

@ -2,10 +2,9 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DashboardScreenComponent } from './dashboard-screen/dashboard-screen.component';
import { RouterModule } from '@angular/router';
import { SharedModule } from '../shared/shared.module';
import { SharedModule } from '@shared/shared.module';
import { TemplateStatsComponent } from './components/template-stats/template-stats.component';
import { BreadcrumbTypes } from '@red/domain';
import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module';
import { TranslateModule } from '@ngx-translate/core';
import { IqserButtonsModule, IqserHelpModeModule, IqserPermissionsModule } from '@iqser/common-ui';
@ -25,7 +24,6 @@ const routes = [
RouterModule.forChild(routes),
CommonModule,
SharedModule,
SharedDossiersModule,
TranslateModule,
IqserButtonsModule,
IqserHelpModeModule,

View File

@ -1,18 +1,9 @@
import { Injectable } from '@angular/core';
import {
DownloadStatus,
IDownloadResponse,
IDownloadStatus,
IDownloadStatusResponse,
IPrepareDownloadRequest,
IRemoveDownloadRequest,
} from '@red/domain';
import { DownloadStatus, IDownloadStatus, IDownloadStatusResponse, IPrepareDownloadRequest, IRemoveDownloadRequest } from '@red/domain';
import { firstValueFrom, Observable } from 'rxjs';
import { ConfigService } from '@services/config.service';
import { map, switchMap, tap } from 'rxjs/operators';
import { KeycloakService } from 'keycloak-angular';
import { UserService } from '@users/user.service';
import { EntitiesService, List, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
import { map, tap } from 'rxjs/operators';
import { EntitiesService, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
import { NGXLogger } from 'ngx-logger';
@Injectable()
@ -20,18 +11,13 @@ export class FileDownloadService extends EntitiesService<IDownloadStatus, Downlo
protected readonly _defaultModelPath = 'async/download';
protected readonly _entityClass = DownloadStatus;
constructor(
private readonly _userService: UserService,
private readonly _keycloakService: KeycloakService,
private readonly _configService: ConfigService,
private readonly _logger: NGXLogger,
) {
constructor(private readonly _configService: ConfigService, private readonly _logger: NGXLogger) {
super();
}
downloadFiles(request: IPrepareDownloadRequest): Promise<DownloadStatus[]> {
const prepare = this.prepareDownload(request).pipe(switchMap(() => this.loadAll()));
return firstValueFrom(prepare);
async downloadFiles(request: IPrepareDownloadRequest) {
await this.prepareDownload(request);
return firstValueFrom(this.loadAll());
}
loadAll(): Observable<DownloadStatus[]> {
@ -46,7 +32,7 @@ export class FileDownloadService extends EntitiesService<IDownloadStatus, Downlo
}
async performDownload(status: DownloadStatus) {
const token = await firstValueFrom(this.generateToken(status.storageId));
const token = await this.generateToken(status.storageId);
const anchor = document.createElement('a');
anchor.href = `${this._configService.values.API_URL}/async/download/with-ott/${token.value}`;
anchor.download = status.filename;
@ -58,13 +44,14 @@ export class FileDownloadService extends EntitiesService<IDownloadStatus, Downlo
}
@Validate()
prepareDownload(@RequiredParam() body: IPrepareDownloadRequest): Observable<IDownloadResponse> {
return this._post(body, `${this._defaultModelPath}/prepare-option`);
prepareDownload(@RequiredParam() body: IPrepareDownloadRequest) {
return firstValueFrom(this._post(body, `${this._defaultModelPath}/prepare-option`));
}
@Validate()
generateToken(@RequiredParam() storageId: string): Observable<{ value: string }> {
return this._post<{ value: string }>({ value: storageId }, `${this._defaultModelPath}/generate-ott`);
generateToken(@RequiredParam() storageId: string) {
const request = this._post<{ value: string }>({ value: storageId }, `${this._defaultModelPath}/generate-ott`);
return firstValueFrom(request);
}
@Validate()