Merge remote-tracking branch 'origin/master' into RED-3796
This commit is contained in:
commit
19f6b057e7
@ -16,6 +16,14 @@
|
||||
"resources": {
|
||||
"files": ["/assets/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pdftron",
|
||||
"installMode": "prefetch",
|
||||
"updateMode": "prefetch",
|
||||
"resources": {
|
||||
"files": ["/assets/wv-resources/**/*.*"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -38,13 +38,13 @@ export class AnnotationPermissions {
|
||||
permissions.canMarkAsFalsePositive = annotation.canBeMarkedAsFalsePositive && annotationEntity.hasDictionary;
|
||||
|
||||
permissions.canRemoveOrSuggestToRemoveOnlyHere =
|
||||
(annotation.isRedacted || annotation.isHint) && !annotation.pending && !annotation.isImage;
|
||||
!annotation.pending && (annotation.isRedacted || (annotation.isHint && !annotation.isImage));
|
||||
permissions.canRemoveOrSuggestToRemoveFromDictionary =
|
||||
annotation.isModifyDictionary &&
|
||||
(annotation.isRedacted || annotation.isSkipped || annotation.isHint) &&
|
||||
!annotation.pending;
|
||||
|
||||
permissions.canChangeLegalBasis = annotation.isRedacted && !annotation.imported && !annotation.pending;
|
||||
permissions.canChangeLegalBasis = annotation.isRedacted && !annotation.pending;
|
||||
|
||||
permissions.canRecategorizeImage =
|
||||
((annotation.isImage && !annotation.isSuggestion) || annotation.isSuggestionRecategorizeImage) && !annotation.pending;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { annotationTypesTranslations } from '../../translations/annotation-types-translations';
|
||||
import { annotationTypesTranslations, SuggestionAddFalsePositive } from '../../translations/annotation-types-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { Highlight, IComment, IManualChange, IPoint, IRectangle, LogEntryStatus, ManualRedactionType } from '@red/domain';
|
||||
import { RedactionLogEntry } from '@models/file/redaction-log.entry';
|
||||
@ -292,11 +292,18 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
|
||||
this._createContent(annotationWrapper, redactionLogEntry);
|
||||
this._setSuperType(annotationWrapper, redactionLogEntry);
|
||||
this._handleRecommendations(annotationWrapper, redactionLogEntry);
|
||||
annotationWrapper.typeLabel = annotationTypesTranslations[annotationWrapper.superType];
|
||||
annotationWrapper.typeLabel = this.#getTypeLabel(redactionLogEntry, annotationWrapper);
|
||||
|
||||
return annotationWrapper;
|
||||
}
|
||||
|
||||
static #getTypeLabel(redactionLogEntry: RedactionLogEntry, annotation: AnnotationWrapper): string {
|
||||
if (redactionLogEntry.reason?.toLowerCase() === 'false positive') {
|
||||
return annotationTypesTranslations[SuggestionAddFalsePositive];
|
||||
}
|
||||
return annotationTypesTranslations[annotation.superType];
|
||||
}
|
||||
|
||||
private static _handleRecommendations(annotationWrapper: AnnotationWrapper, redactionLogEntry: RedactionLogEntry) {
|
||||
if (annotationWrapper.superType === SuperTypes.Recommendation) {
|
||||
annotationWrapper.recommendationType = redactionLogEntry.type;
|
||||
|
||||
@ -7,7 +7,6 @@ import { PendingChangesGuard } from '@guards/can-deactivate.guard';
|
||||
import { FileAttributesListingScreenComponent } from './screens/file-attributes-listing/file-attributes-listing-screen.component';
|
||||
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { LicenseInformationScreenComponent } from './screens/license-information/license-information-screen.component';
|
||||
import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component';
|
||||
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
@ -26,125 +25,127 @@ import { ACTIVE_DOSSIERS_SERVICE } from '../../tokens';
|
||||
import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component';
|
||||
import { PermissionsGuard } from '../../guards/permissions-guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'dossier-templates', pathMatch: 'full' },
|
||||
const dossierTemplateIdRoutes = [
|
||||
{
|
||||
path: 'dossier-templates',
|
||||
path: 'info',
|
||||
canActivate: [CompositeRouteGuard],
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
loadChildren: () => import('./screens/info/dossier-template-info.module').then(m => m.DossierTemplateInfoModule),
|
||||
},
|
||||
{
|
||||
path: 'entities',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: BaseAdminScreenComponent,
|
||||
component: EntitiesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () =>
|
||||
import('./screens/dossier-templates-listing/dossier-templates-listing.module').then(
|
||||
m => m.DossierTemplatesListingModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: `:${DOSSIER_TEMPLATE_ID}`,
|
||||
children: [
|
||||
{
|
||||
path: 'info',
|
||||
canActivate: [CompositeRouteGuard],
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
loadChildren: () => import('./screens/info/dossier-template-info.module').then(m => m.DossierTemplateInfoModule),
|
||||
},
|
||||
{
|
||||
path: 'entities',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: EntitiesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: `:${ENTITY_TYPE}`,
|
||||
component: BaseEntityScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
loadChildren: () => import('./screens/entities/entities.module').then(m => m.EntitiesModule),
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, EntityExistsGuard],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/rules/rules.module').then(m => m.RulesModule),
|
||||
},
|
||||
{
|
||||
path: 'file-attributes',
|
||||
component: FileAttributesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'watermark',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule),
|
||||
},
|
||||
{
|
||||
path: 'reports',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/reports/reports.module').then(m => m.ReportsModule),
|
||||
},
|
||||
{
|
||||
path: 'dossier-attributes',
|
||||
component: DossierAttributesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'dossier-states',
|
||||
component: DossierStatesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'default-colors',
|
||||
component: DefaultColorsScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'justifications',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
loadChildren: () => import('./screens/justifications/justifications.module').then(m => m.JustificationsModule),
|
||||
},
|
||||
{ path: '', redirectTo: 'info', pathMatch: 'full' },
|
||||
],
|
||||
path: `:${ENTITY_TYPE}`,
|
||||
component: BaseEntityScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: { routeGuards: [DossierTemplateExistsGuard] },
|
||||
loadChildren: () => import('./screens/entities/entities.module').then(m => m.EntitiesModule),
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, EntityExistsGuard],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/rules/rules.module').then(m => m.RulesModule),
|
||||
},
|
||||
{
|
||||
path: 'file-attributes',
|
||||
component: FileAttributesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'watermark',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule),
|
||||
},
|
||||
{
|
||||
path: 'reports',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/reports/reports.module').then(m => m.ReportsModule),
|
||||
},
|
||||
{
|
||||
path: 'dossier-attributes',
|
||||
component: DossierAttributesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'dossier-states',
|
||||
component: DossierStatesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'default-colors',
|
||||
component: DefaultColorsScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'justifications',
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
loadChildren: () => import('./screens/justifications/justifications.module').then(m => m.JustificationsModule),
|
||||
},
|
||||
{ path: '', redirectTo: 'info', pathMatch: 'full' },
|
||||
];
|
||||
|
||||
const dossierTemplatesRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: BaseAdminScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
},
|
||||
loadChildren: () =>
|
||||
import('./screens/dossier-templates-listing/dossier-templates-listing.module').then(m => m.DossierTemplatesListingModule),
|
||||
},
|
||||
{
|
||||
path: `:${DOSSIER_TEMPLATE_ID}`,
|
||||
children: dossierTemplateIdRoutes,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: { routeGuards: [DossierTemplateExistsGuard] },
|
||||
},
|
||||
];
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'dossier-templates', pathMatch: 'full' },
|
||||
{
|
||||
path: 'dossier-templates',
|
||||
children: dossierTemplatesRoutes,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard],
|
||||
@ -173,12 +174,13 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'license-info',
|
||||
component: LicenseInformationScreenComponent,
|
||||
component: BaseAdminScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard],
|
||||
requiredRoles: ['RED_ADMIN'],
|
||||
},
|
||||
loadChildren: () => import('./screens/license/license.module').then(m => m.LicenseModule),
|
||||
},
|
||||
{
|
||||
path: 'digital-signature',
|
||||
|
||||
@ -7,7 +7,6 @@ import { DefaultColorsScreenComponent } from './screens/default-colors/default-c
|
||||
import { EntitiesListingScreenComponent } from './screens/entities-listing/entities-listing-screen.component';
|
||||
import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component';
|
||||
import { FileAttributesListingScreenComponent } from './screens/file-attributes-listing/file-attributes-listing-screen.component';
|
||||
import { LicenseInformationScreenComponent } from './screens/license-information/license-information-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { DossierTemplateBreadcrumbsComponent } from './components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
@ -15,8 +14,6 @@ import { AddEditFileAttributeDialogComponent } from './dialogs/add-edit-file-att
|
||||
import { AddEditDossierTemplateDialogComponent } from './dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
|
||||
import { AddEntityDialogComponent } from './dialogs/add-entity-dialog/add-entity-dialog.component';
|
||||
import { EditColorDialogComponent } from './dialogs/edit-color-dialog/edit-color-dialog.component';
|
||||
import { ComboChartComponent, ComboSeriesVerticalComponent } from './components/combo-chart';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
import { AdminDialogService } from './services/admin-dialog.service';
|
||||
import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component';
|
||||
import { SmtpAuthDialogComponent } from './dialogs/smtp-auth-dialog/smtp-auth-dialog.component';
|
||||
@ -24,7 +21,6 @@ import { AddEditUserDialogComponent } from './dialogs/add-edit-user-dialog/add-e
|
||||
import { UsersStatsComponent } from './components/users-stats/users-stats.component';
|
||||
import { FileAttributesCsvImportDialogComponent } from './dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component';
|
||||
import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component';
|
||||
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
|
||||
import { ResetPasswordComponent } from './dialogs/add-edit-user-dialog/reset-password/reset-password.component';
|
||||
import { UserDetailsComponent } from './dialogs/add-edit-user-dialog/user-details/user-details.component';
|
||||
import { AddEditDossierAttributeDialogComponent } from './dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component';
|
||||
@ -33,7 +29,6 @@ import { TrashScreenComponent } from './screens/trash/trash-screen.component';
|
||||
import { AuditService } from './services/audit.service';
|
||||
import { DigitalSignatureService } from './services/digital-signature.service';
|
||||
import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component';
|
||||
import { LicenseReportService } from './services/licence-report.service';
|
||||
import { RulesService } from './services/rules.service';
|
||||
import { SmtpConfigService } from './services/smtp-config.service';
|
||||
import { UploadDictionaryDialogComponent } from './dialogs/upload-dictionary-dialog/upload-dictionary-dialog.component';
|
||||
@ -49,6 +44,7 @@ import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-dele
|
||||
import { TrashTableItemComponent } from './screens/trash/trash-table-item/trash-table-item.component';
|
||||
import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component';
|
||||
import { CloneDossierTemplateDialogComponent } from './dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component';
|
||||
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
|
||||
|
||||
const dialogs = [
|
||||
AddEditDossierTemplateDialogComponent,
|
||||
@ -70,7 +66,6 @@ const screens = [
|
||||
EntitiesListingScreenComponent,
|
||||
DigitalSignatureScreenComponent,
|
||||
FileAttributesListingScreenComponent,
|
||||
LicenseInformationScreenComponent,
|
||||
UserListingScreenComponent,
|
||||
GeneralConfigScreenComponent,
|
||||
DossierAttributesListingScreenComponent,
|
||||
@ -79,11 +74,9 @@ const screens = [
|
||||
|
||||
const components = [
|
||||
DossierTemplateBreadcrumbsComponent,
|
||||
ComboChartComponent,
|
||||
ComboSeriesVerticalComponent,
|
||||
UsersStatsComponent,
|
||||
ActiveFieldsListingComponent,
|
||||
AdminSideNavComponent,
|
||||
ActiveFieldsListingComponent,
|
||||
ResetPasswordComponent,
|
||||
UserDetailsComponent,
|
||||
BaseAdminScreenComponent,
|
||||
@ -104,7 +97,7 @@ const components = [
|
||||
ConfirmDeleteDossierStateDialogComponent,
|
||||
TrashTableItemComponent,
|
||||
],
|
||||
providers: [AdminDialogService, AuditService, DigitalSignatureService, LicenseReportService, RulesService, SmtpConfigService],
|
||||
imports: [CommonModule, SharedModule, AdminRoutingModule, SharedAdminModule, NgxChartsModule, ColorPickerModule, A11yModule],
|
||||
providers: [AdminDialogService, AuditService, DigitalSignatureService, RulesService, SmtpConfigService],
|
||||
imports: [CommonModule, SharedModule, AdminRoutingModule, SharedAdminModule, ColorPickerModule, A11yModule],
|
||||
})
|
||||
export class AdminModule {}
|
||||
|
||||
@ -1,184 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ButtonConfig, IconButtonTypes, LoadingService } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { LicenseReportService } from '../../services/licence-report.service';
|
||||
import { ILicenseReport } from '@red/domain';
|
||||
import { Color, ScaleType } from '@swimlane/ngx-charts';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-license-information-screen',
|
||||
templateUrl: './license-information-screen.component.html',
|
||||
styleUrls: ['./license-information-screen.component.scss'],
|
||||
})
|
||||
export class LicenseInformationScreenComponent implements OnInit {
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly buttonConfigs: readonly ButtonConfig[] = [
|
||||
{
|
||||
label: _('license-info-screen.email-report'),
|
||||
action: (): void => this.sendMail(),
|
||||
type: IconButtonTypes.primary,
|
||||
},
|
||||
];
|
||||
|
||||
currentInfo: ILicenseReport = {};
|
||||
totalInfo: ILicenseReport = {};
|
||||
unlicensedInfo: ILicenseReport = {};
|
||||
totalLicensedNumberOfPages = 0;
|
||||
analysisPercentageOfLicense = 100;
|
||||
barChart: any[];
|
||||
lineChartSeries: any[] = [];
|
||||
lineChartScheme: Color = {
|
||||
name: 'Line chart scheme',
|
||||
selectable: true,
|
||||
group: ScaleType.Ordinal,
|
||||
domain: ['#dd4d50', '#5ce594', '#0389ec'],
|
||||
};
|
||||
comboBarScheme: Color = {
|
||||
name: 'Combo bar scheme',
|
||||
selectable: true,
|
||||
group: ScaleType.Ordinal,
|
||||
domain: ['#0389ec'],
|
||||
};
|
||||
|
||||
constructor(
|
||||
readonly configService: ConfigService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
readonly routerHistoryService: RouterHistoryService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _licenseReportService: LicenseReportService,
|
||||
) {
|
||||
_loadingService.start();
|
||||
}
|
||||
|
||||
get currentYear(): number {
|
||||
return new Date().getFullYear();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.totalLicensedNumberOfPages = this.configService.values.LICENSE_PAGE_COUNT || 0;
|
||||
const startDate = dayjs(this.configService.values.LICENSE_START, 'DD-MM-YYYY');
|
||||
const endDate = dayjs(this.configService.values.LICENSE_END, 'DD-MM-YYYY');
|
||||
|
||||
await this._setMonthlyStats(startDate, endDate);
|
||||
|
||||
const currentConfig = {
|
||||
startDate: startDate.toDate(),
|
||||
endDate: endDate.toDate(),
|
||||
};
|
||||
const promises = [
|
||||
firstValueFrom(this._licenseReportService.licenseReport(currentConfig)),
|
||||
firstValueFrom(this._licenseReportService.licenseReport({})),
|
||||
];
|
||||
|
||||
if (endDate.isBefore(dayjs())) {
|
||||
const unlicensedConfig = {
|
||||
startDate: endDate.toDate(),
|
||||
};
|
||||
promises.push(firstValueFrom(this._licenseReportService.licenseReport(unlicensedConfig)));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(reports => {
|
||||
[this.currentInfo, this.totalInfo, this.unlicensedInfo] = reports;
|
||||
this._loadingService.stop();
|
||||
this.analysisPercentageOfLicense =
|
||||
this.totalLicensedNumberOfPages > 0
|
||||
? (this.currentInfo.numberOfAnalyzedPages / this.totalLicensedNumberOfPages) * 100
|
||||
: 100;
|
||||
});
|
||||
}
|
||||
|
||||
sendMail(): void {
|
||||
const licenseCustomer = this.configService.values.LICENSE_CUSTOMER;
|
||||
const subject = this._translateService.instant('license-info-screen.email.title', {
|
||||
licenseCustomer,
|
||||
});
|
||||
const lineBreak = '%0D%0A';
|
||||
const body = [
|
||||
this._translateService.instant('license-info-screen.email.body.analyzed', {
|
||||
pages: this.currentInfo.numberOfAnalyzedPages,
|
||||
}),
|
||||
this._translateService.instant('license-info-screen.email.body.licensed', {
|
||||
pages: this.totalLicensedNumberOfPages,
|
||||
}),
|
||||
].join(lineBreak);
|
||||
window.location.href = `mailto:${this.configService.values.LICENSE_EMAIL}?subject=${subject}&body=${body}`;
|
||||
}
|
||||
|
||||
private async _setMonthlyStats(startDate: dayjs.Dayjs, endDate: dayjs.Dayjs) {
|
||||
const [startMonth, startYear] = [startDate.month(), startDate.year()];
|
||||
const [endMonth, endYear] = [endDate.month(), endDate.year()];
|
||||
|
||||
let m: number = startMonth;
|
||||
let y: number = startYear;
|
||||
const totalLicensedSeries = [];
|
||||
const cumulativePagesSeries = [];
|
||||
const promises = [];
|
||||
|
||||
while (m <= endMonth && y <= endYear) {
|
||||
totalLicensedSeries.push({
|
||||
name: `${dayjs.monthsShort()[m]} ${y}`,
|
||||
value: this.totalLicensedNumberOfPages,
|
||||
});
|
||||
|
||||
let nm = m + 1;
|
||||
let ny = y;
|
||||
if (nm === 12) {
|
||||
nm = 0;
|
||||
ny++;
|
||||
}
|
||||
|
||||
promises.push(
|
||||
firstValueFrom(
|
||||
this._licenseReportService.licenseReport({
|
||||
startDate: dayjs(`01-${m + 1}-${y}`, 'DD-M-YYYY').toDate(),
|
||||
endDate: dayjs(`01-${nm + 1}-${ny}`, 'DD-M-YYYY').toDate(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
y = ny;
|
||||
m = nm;
|
||||
}
|
||||
|
||||
const reports = await Promise.all(promises);
|
||||
|
||||
m = startMonth;
|
||||
y = startYear;
|
||||
let cumulativePages = 0;
|
||||
this.barChart = [];
|
||||
for (const report of reports) {
|
||||
cumulativePages += report.numberOfAnalyzedPages;
|
||||
this.barChart.push({
|
||||
name: `${dayjs.monthsShort()[m]} ${y}`,
|
||||
value: report.numberOfAnalyzedPages,
|
||||
});
|
||||
cumulativePagesSeries.push({
|
||||
name: `${dayjs.monthsShort()[m]} ${y}`,
|
||||
value: cumulativePages,
|
||||
});
|
||||
m++;
|
||||
if (m === 12) {
|
||||
m = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
this.lineChartSeries = [
|
||||
{
|
||||
name: this._translateService.instant('license-info-screen.chart.licensed-total'),
|
||||
series: totalLicensedSeries,
|
||||
},
|
||||
{
|
||||
name: this._translateService.instant('license-info-screen.chart.cumulative'),
|
||||
series: cumulativePagesSeries,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<combo-chart-component
|
||||
*ngIf="lineChartSeries$ | async as lineChartSeries"
|
||||
[animations]="true"
|
||||
[colorSchemeLine]="lineChartScheme"
|
||||
[legendTitle]="'license-info-screen.chart.legend' | translate"
|
||||
[legend]="true"
|
||||
[lineChart]="lineChartSeries"
|
||||
[results]="barChart"
|
||||
[scheme]="comboBarScheme"
|
||||
[showGridLines]="true"
|
||||
[showRightYAxisLabel]="true"
|
||||
[showYAxisLabel]="true"
|
||||
[view]="[1000, 300]"
|
||||
[xAxis]="true"
|
||||
[yAxisLabelRight]="'license-info-screen.chart.total-pages' | translate"
|
||||
[yAxisLabel]="'license-info-screen.chart.pages-per-month' | translate"
|
||||
[yAxis]="true"
|
||||
></combo-chart-component>
|
||||
@ -0,0 +1,127 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ComboBarScheme, LICENSE_STORAGE_KEY, LineChartScheme } from '../utils/constants';
|
||||
import dayjs from 'dayjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ILicenseReport } from '@red/domain';
|
||||
import { LicenseService } from '../services/license.service';
|
||||
import { IDateRange } from '../utils/date-range';
|
||||
import { ILicense } from '../utils/license';
|
||||
import { switchMap, tap } from 'rxjs/operators';
|
||||
import { ILineChartSeries } from '../combo-chart/models';
|
||||
import { LoadingService } from '@iqser/common-ui';
|
||||
import { generateDateRanges, isCurrentMonth, toDate } from '../utils/functions';
|
||||
|
||||
const monthNames = dayjs.monthsShort();
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-license-chart',
|
||||
templateUrl: './license-chart.component.html',
|
||||
styleUrls: ['./license-chart.component.scss'],
|
||||
})
|
||||
export class LicenseChartComponent {
|
||||
readonly lineChartScheme = LineChartScheme;
|
||||
readonly comboBarScheme = ComboBarScheme;
|
||||
|
||||
lineChartSeries$ = this.#licenseChartSeries$;
|
||||
barChart: any[];
|
||||
|
||||
constructor(
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _licenseService: LicenseService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
) {}
|
||||
|
||||
get #licenseChartSeries$() {
|
||||
return this._licenseService.selectedLicense$.pipe(
|
||||
tap(() => this._loadingService.start()),
|
||||
switchMap(license => this.#setMonthlyStats(license)),
|
||||
tap(() => this._loadingService.stop()),
|
||||
);
|
||||
}
|
||||
|
||||
async #setMonthlyStats(licence: ILicense): Promise<ILineChartSeries[]> {
|
||||
const startDate = dayjs(licence.validFrom);
|
||||
const endDate = dayjs(licence.validUntil);
|
||||
const startMonth: number = startDate.month();
|
||||
const startYear: number = startDate.year();
|
||||
|
||||
const dateRanges = generateDateRanges(startMonth, startYear, endDate.month(), endDate.year());
|
||||
const reports = await this.#getReports(dateRanges);
|
||||
|
||||
return [
|
||||
{
|
||||
name: this._translateService.instant('license-info-screen.chart.licensed-total'),
|
||||
series: this.#totalLicensedPagesSeries(dateRanges),
|
||||
},
|
||||
{
|
||||
name: this._translateService.instant('license-info-screen.chart.cumulative'),
|
||||
series: this.#setBarChartAndGetCumulativePageSeries(startMonth, startYear, reports),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
#setBarChartAndGetCumulativePageSeries(month: number, year: number, reports: ILicenseReport[]) {
|
||||
let cumulativePages = 0;
|
||||
const cumulativePagesSeries = [];
|
||||
this.barChart = [];
|
||||
|
||||
for (const report of reports) {
|
||||
cumulativePages += report.numberOfAnalyzedPages;
|
||||
|
||||
const name = `${monthNames[month]} ${year}`;
|
||||
this.barChart.push({
|
||||
name,
|
||||
value: report.numberOfAnalyzedPages,
|
||||
});
|
||||
|
||||
cumulativePagesSeries.push({
|
||||
name,
|
||||
value: cumulativePages,
|
||||
});
|
||||
|
||||
month++;
|
||||
if (month === 12) {
|
||||
month = 0;
|
||||
year++;
|
||||
}
|
||||
}
|
||||
|
||||
return cumulativePagesSeries;
|
||||
}
|
||||
|
||||
#getReports(dateRanges: IDateRange[]) {
|
||||
const reports = dateRanges.map(dateRange => {
|
||||
const startMonth = dateRange.startMonth + 1;
|
||||
const endMonth = dateRange.endMonth + 1;
|
||||
|
||||
const key = `${startMonth}.${dateRange.startYear}-${endMonth}.${dateRange.endYear}`;
|
||||
const existingReport = this._licenseService.storedReports[key];
|
||||
if (existingReport) {
|
||||
return existingReport;
|
||||
}
|
||||
|
||||
const startDate = toDate(startMonth, dateRange.startYear);
|
||||
const endDate = toDate(endMonth, dateRange.endYear);
|
||||
const requestedReport = this._licenseService.getReport({ startDate, endDate });
|
||||
return requestedReport.then(report => this.#storeReportIfNotCurrentMonth(dateRange, report, key));
|
||||
});
|
||||
|
||||
return Promise.all(reports);
|
||||
}
|
||||
|
||||
#storeReportIfNotCurrentMonth(dateRange: IDateRange, report: ILicenseReport, key: string) {
|
||||
if (!isCurrentMonth(dateRange.startMonth + 1, dateRange.startYear)) {
|
||||
this._licenseService.storedReports[key] = report;
|
||||
localStorage.setItem(LICENSE_STORAGE_KEY, JSON.stringify(this._licenseService.storedReports));
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
#totalLicensedPagesSeries(dateRanges: IDateRange[]) {
|
||||
return dateRanges.map(dateRange => ({
|
||||
name: `${monthNames[dateRange.startMonth]} ${dateRange.startYear}`,
|
||||
value: this._licenseService.totalLicensedNumberOfPages,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,4 @@
|
||||
<section class="settings">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||
|
||||
<div>
|
||||
<iqser-page-header
|
||||
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
||||
@ -38,19 +34,28 @@
|
||||
|
||||
<div class="section-title all-caps-label" translate="license-info-screen.licensing-details"></div>
|
||||
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.licensed-to"></div>
|
||||
<div>{{ configService.values.LICENSE_CUSTOMER || '-' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.licensing-period"></div>
|
||||
<div *ngIf="userPreferenceService.areDevFeaturesEnabled" class="row">
|
||||
<div class="flex align-center" translate="license-info-screen.license-title"></div>
|
||||
<div>
|
||||
{{ configService.values.LICENSE_START || '-' }} /
|
||||
{{ configService.values.LICENSE_END || '-' }}
|
||||
<redaction-license-select (valueChanges)="licenceChanged($event)"></redaction-license-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="licenseService.selectedLicense$ | async as selectedLicense">
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.licensed-to"></div>
|
||||
<div>{{ selectedLicense.licensedTo || '-' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.licensing-period"></div>
|
||||
<div>
|
||||
{{ (selectedLicense.validFrom | date: 'dd-MM-YYYY') || '-' }} /
|
||||
{{ (selectedLicense.validUntil | date: 'dd-MM-YYYY') || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="row">
|
||||
<div>{{ 'license-info-screen.licensed-page-count' | translate }}</div>
|
||||
<div>{{ totalLicensedNumberOfPages }}</div>
|
||||
@ -86,23 +91,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<combo-chart-component
|
||||
[animations]="true"
|
||||
[colorSchemeLine]="lineChartScheme"
|
||||
[legendTitle]="'license-info-screen.chart.legend' | translate"
|
||||
[legend]="true"
|
||||
[lineChart]="lineChartSeries"
|
||||
[results]="barChart"
|
||||
[scheme]="comboBarScheme"
|
||||
[showGridLines]="true"
|
||||
[showRightYAxisLabel]="true"
|
||||
[showYAxisLabel]="true"
|
||||
[view]="[1000, 300]"
|
||||
[xAxis]="true"
|
||||
[yAxisLabelRight]="'license-info-screen.chart.total-pages' | translate"
|
||||
[yAxisLabel]="'license-info-screen.chart.pages-per-month' | translate"
|
||||
[yAxis]="true"
|
||||
></combo-chart-component>
|
||||
<redaction-license-chart></redaction-license-chart>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,95 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ButtonConfig, IconButtonTypes, LoadingService } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { LicenseService } from '../services/license.service';
|
||||
import { ILicenseReport } from '@red/domain';
|
||||
import dayjs from 'dayjs';
|
||||
import { ILicense } from '../utils/license';
|
||||
import { UserPreferenceService } from '../../../../../services/user-preference.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './license-screen.component.html',
|
||||
styleUrls: ['./license-screen.component.scss'],
|
||||
})
|
||||
export class LicenseScreenComponent implements OnInit {
|
||||
readonly currentYear = new Date().getFullYear();
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly buttonConfigs: readonly ButtonConfig[] = [
|
||||
{
|
||||
label: _('license-info-screen.email-report'),
|
||||
action: (): void => this.sendMail(),
|
||||
type: IconButtonTypes.primary,
|
||||
},
|
||||
];
|
||||
|
||||
currentInfo: ILicenseReport = {};
|
||||
totalInfo: ILicenseReport = {};
|
||||
unlicensedInfo: ILicenseReport = {};
|
||||
analysisPercentageOfLicense = 100;
|
||||
totalLicensedNumberOfPages = this.licenseService.totalLicensedNumberOfPages;
|
||||
|
||||
constructor(
|
||||
readonly configService: ConfigService,
|
||||
readonly userPreferenceService: UserPreferenceService,
|
||||
readonly licenseService: LicenseService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
readonly routerHistoryService: RouterHistoryService,
|
||||
private readonly _translateService: TranslateService,
|
||||
) {
|
||||
_loadingService.start();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
return this.loadLicenceData(this.licenseService.selectedLicense);
|
||||
}
|
||||
|
||||
async loadLicenceData(license: ILicense) {
|
||||
const startDate = dayjs(license.validFrom);
|
||||
const endDate = dayjs(license.validUntil);
|
||||
|
||||
const currentConfig = {
|
||||
startDate: startDate.toDate(),
|
||||
endDate: endDate.toDate(),
|
||||
};
|
||||
const reports: Promise<ILicenseReport>[] = [this.licenseService.getReport(currentConfig), this.licenseService.getReport({})];
|
||||
|
||||
if (endDate.isBefore(dayjs())) {
|
||||
const unlicensedConfig = {
|
||||
startDate: endDate.toDate(),
|
||||
};
|
||||
reports.push(this.licenseService.getReport(unlicensedConfig));
|
||||
}
|
||||
|
||||
[this.currentInfo, this.totalInfo, this.unlicensedInfo] = await Promise.all(reports);
|
||||
this.analysisPercentageOfLicense =
|
||||
this.totalLicensedNumberOfPages > 0 ? (this.currentInfo.numberOfAnalyzedPages / this.totalLicensedNumberOfPages) * 100 : 100;
|
||||
}
|
||||
|
||||
sendMail(): void {
|
||||
const licenseCustomer = this.licenseService.selectedLicense.licensedTo;
|
||||
const subject = this._translateService.instant('license-info-screen.email.title', {
|
||||
licenseCustomer,
|
||||
});
|
||||
const lineBreak = '%0D%0A';
|
||||
const body = [
|
||||
this._translateService.instant('license-info-screen.email.body.analyzed', {
|
||||
pages: this.currentInfo.numberOfAnalyzedPages,
|
||||
}),
|
||||
this._translateService.instant('license-info-screen.email.body.licensed', {
|
||||
pages: this.totalLicensedNumberOfPages,
|
||||
}),
|
||||
].join(lineBreak);
|
||||
const mail = this.licenseService.selectedLicense.licensedToEmail;
|
||||
window.location.href = `mailto:${mail}?subject=${subject}&body=${body}`;
|
||||
}
|
||||
|
||||
licenceChanged(license: ILicense) {
|
||||
this.totalLicensedNumberOfPages = this.licenseService.totalLicensedNumberOfPages;
|
||||
return this.loadLicenceData(license);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<div class="iqser-input-group w-400">
|
||||
<mat-select (valueChange)="licenseChanged($event)" [(ngModel)]="value">
|
||||
<mat-select-trigger>
|
||||
<ng-container *ngTemplateOutlet="licenseInfo; context: { license: value }"></ng-container>
|
||||
</mat-select-trigger>
|
||||
|
||||
<mat-option *ngFor="let license of licenseService.licenseData.licenses" [value]="license">
|
||||
<ng-container *ngTemplateOutlet="licenseInfo; context: { license: this.license }"></ng-container>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
|
||||
<ng-template #licenseInfo let-license="license">
|
||||
<div class="flex space-between align-center">
|
||||
<span>{{ license.name }}</span>
|
||||
<div class="mr-10 flex align-center">
|
||||
<div [class.green]="license.id === licenseService.activeLicenseId" class="dot mr-4"></div>
|
||||
<span class="small-label">{{ getStatus(license.id) | translate | uppercase }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
@ -0,0 +1,15 @@
|
||||
.green {
|
||||
background: var(--iqser-green-2);
|
||||
}
|
||||
|
||||
.space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.dot {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.small-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import { Component, EventEmitter, Output } from '@angular/core';
|
||||
import { LicenseService } from '../services/license.service';
|
||||
import { ILicense } from '../utils/license';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
const translations = {
|
||||
active: _('license-info-screen.status.active'),
|
||||
inactive: _('license-info-screen.status.inactive'),
|
||||
} as const;
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-license-select',
|
||||
templateUrl: './license-select.component.html',
|
||||
styleUrls: ['./license-select.component.scss'],
|
||||
})
|
||||
export class LicenseSelectComponent {
|
||||
@Output() readonly valueChanges = new EventEmitter<ILicense>();
|
||||
|
||||
value = this.licenseService.getActiveLicense();
|
||||
|
||||
constructor(readonly licenseService: LicenseService) {}
|
||||
|
||||
getStatus(id) {
|
||||
return id === this.licenseService.activeLicenseId ? translations.active : translations.inactive;
|
||||
}
|
||||
|
||||
licenseChanged($event: ILicense) {
|
||||
this.valueChanges.emit($event);
|
||||
this.licenseService.selectedLicense$.next($event);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { LicenseScreenComponent } from './license-screen/license-screen.component';
|
||||
import { LicenseSelectComponent } from './license-select/license-select.component';
|
||||
import { LicenseChartComponent } from './license-chart/license-chart.component';
|
||||
import { LicenseService } from './services/license.service';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { IqserListingModule } from '@iqser/common-ui';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
import { ComboChartComponent, ComboSeriesVerticalComponent } from './combo-chart';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: LicenseScreenComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LicenseScreenComponent,
|
||||
LicenseSelectComponent,
|
||||
LicenseChartComponent,
|
||||
ComboChartComponent,
|
||||
ComboSeriesVerticalComponent,
|
||||
],
|
||||
imports: [RouterModule.forChild(routes), TranslateModule, MatSelectModule, FormsModule, NgxChartsModule, IqserListingModule],
|
||||
providers: [LicenseService],
|
||||
})
|
||||
export class LicenseModule {}
|
||||
@ -0,0 +1,81 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { GenericService, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { ILicenseReport, ILicenseReportRequest } from '@red/domain';
|
||||
import { BehaviorSubject, firstValueFrom } from 'rxjs';
|
||||
import { ILicense, ILicenses, LICENSE_DATA } from '../utils/license';
|
||||
import { ConfigService } from '../../../../../services/config.service';
|
||||
import dayjs from 'dayjs';
|
||||
import { getStoredReports } from '../utils/functions';
|
||||
|
||||
@Injectable()
|
||||
export class LicenseService extends GenericService<ILicenseReport> {
|
||||
storedReports = getStoredReports();
|
||||
readonly licenseData = this.#licenceData;
|
||||
readonly activeLicenseId = this.licenseData.activeLicense;
|
||||
readonly selectedLicense$ = new BehaviorSubject<ILicense>(this.getActiveLicense());
|
||||
|
||||
constructor(protected readonly _injector: Injector, private readonly _configService: ConfigService) {
|
||||
super(_injector, 'report');
|
||||
}
|
||||
|
||||
get selectedLicense() {
|
||||
return this.selectedLicense$.value;
|
||||
}
|
||||
|
||||
get totalLicensedNumberOfPages() {
|
||||
const processingPagesFeature = this.selectedLicense$.value.features.find(f => f.name === 'processingPages');
|
||||
return Number(processingPagesFeature.value ?? '0');
|
||||
}
|
||||
|
||||
get #licenceData(): ILicenses {
|
||||
return {
|
||||
...LICENSE_DATA,
|
||||
licenses: [
|
||||
...LICENSE_DATA.licenses,
|
||||
{
|
||||
id: 'guid-0',
|
||||
name: this._configService.values.LICENSE_CUSTOMER,
|
||||
product: 'RedactManager',
|
||||
licensedTo: this._configService.values.LICENSE_CUSTOMER,
|
||||
licensedToEmail: this._configService.values.LICENSE_EMAIL,
|
||||
validFrom: dayjs(this._configService.values.LICENSE_START, 'DD-MM-YYYY').toISOString(),
|
||||
validUntil: dayjs(this._configService.values.LICENSE_END, 'DD-MM-YYYY').toISOString(),
|
||||
features: [
|
||||
{
|
||||
name: 'pdftron',
|
||||
type: 'STRING',
|
||||
value: 'base64 encoded pdftron webviewer license key',
|
||||
},
|
||||
{
|
||||
name: 'processingPages',
|
||||
type: 'NUMBER',
|
||||
value: this._configService.values.LICENSE_PAGE_COUNT.toString(),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
getActiveLicense() {
|
||||
return this.licenseData.licenses.find(license => license.id === this.activeLicenseId);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
getReport$(@RequiredParam() body: ILicenseReportRequest, limit?: number, offset?: number) {
|
||||
const queryParams: QueryParam[] = [];
|
||||
if (limit) {
|
||||
queryParams.push({ key: 'limit', value: limit });
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
queryParams.push({ key: 'offset', value: offset });
|
||||
}
|
||||
|
||||
return this._post(body, `${this._defaultModelPath}/license`, queryParams);
|
||||
}
|
||||
|
||||
getReport(body: ILicenseReportRequest, limit?: number, offset?: number) {
|
||||
return firstValueFrom(this.getReport$(body, limit, offset));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { Color, ScaleType } from '@swimlane/ngx-charts';
|
||||
|
||||
export const ComboBarScheme: Color = {
|
||||
name: 'Combo bar scheme',
|
||||
selectable: true,
|
||||
group: ScaleType.Ordinal,
|
||||
domain: ['#0389ec'],
|
||||
};
|
||||
|
||||
export const LineChartScheme: Color = {
|
||||
name: 'Line chart scheme',
|
||||
selectable: true,
|
||||
group: ScaleType.Ordinal,
|
||||
domain: ['#dd4d50', '#5ce594', '#0389ec'],
|
||||
};
|
||||
|
||||
export const LICENSE_STORAGE_KEY = 'redaction-license-reports';
|
||||
@ -0,0 +1,6 @@
|
||||
export interface IDateRange {
|
||||
readonly startMonth: number;
|
||||
readonly startYear: number;
|
||||
readonly endMonth: number;
|
||||
readonly endYear: number;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { IDateRange } from './date-range';
|
||||
import { LICENSE_STORAGE_KEY } from './constants';
|
||||
import { ILicenseReport } from '@red/domain';
|
||||
|
||||
export function toDate(month: number, year: number) {
|
||||
return dayjs(`01-${month}-${year}`, 'DD-M-YYYY').toDate();
|
||||
}
|
||||
|
||||
export function generateDateRanges(month: number, year: number, endMonth: number, endYear: number) {
|
||||
const dates: IDateRange[] = [];
|
||||
|
||||
while (month <= endMonth && year <= endYear) {
|
||||
let nextMonth = month + 1;
|
||||
let nextYear = year;
|
||||
if (nextMonth === 12) {
|
||||
nextMonth = 0;
|
||||
nextYear++;
|
||||
}
|
||||
|
||||
dates.push({ startMonth: month, startYear: year, endMonth: nextMonth, endYear: nextYear });
|
||||
|
||||
year = nextYear;
|
||||
month = nextMonth;
|
||||
}
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
export function getStoredReports() {
|
||||
const rawStoredReports = localStorage.getItem(LICENSE_STORAGE_KEY);
|
||||
return JSON.parse(rawStoredReports ?? '{}') as Record<string, ILicenseReport>;
|
||||
}
|
||||
|
||||
export function isCurrentMonth(month: number, year: number) {
|
||||
const now = dayjs();
|
||||
const currentMonth = now.month() + 1;
|
||||
const currentYear = now.year();
|
||||
|
||||
return month === currentMonth && year === currentYear;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
export interface ILicenseFeature {
|
||||
readonly name: string;
|
||||
readonly type: string;
|
||||
readonly value: string;
|
||||
}
|
||||
|
||||
export interface ILicense {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly product: string;
|
||||
readonly licensedTo: string;
|
||||
readonly licensedToEmail: string;
|
||||
readonly validFrom: string;
|
||||
readonly validUntil: string;
|
||||
readonly features: readonly ILicenseFeature[];
|
||||
}
|
||||
|
||||
export interface ILicenses {
|
||||
readonly activeLicense: string;
|
||||
readonly licenses: readonly ILicense[];
|
||||
}
|
||||
|
||||
export const LICENSE_DATA: ILicenses = {
|
||||
activeLicense: 'guid-0',
|
||||
licenses: [
|
||||
{
|
||||
id: 'guid-1',
|
||||
name: '1 Year comulative (2022)',
|
||||
product: 'RedactManager',
|
||||
licensedTo: 'Customer company name 1',
|
||||
licensedToEmail: 'customer@example.com',
|
||||
validFrom: '2022-01-01T00:00:00.000Z',
|
||||
validUntil: '2022-12-31T23:59:59.999Z',
|
||||
features: [
|
||||
{
|
||||
name: 'pdftron',
|
||||
type: 'STRING',
|
||||
value: 'base64 encoded pdftron webviewer license key',
|
||||
},
|
||||
{
|
||||
name: 'processingPages',
|
||||
type: 'NUMBER',
|
||||
value: '200000',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'guid-2',
|
||||
name: '2 Year comulative (2021)',
|
||||
product: 'RedactManager',
|
||||
licensedTo: 'Customer company name 2',
|
||||
licensedToEmail: 'customer@example.com',
|
||||
validFrom: '2021-01-01T00:00:00.000Z',
|
||||
validUntil: '2021-12-31T23:59:59.999Z',
|
||||
features: [
|
||||
{
|
||||
name: 'pdftron',
|
||||
type: 'STRING',
|
||||
value: 'base64 encoded pdftron webviewer license key',
|
||||
},
|
||||
{
|
||||
name: 'processingPages',
|
||||
type: 'NUMBER',
|
||||
value: '100000',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -1,24 +0,0 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { GenericService, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { ILicenseReport, ILicenseReportRequest } from '@red/domain';
|
||||
|
||||
@Injectable()
|
||||
export class LicenseReportService extends GenericService<ILicenseReport> {
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector, 'report');
|
||||
}
|
||||
|
||||
@Validate()
|
||||
licenseReport(@RequiredParam() body: ILicenseReportRequest, limit?: number, offset?: number) {
|
||||
const queryParams: QueryParam[] = [];
|
||||
if (limit) {
|
||||
queryParams.push({ key: 'limit', value: limit });
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
queryParams.push({ key: 'offset', value: offset });
|
||||
}
|
||||
|
||||
return this._post(body, `${this._defaultModelPath}/license`, queryParams);
|
||||
}
|
||||
}
|
||||
@ -4,13 +4,15 @@ import { SharedModule } from '@shared/shared.module';
|
||||
import { DossierTemplateActionsComponent } from './components/dossier-template-actions/dossier-template-actions.component';
|
||||
import { AddEditEntityComponent } from './components/add-edit-entity/add-edit-entity.component';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
const components = [DossierTemplateActionsComponent, AddEditEntityComponent];
|
||||
|
||||
const modules = [CommonModule, SharedModule];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
exports: [...components],
|
||||
providers: [],
|
||||
imports: [CommonModule, SharedModule, ColorPickerModule],
|
||||
exports: [...components, ...modules],
|
||||
imports: [...modules, RouterModule, ColorPickerModule],
|
||||
})
|
||||
export class SharedAdminModule {}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
[tooltip]="'dossier-details.edit-owner' | translate"
|
||||
class="ml-14"
|
||||
icon="iqser:edit"
|
||||
iqserHelpMode="edit_dossier_owner"
|
||||
iqserHelpMode="dashboard_in_dossier"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</ng-container>
|
||||
@ -43,7 +43,7 @@
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-overview.dossier-details.charts.documents-in-dossier' | translate"
|
||||
direction="row"
|
||||
helpModeKey="filter_for_status"
|
||||
helpModeKey="dashboard_in_dossier"
|
||||
></redaction-simple-doughnut-chart>
|
||||
</div>
|
||||
|
||||
@ -51,11 +51,7 @@
|
||||
<iqser-progress-bar *ngFor="let config of statusConfig" [config]="config"></iqser-progress-bar>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="stats.hasFiles && needsWorkFilters$ | async as filters"
|
||||
class="mt-32 legend pb-32"
|
||||
iqserHelpMode="filter_for_editing_notes"
|
||||
>
|
||||
<div *ngIf="stats.hasFiles && needsWorkFilters$ | async as filters" class="mt-32 legend pb-32" iqserHelpMode="dashboard_in_dossier">
|
||||
<div
|
||||
(click)="filterService.toggleFilter('needsWorkFilters', filter.id)"
|
||||
*ngFor="let filter of filters"
|
||||
|
||||
@ -361,21 +361,21 @@ export class ConfigService {
|
||||
label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-me'),
|
||||
checker: this._assignedToMeChecker,
|
||||
disabled: entities.filter(this._assignedToMeChecker).length === 0,
|
||||
helpModeKey: 'documents_quickfilter',
|
||||
helpModeKey: 'filter_document_list',
|
||||
},
|
||||
{
|
||||
id: 'unassigned',
|
||||
label: this._translateService.instant('dossier-overview.quick-filters.unassigned'),
|
||||
checker: this._unassignedChecker,
|
||||
disabled: entities.filter(this._unassignedChecker).length === 0,
|
||||
helpModeKey: 'documents_quickfilter',
|
||||
helpModeKey: 'filter_document_list',
|
||||
},
|
||||
{
|
||||
id: 'assigned-to-others',
|
||||
label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-others'),
|
||||
checker: this._assignedToOthersChecker,
|
||||
disabled: entities.filter(this._assignedToOthersChecker).length === 0,
|
||||
helpModeKey: 'documents_quickfilter',
|
||||
helpModeKey: 'filter_document_list',
|
||||
},
|
||||
].map(filter => new NestedFilter(filter));
|
||||
}
|
||||
|
||||
@ -83,6 +83,8 @@
|
||||
[type]="iconButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
id="deleteDossier"
|
||||
iqserHelpMode="edit_dossier_delete_dossier"
|
||||
[dialogElement]="true"
|
||||
></iqser-icon-button>
|
||||
|
||||
<iqser-icon-button
|
||||
@ -91,6 +93,8 @@
|
||||
[label]="'dossier-listing.archive.action' | translate"
|
||||
[type]="iconButtonTypes.dark"
|
||||
icon="red:archive"
|
||||
iqserHelpMode="edit_dossier_archive_dossier"
|
||||
[dialogElement]="true"
|
||||
></iqser-icon-button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -40,8 +40,7 @@ export class FileActionsComponent implements OnChanges {
|
||||
@Input() dossier: Dossier;
|
||||
@Input() type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow';
|
||||
@Input() maxWidth: number;
|
||||
@Input() fileActionsHelpModeKey: 'document_features' | 'editor_document_features' = 'document_features';
|
||||
|
||||
@Input() fileActionsHelpModeKey: 'document_features_in_dossier' | 'document_features_in_editor' = 'document_features_in_dossier';
|
||||
toggleTooltip?: string;
|
||||
assignTooltip?: string;
|
||||
buttonType?: CircleButtonType;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltip]="(currentUser.isManager ? 'dossier-listing.edit.action' : 'dossier-listing.dossier-info.action') | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
iqserHelpMode="edit_dossier"
|
||||
iqserHelpMode="edit_dossier_dossier_info"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
|
||||
@ -29,8 +29,6 @@
|
||||
<iqser-circle-button
|
||||
(action)="resize($event)"
|
||||
*ngIf="annotationPermissions.canResizeAnnotation && annotations.length === 1"
|
||||
[iqserHelpMode]="helpModeKey + '_resize'"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.resize.label' | translate"
|
||||
[type]="buttonType"
|
||||
@ -40,23 +38,19 @@
|
||||
<iqser-circle-button
|
||||
(action)="annotationActionsService.changeLegalBasis($event, annotations)"
|
||||
*ngIf="annotationPermissions.canChangeLegalBasis"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.edit-reason.label' | translate"
|
||||
[type]="buttonType"
|
||||
icon="iqser:edit"
|
||||
iqserHelpMode="redaction_edit_reason"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="acceptRecommendation($event)"
|
||||
*ngIf="annotationPermissions.canAcceptRecommendation"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.accept-recommendation.label' | translate"
|
||||
[type]="buttonType"
|
||||
icon="iqser:check"
|
||||
iqserHelpMode="recommendation_accept_or_reject"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
@ -107,7 +101,6 @@
|
||||
<iqser-circle-button
|
||||
(action)="annotationActionsService.recategorizeImages($event, annotations)"
|
||||
*ngIf="annotationPermissions.canRecategorizeImage"
|
||||
[iqserHelpMode]="helpModeKey + '_recategorize'"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.recategorize-image' | translate"
|
||||
[type]="buttonType"
|
||||
@ -126,18 +119,15 @@
|
||||
<iqser-circle-button
|
||||
(action)="annotationActionsService.forceAnnotation($event, annotations)"
|
||||
*ngIf="annotationPermissions.canForceRedaction"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.force-redaction.label' | translate"
|
||||
[type]="buttonType"
|
||||
icon="red:thumb-up"
|
||||
iqserHelpMode="skipped_force_redaction"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="annotationActionsService.forceAnnotation($event, annotations, true)"
|
||||
*ngIf="annotationPermissions.canForceHint"
|
||||
[iqserHelpMode]="helpModeKey + '_force_hint'"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.force-hint.label' | translate"
|
||||
[type]="buttonType"
|
||||
@ -147,7 +137,6 @@
|
||||
<iqser-circle-button
|
||||
(action)="hideAnnotation($event)"
|
||||
*ngIf="isImage && isVisible"
|
||||
[iqserHelpMode]="helpModeKey + '_hide'"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.hide' | translate"
|
||||
[type]="buttonType"
|
||||
@ -166,8 +155,6 @@
|
||||
<iqser-circle-button
|
||||
(action)="removeOrSuggestRemoveAnnotation($event, true)"
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveFromDictionary"
|
||||
[iqserHelpMode]="helpModeKey + '_remove_from_dictionary'"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.remove-annotation.remove-from-dict' | translate"
|
||||
[type]="buttonType"
|
||||
@ -177,8 +164,6 @@
|
||||
<iqser-circle-button
|
||||
(action)="markAsFalsePositive($event)"
|
||||
*ngIf="annotationPermissions.canMarkAsFalsePositive"
|
||||
[iqserHelpMode]="helpModeKey + '_false_positive'"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.remove-annotation.false-positive' | translate"
|
||||
[type]="buttonType"
|
||||
@ -188,8 +173,6 @@
|
||||
<iqser-circle-button
|
||||
(action)="removeOrSuggestRemoveAnnotation($event, false)"
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere"
|
||||
[iqserHelpMode]="helpModeKey + '_remove_only_here'"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'annotation-actions.remove-annotation.only-here' | translate"
|
||||
[type]="buttonType"
|
||||
|
||||
@ -78,22 +78,6 @@ export class AnnotationActionsComponent implements OnChanges {
|
||||
return this.annotations?.length === 1 && this.annotations?.[0].resizing;
|
||||
}
|
||||
|
||||
get scrollableParentView(): ScrollableParentView {
|
||||
return ScrollableParentViews.ANNOTATIONS_LIST;
|
||||
}
|
||||
|
||||
get helpModeKey() {
|
||||
const type = this.annotations[0]?.typeLabel?.split('.')[1];
|
||||
const typeValue = this.annotations[0]?.typeValue;
|
||||
if (type === 'hint' && (typeValue === 'formula' || typeValue === 'image')) {
|
||||
return 'image';
|
||||
}
|
||||
if (type === 'redaction' || type === 'manual-redaction') {
|
||||
return 'redaction';
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this._setPermissions();
|
||||
this._changeRef.markForCheck();
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<span [translateParams]="highlightGroup" [translate]="'highlights'" class="all-caps-label"></span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="(isWritable$ | async) && (multiSelectInactive$ | async)">
|
||||
<div *ngIf="(isWritable$ | async) && (multiSelectInactive$ | async)" iqserHelpMode="highlights">
|
||||
<iqser-circle-button
|
||||
(action)="convertHighlights(highlightGroup)"
|
||||
[size]="28"
|
||||
@ -11,7 +11,6 @@
|
||||
[type]="circleButtonTypes.dark"
|
||||
class="mr-2"
|
||||
icon="red:convert"
|
||||
iqserHelpMode="convert_highlights"
|
||||
tooltipPosition="above"
|
||||
></iqser-circle-button>
|
||||
|
||||
@ -21,7 +20,6 @@
|
||||
[tooltip]="'file-preview.highlights.remove' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
iqserHelpMode="remove_highlights"
|
||||
tooltipPosition="above"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
@ -552,13 +552,19 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
||||
return entry;
|
||||
}
|
||||
|
||||
private _loadDocument(blob: Blob, file: File) {
|
||||
private async _loadDocument(blob: Blob, file: File) {
|
||||
const onError = () => {
|
||||
this._loadingService.stop();
|
||||
this._errorService.set(DocLoadingError);
|
||||
this.stateService.reloadBlob();
|
||||
};
|
||||
this.instance.UI.loadDocument(blob, { filename: file?.filename + '.pdf' ?? 'document.pdf', onError });
|
||||
|
||||
const pdfNet = this.instance.Core.PDFNet;
|
||||
|
||||
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
|
||||
const document = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
|
||||
await document.flattenAnnotations(false);
|
||||
this.instance.UI.loadDocument(document, { filename: file?.filename + '.pdf' ?? 'document.pdf', onError });
|
||||
this._pageRotationService.clearRotationsHideActions();
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
[tooltip]="assignTooltip$ | async"
|
||||
icon="iqser:edit"
|
||||
tooltipPosition="below"
|
||||
iqserHelpMode="assign_reviewer"
|
||||
iqserHelpMode="document_features_in_editor"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
[class.active]="viewModeService.isStandard"
|
||||
[matTooltip]="'file-preview.standard-tooltip' | translate"
|
||||
class="red-tab"
|
||||
iqserHelpMode="standard_view"
|
||||
iqserHelpMode="view"
|
||||
>
|
||||
{{ 'file-preview.standard' | translate }}
|
||||
</button>
|
||||
@ -15,7 +15,7 @@
|
||||
[disabled]="(canSwitchToDeltaView$ | async) === false"
|
||||
[matTooltip]="'file-preview.delta-tooltip' | translate"
|
||||
class="red-tab"
|
||||
iqserHelpMode="delta_view"
|
||||
iqserHelpMode="view"
|
||||
>
|
||||
{{ 'file-preview.delta' | translate }}
|
||||
</button>
|
||||
@ -26,7 +26,7 @@
|
||||
[disabled]="(canSwitchToRedactedView$ | async) === false"
|
||||
[matTooltip]="'file-preview.redacted-tooltip' | translate"
|
||||
class="red-tab"
|
||||
iqserHelpMode="preview_view"
|
||||
iqserHelpMode="view"
|
||||
>
|
||||
{{ 'file-preview.redacted' | translate }}
|
||||
</button>
|
||||
@ -37,7 +37,7 @@
|
||||
[disabled]="(canSwitchToHighlightsView$ | async) === false"
|
||||
[matTooltip]="'file-preview.text-highlights-tooltip' | translate"
|
||||
class="red-tab"
|
||||
iqserHelpMode="highlights_view"
|
||||
iqserHelpMode="view"
|
||||
>
|
||||
{{ 'file-preview.text-highlights' | translate }}
|
||||
</button>
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
<redaction-file-actions
|
||||
[dossier]="dossier"
|
||||
[file]="file"
|
||||
fileActionsHelpModeKey="editor_document_features"
|
||||
fileActionsHelpModeKey="document_features_in_editor"
|
||||
type="file-preview"
|
||||
></redaction-file-actions>
|
||||
|
||||
@ -103,6 +103,8 @@
|
||||
<redaction-annotation-actions
|
||||
[annotations]="[annotation]"
|
||||
[canPerformAnnotationActions]="canPerformAnnotationActions$ | async"
|
||||
[iqserHelpMode]="getActionsHelpModeKey(annotation)"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
></redaction-annotation-actions>
|
||||
</ng-template>
|
||||
|
||||
|
||||
@ -14,6 +14,8 @@ import {
|
||||
OnAttach,
|
||||
OnDetach,
|
||||
processFilters,
|
||||
ScrollableParentView,
|
||||
ScrollableParentViews,
|
||||
shareDistinctLast,
|
||||
} from '@iqser/common-ui';
|
||||
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
|
||||
@ -52,6 +54,17 @@ import { NGXLogger } from 'ngx-logger';
|
||||
import { StampService } from './services/stamp.service';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
const HelpModeKeys = {
|
||||
redaction: 'redaction_text',
|
||||
'manual-redaction': 'redaction_text',
|
||||
recommendation: 'recommendation',
|
||||
skipped: 'skipped',
|
||||
hint: 'hint_text',
|
||||
'hint-ocr': 'hint_picture',
|
||||
'hint-formula': 'picture',
|
||||
'hint-image': 'image',
|
||||
};
|
||||
|
||||
@Component({
|
||||
templateUrl: './file-preview-screen.component.html',
|
||||
styleUrls: ['./file-preview-screen.component.scss'],
|
||||
@ -486,6 +499,19 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
this.handleAnnotationSelected([]);
|
||||
}
|
||||
|
||||
get scrollableParentView(): ScrollableParentView {
|
||||
return ScrollableParentViews.ANNOTATIONS_LIST;
|
||||
}
|
||||
|
||||
getActionsHelpModeKey(annotation: AnnotationWrapper): string {
|
||||
const type = annotation?.typeLabel?.split('.')[1];
|
||||
const typeValue = annotation?.typeValue;
|
||||
if (type === 'hint' && (typeValue === 'ocr' || typeValue === 'formula' || typeValue === 'image')) {
|
||||
return HelpModeKeys[`${type}-${typeValue}`];
|
||||
}
|
||||
return HelpModeKeys[type];
|
||||
}
|
||||
|
||||
private _setExcludedPageStyles() {
|
||||
const file = this._filesMapService.get(this.dossierId, this.fileId);
|
||||
setTimeout(() => {
|
||||
|
||||
@ -501,19 +501,26 @@ export class AnnotationActionsService {
|
||||
}
|
||||
|
||||
private _getFalsePositiveText(annotation: AnnotationWrapper) {
|
||||
if (annotation.canBeMarkedAsFalsePositive) {
|
||||
let text: string;
|
||||
if (annotation.hasTextAfter) {
|
||||
text = getFirstRelevantTextPart(annotation.textAfter, 'FORWARD');
|
||||
return text ? (annotation.value + text).trim() : annotation.value;
|
||||
}
|
||||
if (annotation.hasTextAfter) {
|
||||
text = getFirstRelevantTextPart(annotation.textBefore, 'BACKWARD');
|
||||
return text ? (text + annotation.value).trim() : annotation.value;
|
||||
} else {
|
||||
return annotation.value;
|
||||
}
|
||||
if (!annotation.canBeMarkedAsFalsePositive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (annotation.isRecommendation) {
|
||||
return annotation.value;
|
||||
}
|
||||
|
||||
let text: string;
|
||||
if (annotation.hasTextAfter) {
|
||||
text = getFirstRelevantTextPart(annotation.textAfter, 'FORWARD');
|
||||
return text ? (annotation.value + text).trim() : annotation.value;
|
||||
}
|
||||
|
||||
if (annotation.hasTextBefore) {
|
||||
text = getFirstRelevantTextPart(annotation.textBefore, 'BACKWARD');
|
||||
return text ? (text + annotation.value).trim() : annotation.value;
|
||||
}
|
||||
|
||||
return annotation.value;
|
||||
}
|
||||
|
||||
private _convertPath(path: string): string {
|
||||
|
||||
@ -5,13 +5,13 @@
|
||||
[attr.aria-expanded]="btn.ariaExpanded && btn.ariaExpanded | async"
|
||||
[disabled]="btn.disabled"
|
||||
[icon]="btn.icon"
|
||||
[iqserHelpMode]="helpModeKey"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[showDot]="btn.showDot"
|
||||
[tooltipClass]="btn.tooltipClass"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="btn.tooltip | translate"
|
||||
[type]="btn.buttonType || buttonType"
|
||||
[iqserHelpMode]="helpModeKey"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
></iqser-circle-button>
|
||||
|
||||
<!-- download redacted file-->
|
||||
@ -19,11 +19,11 @@
|
||||
*ngIf="btn.type === 'downloadBtn'"
|
||||
[dossier]="btn.dossier"
|
||||
[files]="btn.files"
|
||||
[iqserHelpMode]="helpModeKey"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
[tooltipClass]="btn.tooltipClass"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="buttonType"
|
||||
[iqserHelpMode]="helpModeKey"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
></redaction-file-download-btn>
|
||||
|
||||
<!-- exclude from redaction -->
|
||||
@ -33,10 +33,10 @@
|
||||
(click)="$event.stopPropagation()"
|
||||
[checked]="btn.checked"
|
||||
[disabled]="btn.disabled"
|
||||
[iqserHelpMode]="helpModeKey"
|
||||
[matTooltipPosition]="tooltipPosition"
|
||||
[matTooltip]="btn.tooltip | translate"
|
||||
[ngClass]="btn.class"
|
||||
[iqserHelpMode]="helpModeKey"
|
||||
[scrollableParentView]="scrollableParentView"
|
||||
color="primary"
|
||||
></mat-slide-toggle>
|
||||
|
||||
@ -17,7 +17,7 @@ export class ExpandableFileActionsComponent implements OnChanges {
|
||||
@Input() actions: Action[];
|
||||
@Input() buttonType: CircleButtonType;
|
||||
@Input() tooltipPosition: IqserTooltipPosition;
|
||||
@Input() helpModeKey: 'document_features' | 'editor_document_features';
|
||||
@Input() helpModeKey: 'document_features_in_dossier' | 'document_features_in_editor';
|
||||
|
||||
displayedButtons: Action[];
|
||||
hiddenButtons: Action[];
|
||||
@ -30,7 +30,7 @@ export class ExpandableFileActionsComponent implements OnChanges {
|
||||
) {}
|
||||
|
||||
get scrollableParentView(): ScrollableParentView {
|
||||
return this.helpModeKey === 'document_features' ? ScrollableParentViews.VIRTUAL_SCROLL : undefined;
|
||||
return this.helpModeKey === 'document_features_in_dossier' ? ScrollableParentViews.VIRTUAL_SCROLL : undefined;
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
|
||||
@ -26,7 +26,7 @@ export class SimpleDoughnutChartComponent implements OnChanges, OnInit {
|
||||
@Input() totalType: 'sum' | 'count' | 'simpleLabel' = 'sum';
|
||||
@Input() counterText: string;
|
||||
@Input() filterKey = 'statusFilters';
|
||||
@Input() helpModeKey: 'filter_for_status';
|
||||
@Input() helpModeKey: 'dashboard_in_dossier';
|
||||
filtersEnabled: boolean;
|
||||
|
||||
chartData: any[] = [];
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { SuperType, SuperTypes } from '@models/file/super-types';
|
||||
|
||||
export const annotationTypesTranslations: { [key in SuperType]: string } = {
|
||||
export const SuggestionAddFalsePositive = 'suggestion-add-false-positive' as const;
|
||||
|
||||
type TranslationKey = SuperType & typeof SuggestionAddFalsePositive;
|
||||
|
||||
export const annotationTypesTranslations: Record<TranslationKey, string> = {
|
||||
[SuperTypes.TextHighlight]: _('annotation-type.text-highlight'),
|
||||
[SuperTypes.DeclinedSuggestion]: _('annotation-type.declined-suggestion'),
|
||||
[SuperTypes.Hint]: _('annotation-type.hint'),
|
||||
@ -19,4 +23,5 @@ export const annotationTypesTranslations: { [key in SuperType]: string } = {
|
||||
[SuperTypes.SuggestionRemove]: _('annotation-type.suggestion-remove'),
|
||||
[SuperTypes.SuggestionRemoveDictionary]: _('annotation-type.suggestion-remove-dictionary'),
|
||||
[SuperTypes.SuggestionResize]: _('annotation-type.suggestion-resize'),
|
||||
[SuggestionAddFalsePositive]: _('annotation-type.suggestion-add-false-positive'),
|
||||
} as const;
|
||||
|
||||
@ -1,30 +1,12 @@
|
||||
{
|
||||
"assign_reviewer": {
|
||||
"en": "/en/index-en.html?contextId=assign_reviewer",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"bulk_select_annotations": {
|
||||
"en": "/en/index-en.html?contextId=bulk_select_annotations",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"delta_view": {
|
||||
"en": "/en/index-en.html?contextId=delta_view",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"document_features": {
|
||||
"en": "/en/index-en.html?contextId=document_features",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"edit_dossier": {
|
||||
"en": "/en/index-en.html?contextId=edit_dossier",
|
||||
"document_features_in_dossier": {
|
||||
"en": "/en/index-en.html?contextId=document_features_in_dossier",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -41,14 +23,8 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"edit_dossier_owner": {
|
||||
"en": "/en/index-en.html?contextId=edit_dossier_owner",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"redaction_edit_reason": {
|
||||
"en": "/en/index-en.html?contextId=redaction_edit_reason",
|
||||
"dashboard_in_dossier": {
|
||||
"en": "/en/index-en.html?contextId=dashboard_in_dossier",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -65,12 +41,6 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"filter_for_editing_notes": {
|
||||
"en": "/en/index-en.html?contextId=filter_for_editing_notes",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"filter_for_status": {
|
||||
"en": "/en/index-en.html?contextId=filter_for_status",
|
||||
"de": "",
|
||||
@ -101,104 +71,8 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"preview_view": {
|
||||
"en": "/en/index-en.html?contextId=delta_view",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"highlights_view": {
|
||||
"en": "/en/index-en.html?contextId=highlights_view",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"convert_highlights": {
|
||||
"en": "/en/index-en.html?contextId=convert_highlights",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"remove_highlights": {
|
||||
"en": "/en/index-en.html?contextId=remove_highlights",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"recommendation_accept_or_reject": {
|
||||
"en": "/en/index-en.html?contextId=recommendation_accept_or_reject",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"redaction_false_positive": {
|
||||
"en": "/en/index-en.html?contextId=redaction_false_positive",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"recommendation_false_positive": {
|
||||
"en": "/en/index-en.html?contextId=recommendation_false_positive",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"skipped_remove_from_dictionary": {
|
||||
"en": "/en/index-en.html?contextId=skipped_remove_from_dictionary",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_remove_from_dictionary": {
|
||||
"en": "/en/index-en.html?contextId=hint_remove_from_dictionary",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"recommendation_remove_from_dictionary": {
|
||||
"en": "/en/index-en.html?contextId=recommendation_remove_from_dictionary",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"redaction_remove_only_here": {
|
||||
"en": "/en/index-en.html?contextId=redaction_remove_only_here",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_remove_only_here": {
|
||||
"en": "/en/index-en.html?contextId=hint_remove_only_here",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_recategorize": {
|
||||
"en": "/en/index-en.html?contextId=hint_recategorize",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_hide": {
|
||||
"en": "/en/index-en.html?contextId=hint_hide",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_force_hint": {
|
||||
"en": "/en/index-en.html?contextId=hint_force_hint",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"redaction_recategorize": {
|
||||
"en": "/en/index-en.html?contextId=redaction_recategorize",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"redaction_hide": {
|
||||
"en": "/en/index-en.html?contextId=redaction_hide",
|
||||
"view": {
|
||||
"en": "/en/index-en.html?contextId=view",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -215,12 +89,6 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"standard_view": {
|
||||
"en": "/en/index-en.html?contextId=standard_view",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"workload_filter": {
|
||||
"en": "/en/index-en.html?contextId=workload_filter",
|
||||
"de": "",
|
||||
@ -233,18 +101,6 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"delete_document_filter": {
|
||||
"en": "/en/index-en.html?contextId=delete_document_filter",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"delete_dossier_filter": {
|
||||
"en": "",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"edit_dossier_in_dossier": {
|
||||
"en": "/en/index-en.html?contextId=edit_dossier_in_dossier",
|
||||
"de": "",
|
||||
@ -257,32 +113,8 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"recommendation_resize": {
|
||||
"en": "/en/index-en.html?contextId=recommendation_resize",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_resize": {
|
||||
"en": "/en/index-en.html?contextId=hint_resize",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"skipped_force_redaction": {
|
||||
"en": "/en/index-en.html?contextId=skipped_force_redaction",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"editor_document_features": {
|
||||
"en": "/en/index-en.html?contextId=editor_document_features",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"documents_quickfilter": {
|
||||
"en": "/en/index-en.html?contextId=documents_quickfilter",
|
||||
"document_features_in_editor": {
|
||||
"en": "/en/index-en.html?contextId=document_features_in_editor",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -305,14 +137,8 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"dossiers_scroll_up_button": {
|
||||
"en": "/en/index-en.html?contextId=dossiers_scroll_up_and_down",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"dossiers_scroll_down_button": {
|
||||
"en": "/en/index-en.html?contextId=dossiers_scroll_up_and_down",
|
||||
"scroll_dossier_list": {
|
||||
"en": "/en/index-en.html?contextId=scroll_dossier_list",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -335,6 +161,18 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"edit_dossier_delete_dossier": {
|
||||
"en": "/en/index-en.html?contextId=edit_dossier_delete_dossier",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"edit_dossier_archive_dossier": {
|
||||
"en": "/en/index-en.html?contextId=edit_dossier_archive_dossier",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"edit_dossier_download_package": {
|
||||
"en": "/en/index-en.html?contextId=edit_dossier_download_package",
|
||||
"de": "",
|
||||
@ -389,26 +227,44 @@
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"redaction_remove_from_dictionary": {
|
||||
"en": "/en/index-en.html?contextId=redaction_remove_from_dictionary",
|
||||
"redaction_text": {
|
||||
"en": "/en/index-en.html?contextId=redaction_text",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"skipped_resize": {
|
||||
"en": "/en/index-en.html?contextId=skipped_resize_redaction",
|
||||
"recommendation": {
|
||||
"en": "/en/index-en.html?contextId=recommendation",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"skipped_recategorize": {
|
||||
"en": "/en/index-en.html?contextId=skipped_recategorize_redaction",
|
||||
"skipped": {
|
||||
"en": "/en/index-en.html?contextId=skipped",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"skipped_hide": {
|
||||
"en": "/en/index-en.html?contextId=skipped_hide",
|
||||
"hint_text": {
|
||||
"en": "/en/index-en.html?contextId=hint_text",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"hint_picture": {
|
||||
"en": "/en/index-en.html?contextId=hint_picture",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"picture": {
|
||||
"en": "/en/index-en.html?contextId=picture",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"image": {
|
||||
"en": "/en/index-en.html?contextId=image",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"skipped": "Übersprungen",
|
||||
"suggestion-add": "Vorschlag für Schwärzung",
|
||||
"suggestion-add-dictionary": "Vorschlag für neuen Wörterbucheintrag",
|
||||
"suggestion-add-false-positive": "",
|
||||
"suggestion-change-legal-basis": "Vorschlag für Änderung der Rechtsgrundlage",
|
||||
"suggestion-force-hint": "",
|
||||
"suggestion-force-redaction": "Vorschlag für erzwungene Schwärzung",
|
||||
@ -1549,11 +1550,16 @@
|
||||
},
|
||||
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
|
||||
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
|
||||
"license-title": "",
|
||||
"licensed-page-count": "Anzahl der lizenzierten Seiten",
|
||||
"licensed-to": "Lizenziert für",
|
||||
"licensing-details": "Lizenzdetails",
|
||||
"licensing-period": "Laufzeit der Lizenz",
|
||||
"ocr-analyzed-pages": "Mit OCR konvertierte Seiten",
|
||||
"status": {
|
||||
"active": "Aktiv",
|
||||
"inactive": ""
|
||||
},
|
||||
"total-analyzed": "Seit {date} insgesamt analysierte Seiten",
|
||||
"unlicensed-analyzed": "Über Lizenz hinaus analysierte Seiten",
|
||||
"usage-details": "Nutzungsdetails"
|
||||
|
||||
@ -344,6 +344,7 @@
|
||||
"skipped": "Skipped",
|
||||
"suggestion-add": "Suggested redaction",
|
||||
"suggestion-add-dictionary": "Suggested dictionary add",
|
||||
"suggestion-add-false-positive": "Suggested add to false positive",
|
||||
"suggestion-change-legal-basis": "Suggested change legal basis",
|
||||
"suggestion-force-hint": "Suggestion force hint",
|
||||
"suggestion-force-redaction": "Suggestion force redaction",
|
||||
@ -1549,11 +1550,16 @@
|
||||
},
|
||||
"end-user-license-text": "The use of this product is subject to the terms of the Redaction End User Agreement, unless otherwise specified therein.",
|
||||
"end-user-license-title": "End User License Agreement",
|
||||
"license-title": "License Title",
|
||||
"licensed-page-count": "Number of licensed pages",
|
||||
"licensed-to": "Licensed to",
|
||||
"licensing-details": "Licensing Details",
|
||||
"licensing-period": "Licensing Period",
|
||||
"ocr-analyzed-pages": "OCR Analyzed Pages",
|
||||
"status": {
|
||||
"active": "Active",
|
||||
"inactive": "Inactive"
|
||||
},
|
||||
"total-analyzed": "Total Analyzed Pages Since {date}",
|
||||
"unlicensed-analyzed": "Unlicensed Analyzed Pages",
|
||||
"usage-details": "Usage Details"
|
||||
|
||||
@ -98,3 +98,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ server {
|
||||
root /usr/share/nginx/html;
|
||||
# SSL stuff for cloudflare proxy-ing - ignores SSL certificate and uses SNI
|
||||
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' data: 'unsafe-eval'; script-src-elem 'self' data: blob: 'unsafe-inline'; script-src-attr 'self' data:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:";
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' blob: data: 'unsafe-eval' 'unsafe-inline'; script-src-elem 'self' data: blob: 'unsafe-inline'; script-src-attr 'self' data:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:";
|
||||
|
||||
proxy_ssl_verify off;
|
||||
proxy_read_timeout 1m;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "redaction",
|
||||
"version": "3.451.0",
|
||||
"version": "3.464.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@ -11,31 +11,33 @@
|
||||
.publication-icon {
|
||||
background-color: variables.$red-1;
|
||||
}
|
||||
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.portal-contents {
|
||||
.featured-content-label {
|
||||
margin-top: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.featured-content {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 0;
|
||||
|
||||
.inner {
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 24px;
|
||||
|
||||
&::before {
|
||||
content: none;
|
||||
}
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.publication-contents {
|
||||
@include mixin.card;
|
||||
}
|
||||
.publication-contents {
|
||||
@include mixin.card;
|
||||
width: 250px;
|
||||
margin: 0 15px !important;
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.portal-contents .inner {
|
||||
grid-template-columns: 1fr;
|
||||
li a {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@ -59,6 +59,7 @@
|
||||
}
|
||||
.portal-single-publication {
|
||||
background-color: transparent;
|
||||
width: 280px;
|
||||
}
|
||||
.portal-single-publication > a {
|
||||
border-radius: 4px;
|
||||
@ -67,78 +68,78 @@
|
||||
background-color: #dd4d50;
|
||||
}
|
||||
|
||||
.portal-contents {
|
||||
.featured-content-label {
|
||||
margin-top: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.featured-content {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.portal-contents .inner {
|
||||
.featured-content .inner {
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 24px;
|
||||
justify-content: center;
|
||||
}
|
||||
.portal-contents .inner::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.publication-contents {
|
||||
.featured-content .publication-contents {
|
||||
padding: 24px 40px;
|
||||
border: 1px solid #e2e4e9;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
width: 250px;
|
||||
margin: 0 15px !important;
|
||||
}
|
||||
.publication-contents h4.featured-title,
|
||||
.publication-contents .section-toc-title {
|
||||
.featured-content .publication-contents h4.featured-title,
|
||||
.featured-content .publication-contents .section-toc-title {
|
||||
margin: 0;
|
||||
}
|
||||
.publication-contents h4.featured-title a,
|
||||
.publication-contents .section-toc-title a {
|
||||
.featured-content .publication-contents h4.featured-title a,
|
||||
.featured-content .publication-contents .section-toc-title a {
|
||||
color: #283241;
|
||||
}
|
||||
.publication-contents h4.featured-title a:hover,
|
||||
.publication-contents .section-toc-title a:hover {
|
||||
.featured-content .publication-contents h4.featured-title a:hover,
|
||||
.featured-content .publication-contents .section-toc-title a:hover {
|
||||
color: #283241;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.publication-contents .section-toc-title {
|
||||
.featured-content .publication-contents .section-toc-title {
|
||||
font-size: 28px;
|
||||
font-weight: 300;
|
||||
line-height: 36px;
|
||||
}
|
||||
.publication-contents ul {
|
||||
.featured-content .publication-contents ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.publication-contents li {
|
||||
.featured-content .publication-contents li {
|
||||
margin: 4px 0;
|
||||
}
|
||||
.publication-contents li:first-child {
|
||||
.featured-content .publication-contents li:first-child {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.publication-contents li:last-child {
|
||||
.featured-content .publication-contents li:last-child {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.publication-contents li a {
|
||||
.featured-content .publication-contents li a {
|
||||
color: #dd4d50;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
.publication-contents li a:hover {
|
||||
.featured-content .publication-contents li a:hover {
|
||||
color: #dd4d50;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.publication-contents h4 span,
|
||||
.publication-contents li::before {
|
||||
.featured-content .publication-contents h4 span,
|
||||
.featured-content .publication-contents li::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.portal-contents .inner {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.featured-content .publication-contents li a {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/* Einleitung */
|
||||
.cat-panel-1:before {
|
||||
content: '\f277';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user