added new box for rules logger poc
This commit is contained in:
parent
df64a73adc
commit
d4435752ac
@ -1,3 +1,6 @@
|
|||||||
|
<div class="rules-screen-container">
|
||||||
|
<!-- Main content area -->
|
||||||
|
<div class="main-content">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<div [translate]="translations[type()]['title']" class="heading-l"></div>
|
<div [translate]="translations[type()]['title']" class="heading-l"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -7,13 +10,17 @@
|
|||||||
|
|
||||||
<div [class.collapsed]="collapsed()" class="right-container flex-column">
|
<div [class.collapsed]="collapsed()" class="right-container flex-column">
|
||||||
<div class="collapsed-wrapper">
|
<div class="collapsed-wrapper">
|
||||||
<ng-container *ngTemplateOutlet="collapsible; context: { action: 'expand', tooltip: ('copilot' | translate) }"></ng-container>
|
<ng-container
|
||||||
|
*ngTemplateOutlet="collapsible; context: { action: 'expand', tooltip: ('copilot' | translate) }"
|
||||||
|
></ng-container>
|
||||||
<div class="all-caps-label" translate="dossier-details.title"></div>
|
<div class="all-caps-label" translate="dossier-details.title"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="header-wrapper flex mt-8">
|
<div class="header-wrapper flex mt-8">
|
||||||
<div class="heading-xl flex-1" id="dossierDetailsDossierName">Copilot</div>
|
<div class="heading-xl flex-1" id="dossierDetailsDossierName">Copilot</div>
|
||||||
<ng-container *ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: ('copilot' | translate) }"></ng-container>
|
<ng-container
|
||||||
|
*ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: ('copilot' | translate) }"
|
||||||
|
></ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-24">
|
<div class="mt-24">
|
||||||
@ -85,5 +92,36 @@
|
|||||||
<div (click)="revert()" [translate]="translations[type()]['revert-changes']" class="all-caps-label cancel"></div>
|
<div (click)="revert()" [translate]="translations[type()]['revert-changes']" class="all-caps-label cancel"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<redaction-rules-logger></redaction-rules-logger>
|
<div class="rules-logger" [class.collapsed]="isLogCollapsed">
|
||||||
|
<div class="logger-header" (click)="toggleLogCollapse()">
|
||||||
|
<h3>Rules Log</h3>
|
||||||
|
<button class="collapse-button">
|
||||||
|
<!--todo: add proper icon -->
|
||||||
|
<mat-icon>{{ isLogCollapsed ? 'x' : 'x' }}</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="logger-messages" *ngIf="!isLogCollapsed">
|
||||||
|
<div *ngFor="let msg of messages" class="log-entry">
|
||||||
|
<div class="log-header">
|
||||||
|
<span class="log-level">{{ msg.logLevel }}</span>
|
||||||
|
<span class="log-time">{{ msg.parsedTimeStamp | date: 'short' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="log-message">
|
||||||
|
{{ msg.message }}
|
||||||
|
</div>
|
||||||
|
<div class="log-details">
|
||||||
|
<!--todo: add translation -->
|
||||||
|
<div><strong>Tenant ID:</strong> {{ msg.tenantId }}</div>
|
||||||
|
<div><strong>File ID:</strong> {{ msg.fileId }}</div>
|
||||||
|
<div><strong>Dossier ID:</strong> {{ msg.dossierId }}</div>
|
||||||
|
<div><strong>Rule Version:</strong> {{ msg.ruleVersion }}</div>
|
||||||
|
<div><strong>Analysis Number:</strong> {{ msg.analysisNumber }}</div>
|
||||||
|
<div><strong>Timestamp:</strong> {{ msg.parsedTimeStamp }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@ -96,3 +96,94 @@ ngx-monaco-editor {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rules-screen-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh; /* Adjust based on your layout */
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rules-logger {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: max-height 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
background-color: #fafafa;
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
max-height: 50px; /* Height of the header when collapsed */
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.collapsed) {
|
||||||
|
max-height: 300px; /* Maximum height when expanded */
|
||||||
|
}
|
||||||
|
|
||||||
|
.logger-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logger-messages {
|
||||||
|
overflow-y: auto;
|
||||||
|
height: calc(100% - 50px); /* Subtract header height */
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.log-entry {
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
|
||||||
|
.log-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.log-level {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-time {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-message {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-details {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #666;
|
||||||
|
|
||||||
|
div {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -24,7 +24,8 @@ import { rulesScreenTranslations } from '../../../translations/rules-screen-tran
|
|||||||
import ICodeEditor = monaco.editor.ICodeEditor;
|
import ICodeEditor = monaco.editor.ICodeEditor;
|
||||||
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
||||||
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
|
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
|
||||||
import { RulesLoggerComponent } from '@components/rules-logger/rules-logger.component';
|
import { RulesLoggerService } from '@services/rules-logger.service';
|
||||||
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||||
|
|
||||||
interface SyntaxError {
|
interface SyntaxError {
|
||||||
line: number;
|
line: number;
|
||||||
@ -39,6 +40,19 @@ interface UploadResponse {
|
|||||||
deprecatedWarnings: SyntaxError[];
|
deprecatedWarnings: SyntaxError[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RulesLogMessage {
|
||||||
|
tenantId: string;
|
||||||
|
fileId: string;
|
||||||
|
dossierId: string;
|
||||||
|
dossierTemplateId: string;
|
||||||
|
ruleVersion: number;
|
||||||
|
analysisNumber: number;
|
||||||
|
timeStamp: string;
|
||||||
|
logLevel: string;
|
||||||
|
message: string;
|
||||||
|
parsedTimeStamp?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
const RULE_VALIDATION_TIMEOUT = 2000;
|
const RULE_VALIDATION_TIMEOUT = 2000;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -61,7 +75,7 @@ const RULE_VALIDATION_TIMEOUT = 2000;
|
|||||||
NamePipe,
|
NamePipe,
|
||||||
NgForOf,
|
NgForOf,
|
||||||
MatTooltip,
|
MatTooltip,
|
||||||
RulesLoggerComponent,
|
ScrollingModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export default class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
|
export default class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
|
||||||
@ -71,6 +85,7 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
|
|||||||
readonly #errors = signal<SyntaxError[]>([]);
|
readonly #errors = signal<SyntaxError[]>([]);
|
||||||
#ruleValidationTimeout: number = null;
|
#ruleValidationTimeout: number = null;
|
||||||
readonly #copilotService = inject(CopilotService);
|
readonly #copilotService = inject(CopilotService);
|
||||||
|
readonly #rulesLoggerService = inject(RulesLoggerService);
|
||||||
readonly #currentUser = getCurrentUser();
|
readonly #currentUser = getCurrentUser();
|
||||||
protected readonly collapsed = signal(true);
|
protected readonly collapsed = signal(true);
|
||||||
protected readonly IqserTooltipPositions = IqserTooltipPositions;
|
protected readonly IqserTooltipPositions = IqserTooltipPositions;
|
||||||
@ -88,10 +103,12 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
|
|||||||
initialLines: string[] = [];
|
initialLines: string[] = [];
|
||||||
currentLines: string[] = [];
|
currentLines: string[] = [];
|
||||||
isLeaving = false;
|
isLeaving = false;
|
||||||
|
messages: RulesLogMessage[] = [];
|
||||||
readonly type = input.required<IRules['ruleFileType']>();
|
readonly type = input.required<IRules['ruleFileType']>();
|
||||||
readonly numberOfErrors = computed(() => this.#errors().filter(e => !e.warning).length);
|
readonly numberOfErrors = computed(() => this.#errors().filter(e => !e.warning).length);
|
||||||
readonly numberOfWarnings = computed(() => this.#errors().filter(e => e.warning).length);
|
readonly numberOfWarnings = computed(() => this.#errors().filter(e => e.warning).length);
|
||||||
readonly responses$ = new BehaviorSubject<{ text: string; date: string }[]>([]);
|
readonly responses$ = new BehaviorSubject<{ text: string; date: string }[]>([]);
|
||||||
|
isLogCollapsed = true;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly permissionsService: PermissionsService,
|
readonly permissionsService: PermissionsService,
|
||||||
@ -114,6 +131,15 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
|
|||||||
destination: '/app/rules-copilot',
|
destination: '/app/rules-copilot',
|
||||||
body: JSON.stringify({ prompts: ['manageradmin'] }),
|
body: JSON.stringify({ prompts: ['manageradmin'] }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.#rulesLoggerService
|
||||||
|
.listen<RulesLogMessage>('/topic/' + tenant + '/rule-log-events')
|
||||||
|
.pipe(takeUntilDestroyed())
|
||||||
|
.subscribe(message => {
|
||||||
|
message.parsedTimeStamp = this.parseTimestamp(message.timeStamp);
|
||||||
|
this.messages.push(message);
|
||||||
|
this._changeDetectorRef.detectChanges();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
set isLeavingPage(isLeaving: boolean) {
|
set isLeavingPage(isLeaving: boolean) {
|
||||||
@ -352,4 +378,23 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
|
|||||||
() => this._loadingService.stop(),
|
() => this._loadingService.stop(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseTimestamp(timestamp: string): Date {
|
||||||
|
let adjustedTimestamp = timestamp.replace('Z', '');
|
||||||
|
|
||||||
|
const dotIndex = adjustedTimestamp.indexOf('.');
|
||||||
|
if (dotIndex !== -1) {
|
||||||
|
adjustedTimestamp = adjustedTimestamp.substring(0, dotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Date(adjustedTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
trackByMessageId(index: number, msg: RulesLogMessage): string {
|
||||||
|
return msg.timeStamp; // Assuming timeStamp is unique
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleLogCollapse() {
|
||||||
|
this.isLogCollapsed = !this.isLogCollapsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,3 @@
|
|||||||
></ngx-monaco-editor>
|
></ngx-monaco-editor>
|
||||||
|
|
||||||
<ngx-monaco-diff-editor (init)="onDiffEditorInit($event)" *ngIf="showDiffEditor" [options]="editorOptions"></ngx-monaco-diff-editor>
|
<ngx-monaco-diff-editor (init)="onDiffEditorInit($event)" *ngIf="showDiffEditor" [options]="editorOptions"></ngx-monaco-diff-editor>
|
||||||
|
|
||||||
<redaction-rules-logger></redaction-rules-logger>
|
|
||||||
|
|||||||
@ -7,14 +7,13 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|||||||
import { List, OnChange } from '@iqser/common-ui/lib/utils';
|
import { List, OnChange } from '@iqser/common-ui/lib/utils';
|
||||||
import { MonacoEditorModule, MonacoStandaloneCodeEditor, MonacoStandaloneDiffEditor } from '@materia-ui/ngx-monaco-editor';
|
import { MonacoEditorModule, MonacoStandaloneCodeEditor, MonacoStandaloneDiffEditor } from '@materia-ui/ngx-monaco-editor';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { NgIf } from '@angular/common';
|
|
||||||
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
|
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
|
||||||
import IDiffEditor = monaco.editor.IDiffEditor;
|
import IDiffEditor = monaco.editor.IDiffEditor;
|
||||||
import ICodeEditor = monaco.editor.ICodeEditor;
|
import ICodeEditor = monaco.editor.ICodeEditor;
|
||||||
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
||||||
import ILineChange = monaco.editor.ILineChange;
|
import ILineChange = monaco.editor.ILineChange;
|
||||||
import IEditorMouseEvent = monaco.editor.IEditorMouseEvent;
|
import IEditorMouseEvent = monaco.editor.IEditorMouseEvent;
|
||||||
import { RulesLoggerComponent } from '@components/rules-logger/rules-logger.component';
|
import { NgIf } from '@angular/common';
|
||||||
|
|
||||||
const MIN_WORD_LENGTH = 2;
|
const MIN_WORD_LENGTH = 2;
|
||||||
const lineChangeToDecoration = ({ originalEndLineNumber, originalStartLineNumber }: ILineChange) =>
|
const lineChangeToDecoration = ({ originalEndLineNumber, originalStartLineNumber }: ILineChange) =>
|
||||||
@ -33,7 +32,7 @@ const notZero = (lineChange: ILineChange) => lineChange.originalEndLineNumber !=
|
|||||||
templateUrl: './editor.component.html',
|
templateUrl: './editor.component.html',
|
||||||
styleUrls: ['./editor.component.scss'],
|
styleUrls: ['./editor.component.scss'],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [MonacoEditorModule, FormsModule, NgIf, RulesLoggerComponent],
|
imports: [MonacoEditorModule, FormsModule, NgIf],
|
||||||
})
|
})
|
||||||
export class EditorComponent implements OnInit, OnChanges {
|
export class EditorComponent implements OnInit, OnChanges {
|
||||||
@Input() showDiffEditor = false;
|
@Input() showDiffEditor = false;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user