RED-3800: some fixes
This commit is contained in:
parent
697acb44db
commit
d1ad17bc5d
47
README.md
47
README.md
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user