Skip to content

Commit

Permalink
feat(simulator-ui): code highlighting in message payloads
Browse files Browse the repository at this point in the history
  • Loading branch information
bbortt committed Aug 22, 2024
1 parent 15afe9c commit 91cb6d1
Show file tree
Hide file tree
Showing 15 changed files with 3,938 additions and 3,741 deletions.
7,397 changes: 3,700 additions & 3,697 deletions simulator-ui/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion simulator-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
"bootswatch": "5.3.3",
"dayjs": "1.11.12",
"mdb-angular-ui-kit": "^6.1.0",
"ngx-highlightjs": "^12.0.0",
"ngx-infinite-scroll": "18.0.0",
"prettier": "^3.3.3",
"rxjs": "7.8.1",
"tslib": "2.6.3",
"zone.js": "~0.14.10"
Expand Down Expand Up @@ -90,7 +92,6 @@
"jest-preset-angular": "14.2.2",
"jest-sonar": "0.2.16",
"merge-jsons-webpack-plugin": "2.0.1",
"prettier": "3.3.3",
"prettier-plugin-packagejson": "2.5.1",
"rimraf": "6.0.1",
"swagger-ui-dist": "5.17.14",
Expand Down
13 changes: 9 additions & 4 deletions simulator-ui/src/main/webapp/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { registerLocaleData } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { provideHttpClient } from '@angular/common/http';
import locale from '@angular/common/locales/en';
import { NgModule, LOCALE_ID } from '@angular/core';
import { LOCALE_ID, NgModule } from '@angular/core';
import { BrowserModule, Title } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TitleStrategy } from '@angular/router';
Expand All @@ -12,14 +12,16 @@ import { FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { NgbDateAdapter, NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap';

import dayjs from 'dayjs/esm';
import './config/dayjs';

import { HIGHLIGHT_OPTIONS, provideHighlightOptions } from 'ngx-highlightjs';

import { ApplicationConfigService } from 'app/core/config/application-config.service';
import { httpInterceptorProviders } from 'app/core/interceptor';
import { TranslationModule } from 'app/shared/language/translation.module';

import { AppPageTitleStrategy } from './app-page-title-strategy';
import { AppRoutingModule } from './app-routing.module';
import './config/dayjs';
import { NgbDateDayjsAdapter } from './config/datepicker-adapter';
import { fontAwesomeIcons } from './config/font-awesome-icons';
import MainComponent from './layouts/main/main.component';
Expand All @@ -35,16 +37,19 @@ import MainModule from './layouts/main/main.module';
AppRoutingModule,
// Set this to true to enable service worker (PWA)
ServiceWorkerModule.register('ngsw-worker.js', { enabled: false }),
HttpClientModule,
MainModule,
TranslationModule,
],
providers: [
provideHttpClient(),
Title,
{ provide: LOCALE_ID, useValue: 'en' },
{ provide: NgbDateAdapter, useClass: NgbDateDayjsAdapter },
httpInterceptorProviders,
{ provide: TitleStrategy, useClass: AppPageTitleStrategy },
provideHighlightOptions({
fullLibraryLoader: () => import('highlight.js'),
}),
],
bootstrap: [MainComponent],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ <h2 data-test="messageDetailsHeading"><span jhiTranslate="citrusSimulatorApp.mes
</dd>
<dt><span jhiTranslate="citrusSimulatorApp.message.payload">Payload</span></dt>
<dd>
<span data-test="messageDetailPayload">{{ message.payload }}</span>
<span data-test="messageDetailPayload">
<pre *ngIf="message.payload"><code [highlightAuto]="message.payload"></code></pre>
</span>
</dd>
<dt><span jhiTranslate="citrusSimulatorApp.message.citrusMessageId">Citrus Message Id</span></dt>
<dd>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pre {
padding: 0;
margin: 0;

code {
padding: 0;
margin: 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { Component, Input } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';

import { HighlightAuto } from 'ngx-highlightjs';

import { IMessage } from 'app/entities/message/message.model';
import MessageHeaderTableComponent from 'app/entities/message-header/list/message-header-table.component';

import SharedModule from 'app/shared/shared.module';
import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date';

import { IMessage } from '../message.model';
import MessageHeaderTableComponent from '../../message-header/list/message-header-table.component';

@Component({
standalone: true,
selector: 'app-message-detail',
templateUrl: './message-detail.component.html',
styleUrls: ['./message-detail.component.scss'],
imports: [
SharedModule,
RouterModule,
DurationPipe,
FormatMediumDatetimePipe,
FormatMediumDatePipe,
MessageHeaderTableComponent,
MessageHeaderTableComponent,
HighlightAuto,
],
})
export class MessageDetailComponent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ <h2 id="page-heading" data-test="MessageHeading">
<a [routerLink]="['/message', message.messageId, 'view']" data-test="messageEntityMessageId">{{ message.messageId }}</a>
</td>
<td data-test="messageEntityMessageDirection">{{ message.direction }}</td>
<td data-test="messageEntityMessagePayload">{{ message.payload }}</td>
<td data-test="messageEntityMessagePayload"><code *ngIf="message.payload" [highlightAuto]="message.payload"></code></td>
<td data-test="messageEntityMessageCitrusMessage">{{ message.citrusMessageId }}</td>
<td>
<div *ngIf="message.scenarioExecutionId">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/r

import { combineLatest, Observable, switchMap, tap } from 'rxjs';

import { HighlightAuto } from 'ngx-highlightjs';

import { ASC, DESC, SORT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants';
import { ITEMS_PER_PAGE, PAGE_HEADER, TOTAL_COUNT_RESPONSE_HEADER } from 'app/config/pagination.constants';

Expand Down Expand Up @@ -35,6 +37,7 @@ import { navigateToWithPagingInformation } from '../../navigation-util';
FormatMediumDatePipe,
FilterComponent,
ItemCountComponent,
HighlightAuto,
],
})
export class MessageComponent implements OnInit {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { HttpResponse, provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { HttpResponse } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRoute, ActivatedRouteSnapshot, Router, convertToParamMap, provideRouter } from '@angular/router';

import { of } from 'rxjs';

import { CodeFormatterService } from 'app/shared/code-formatter.service';

import { IMessage } from '../message.model';
import { MessageService } from '../service/message.service';

Expand All @@ -13,13 +15,18 @@ import messageResolve from './message-routing-resolve.service';
describe('Message routing resolve service', () => {
let mockRouter: Router;
let mockActivatedRouteSnapshot: ActivatedRouteSnapshot;
let service: MessageService;

let codeFormatterService: CodeFormatterService;
let messageService: MessageService;

let resultMessage: IMessage | null | undefined;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([])],
providers: [
provideRouter([]),
provideHttpClient(),
provideHttpClientTesting(),
{
provide: ActivatedRoute,
useValue: {
Expand All @@ -28,19 +35,30 @@ describe('Message routing resolve service', () => {
},
},
},
{
provide: CodeFormatterService,
useValue: {
formatCode: jest.fn(),
},
},
],
});

mockRouter = TestBed.inject(Router);
jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true));

mockActivatedRouteSnapshot = TestBed.inject(ActivatedRoute).snapshot;
service = TestBed.inject(MessageService);

codeFormatterService = TestBed.inject(CodeFormatterService);
messageService = TestBed.inject(MessageService);

resultMessage = undefined;
});

describe('resolve', () => {
it('should return IMessage returned by find', () => {
// GIVEN
service.find = jest.fn(messageId => of(new HttpResponse({ body: { messageId } })));
messageService.find = jest.fn((messageId: number) => of(new HttpResponse<IMessage>({ body: { messageId } })));
mockActivatedRouteSnapshot.params = { messageId: 123 };

// WHEN
Expand All @@ -53,13 +71,14 @@ describe('Message routing resolve service', () => {
});

// THEN
expect(service.find).toBeCalledWith(123);
expect(messageService.find).toBeCalledWith(123);
expect(codeFormatterService.formatCode).not.toHaveBeenCalled();
expect(resultMessage).toEqual({ messageId: 123 });
});

it('should return null if messageId is not provided', () => {
// GIVEN
service.find = jest.fn();
messageService.find = jest.fn();
mockActivatedRouteSnapshot.params = {};

// WHEN
Expand All @@ -72,13 +91,34 @@ describe('Message routing resolve service', () => {
});

// THEN
expect(service.find).not.toBeCalled();
expect(messageService.find).not.toHaveBeenCalled();
expect(resultMessage).toEqual(null);
});

it('should return IMessage returned by find with formatted payload', () => {
// GIVEN
messageService.find = jest.fn((messageId: number) => of(new HttpResponse<IMessage>({ body: { messageId, payload: 'foo' } })));
mockActivatedRouteSnapshot.params = { messageId: 123 };
(codeFormatterService.formatCode as jest.Mock).mockReturnValueOnce(of('bar'));

// WHEN
TestBed.runInInjectionContext(() => {
messageResolve(mockActivatedRouteSnapshot).subscribe({
next(result) {
resultMessage = result;
},
});
});

// THEN
expect(messageService.find).toBeCalledWith(123);
expect(codeFormatterService.formatCode).toHaveBeenCalledWith('foo');
expect(resultMessage).toEqual({ messageId: 123, payload: 'bar' });
});

it('should route to 404 page if data not found in server', () => {
// GIVEN
jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse<IMessage>({ body: null })));
jest.spyOn(messageService, 'find').mockReturnValue(of(new HttpResponse<IMessage>({ body: null })));
mockActivatedRouteSnapshot.params = { messageId: 123 };

// WHEN
Expand All @@ -91,7 +131,7 @@ describe('Message routing resolve service', () => {
});

// THEN
expect(service.find).toBeCalledWith(123);
expect(messageService.find).toBeCalledWith(123);
expect(resultMessage).toEqual(undefined);
expect(mockRouter.navigate).toHaveBeenCalledWith(['404']);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,44 @@
import { inject } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import { of, EMPTY, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

import { IMessage } from '../message.model';
import { MessageService } from '../service/message.service';
import { of, EMPTY, Observable, from } from 'rxjs';
import { map, mergeMap, switchMap } from 'rxjs/operators';

import { IMessage } from 'app/entities/message/message.model';
import { MessageService } from 'app/entities/message/service/message.service';
import { CodeFormatterService } from 'app/shared/code-formatter.service';

export const messageResolve = (route: ActivatedRouteSnapshot): Observable<null | IMessage> => {
const messageService = inject(MessageService);
const codeFormatterService = inject(CodeFormatterService);

const messageId = route.params['messageId'];

if (messageId) {
return inject(MessageService)
.find(messageId)
.pipe(
mergeMap((message: HttpResponse<IMessage>) => {
if (message.body) {
return of(message.body);
return messageService.find(messageId).pipe(
mergeMap((response: HttpResponse<IMessage>) => {
const message = response.body;

if (message) {
if (message.payload) {
return codeFormatterService.formatCode(message.payload).pipe(
map(result => {
message.payload = result;
return message;
}),
);
} else {
inject(Router).navigate(['404']);
return EMPTY;
return of(message);
}
}),
);
} else {
inject(Router).navigate(['404']);
return EMPTY;
}
}),
);
}

return of(null);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}}</a>
</td>
<td data-test="scenarioMessagesEntityDirection">{{ message.direction }}</td>
<td data-test="scenarioMessagesEntityPayload">{{ message.payload }}</td>
<td data-test="scenarioMessagesEntityPayload"><code *ngIf="message.payload" [highlightAuto]="message.payload"></code></td>
<td data-test="scenarioMessagesEntityCreatedDate">{{ message.createdDate | formatMediumDatetime }}</td>
<td class="text-end">
<div class="btn-group" (click)="$event.stopPropagation()">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { RouterModule } from '@angular/router';

import { HighlightAuto } from 'ngx-highlightjs';

import { sort } from 'app/core/util/operators';

import { IMessage } from 'app/entities/message/message.model';
import { MessageService } from 'app/entities/message/service/message.service';

import SharedModule from 'app/shared/shared.module';
import { DurationPipe, FormatMediumDatePipe } from 'app/shared/date';
import FormatMediumDatetimePipe from 'app/shared/date/format-medium-datetime.pipe';
import SortDirective from 'app/shared/sort/sort.directive';
import SharedModule from 'app/shared/shared.module';
import SortByDirective from 'app/shared/sort/sort-by.directive';
import SortDirective from 'app/shared/sort/sort.directive';

@Component({
standalone: true,
selector: 'app-scenario-messages-table',
templateUrl: './scenario-messages-table.component.html',
imports: [RouterModule, SharedModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe, SortDirective, SortByDirective],
imports: [
RouterModule,
SharedModule,
DurationPipe,
FormatMediumDatetimePipe,
FormatMediumDatePipe,
SortDirective,
SortByDirective,
HighlightAuto,
],
})
export class ScenarioMessagesTableComponent implements OnInit {
@Input()
Expand Down
Loading

0 comments on commit 91cb6d1

Please sign in to comment.