diff --git a/nebula-logger/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js b/nebula-logger/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js index d423ba7b8..c91513aae 100644 --- a/nebula-logger/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js +++ b/nebula-logger/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js @@ -112,7 +112,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const loggingLevelFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="logging-level-filter"]'); + const loggingLevelFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="loggingLevelFilter"]'); loggingLevelFilterDropdown.value = loggingLevels.DEBUG; loggingLevelFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -136,7 +136,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const loggingLevelFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="logging-level-filter"]'); + const loggingLevelFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="loggingLevelFilter"]'); loggingLevelFilterDropdown.value = loggingLevels.DEBUG; loggingLevelFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -159,7 +159,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const originTypeFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="origin-type-filter"]'); + const originTypeFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="originTypeFilter"]'); originTypeFilterDropdown.value = 'Flow'; originTypeFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -182,7 +182,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const originTypeFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="origin-type-filter"]'); + const originTypeFilterDropdown = element.shadowRoot.querySelector('lightning-combobox[data-id="originTypeFilter"]'); originTypeFilterDropdown.value = 'Flow'; originTypeFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -204,7 +204,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="origin-location-filter"]'); + const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="originLocationFilter"]'); originLocationFilterDropdown.value = 'SomeClass.someMethod'; originLocationFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -227,7 +227,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="origin-location-filter"]'); + const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="originLocationFilter"]'); originLocationFilterDropdown.value = 'SomeClass.someMethod'; originLocationFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -249,7 +249,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="logged-by-filter"]'); + const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="loggedByFilter"]'); originLocationFilterDropdown.value = 'some.person@test.com'; originLocationFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -272,7 +272,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="logged-by-filter"]'); + const originLocationFilterDropdown = element.shadowRoot.querySelector('lightning-input[data-id="loggedByFilter"]'); originLocationFilterDropdown.value = 'some.person@test.com'; originLocationFilterDropdown.dispatchEvent(new CustomEvent('change')); @@ -288,13 +288,13 @@ describe('LogEntryEventStream tests', () => { const eventStreamDiv = element.shadowRoot.querySelector('.event-stream'); expect(eventStreamDiv.textContent).toBeFalsy(); }); - it('includes matching log entry event for message filter', async () => { + it('includes matching log entry event using string for message filter', async () => { const element = createElement('log-entry-event-stream', { is: LogEntryEventStream }); document.body.appendChild(element); await Promise.resolve(); - const messageFilterTextarea = element.shadowRoot.querySelector('lightning-textarea[data-id="message-filter"]'); + const messageFilterTextarea = element.shadowRoot.querySelector('lightning-textarea[data-id="messageFilter"]'); messageFilterTextarea.value = 'matching text'; messageFilterTextarea.dispatchEvent(new CustomEvent('change')); @@ -317,7 +317,7 @@ describe('LogEntryEventStream tests', () => { }); document.body.appendChild(element); await Promise.resolve(); - const messageFilterTextarea = element.shadowRoot.querySelector('lightning-textarea[data-id="message-filter"]'); + const messageFilterTextarea = element.shadowRoot.querySelector('lightning-textarea[data-id="messageFilter"]'); messageFilterTextarea.value = 'non-matching text'; messageFilterTextarea.dispatchEvent(new CustomEvent('change')); @@ -333,4 +333,28 @@ describe('LogEntryEventStream tests', () => { const eventStreamDiv = element.shadowRoot.querySelector('.event-stream'); expect(eventStreamDiv.textContent).toBeFalsy(); }); + + it('includes matching log entry event using regex for message filter', async () => { + const element = createElement('log-entry-event-stream', { + is: LogEntryEventStream + }); + document.body.appendChild(element); + await Promise.resolve(); + + const messageFilterTextarea = element.shadowRoot.querySelector('lightning-textarea[data-id="messageFilter"]'); + messageFilterTextarea.value = 'Something.+? blah$'; + messageFilterTextarea.dispatchEvent(new CustomEvent('change')); + + const matchingLogEntryEvent = { ...mockLogEntryEventTemplate }; + matchingLogEntryEvent.Message__c = 'Something, something, something, beep boop beep!!!!!!!%@#$!%, blah, blah, blah'; + await jestMockPublish('/event/LogEntryEvent__e', { + data: { + payload: matchingLogEntryEvent + } + }); + + const expectedStreamText = getPlatformEventText(matchingLogEntryEvent); + const eventStreamDiv = element.shadowRoot.querySelector('.event-stream'); + expect(eventStreamDiv.textContent).toBe(expectedStreamText); + }); }); diff --git a/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.html b/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.html index 700a9baf3..86d50e7c6 100644 --- a/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.html +++ b/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.html @@ -26,39 +26,46 @@ value={maxEvents} > + diff --git a/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js b/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js index dcd31e2c0..beff92548 100644 --- a/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js +++ b/nebula-logger/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js @@ -2,6 +2,7 @@ import { LightningElement } from 'lwc'; import { isEmpEnabled, subscribe, unsubscribe } from 'lightning/empApi'; export default class LogEntryEventStream extends LightningElement { + unfilteredEvents = []; logEntryEvents = []; isExpanded = false; isStreamEnabled = true; @@ -12,13 +13,19 @@ export default class LogEntryEventStream extends LightningElement { messageFilter; originTypeFilter; originLocationFilter; + scenarioFilter; maxEvents = 50; _channel = '/event/LogEntryEvent__e'; // TODO need to support namespace in managed package _subscription = {}; get title() { - return this.logEntryEvents.length + ' Log Entry Events'; + let logEntryString = ' Log Entry Events'; + let startingTitle = this.logEntryEvents.length + logEntryString; + if (this.unfilteredEvents.length !== this.logEntryEvents.length) { + startingTitle = this.logEntryEvents.length + ' matching results out of ' + this.unfilteredEvents.length + logEntryString; + } + return startingTitle; } get streamButtonVariant() { @@ -59,7 +66,7 @@ export default class LogEntryEventStream extends LightningElement { } createSubscription() { - subscribe(this._channel, -1, this.subscriptionCallback.bind(this)).then(response => { + subscribe(this._channel, -1, this.subscriptionCallback).then(response => { this._subscription = response; }); } @@ -68,24 +75,9 @@ export default class LogEntryEventStream extends LightningElement { unsubscribe(this._subscription); } - handleLoggingLevelFilterChange(event) { - this.loggingLevelFilter = event.target.value; - } - - handleOriginTypeFilterChange(event) { - this.originTypeFilter = event.target.value; - } - - handleOriginLocationFilterChange(event) { - this.originLocationFilter = event.target.value; - } - - handleLoggedByFilterChange(event) { - this.loggedByFilter = event.target.value; - } - - handleMessageFilterChange(event) { - this.messageFilter = event.target.value; + handleFilterChange(event) { + this[event.target.dataset.id] = event.target.value; + this._filterEvents(); } handleMaxEventsChange(event) { @@ -94,6 +86,7 @@ export default class LogEntryEventStream extends LightningElement { onClear() { this.logEntryEvents = []; + this.unfilteredEvents = []; } // onToggleExpand() { @@ -104,44 +97,38 @@ export default class LogEntryEventStream extends LightningElement { onToggleStream() { this.isStreamEnabled = !this.isStreamEnabled; - if (this.isStreamEnabled) { - this.createSubscription(); - } else { - this.cancelSubscription(); - } + // eslint-disable-next-line + this.isStreamEnabled ? this.createSubscription() : this.cancelSubscription(); } - subscriptionCallback(response) { + subscriptionCallback = response => { const logEntryEvent = response.data.payload; // As of API v52.0 (Summer '21), platform events have a unique field, EventUUID // but it doesn't seem to be populated via empApi, so use a synthetic key instead logEntryEvent.key = logEntryEvent.TransactionId__c + '__' + logEntryEvent.TransactionEntryNumber__c; + this.unfilteredEvents.unshift(logEntryEvent); + this._filterEvents(); + }; - const updatedLogEntryEvents = [...this.logEntryEvents]; - - if ( - this._meetsLoggedByFilter(logEntryEvent) && - this._meetsLoggingLevelFilter(logEntryEvent) && - this._meetsMessageFilter(logEntryEvent) && - this._meetsOriginLocationFilter(logEntryEvent) && - this._meetsOriginTypeFilter(logEntryEvent) - ) { - updatedLogEntryEvents.unshift(logEntryEvent); + // Private functions + _filterEvents() { + while (this.unfilteredEvents.length > this.maxEvents) { + this.unfilteredEvents.pop(); } - while (updatedLogEntryEvents.length > this.maxEvents) { - updatedLogEntryEvents.pop(); - } - this.logEntryEvents = updatedLogEntryEvents; + this.logEntryEvents = this.unfilteredEvents.filter( + logEntryEvent => + this._meetsLoggedByFilter(logEntryEvent) && + this._meetsLoggingLevelFilter(logEntryEvent) && + this._meetsMessageFilter(logEntryEvent) && + this._meetsOriginLocationFilter(logEntryEvent) && + this._meetsOriginTypeFilter(logEntryEvent) && + this._meetsScenarioFilter(logEntryEvent) + ); } - // Private functions _meetsLoggedByFilter(logEntryEvent) { - let matches = false; - if (!this.loggedByFilter || logEntryEvent.LoggedByUsername__c.includes(this.loggedByFilter)) { - matches = true; - } - return matches; + return this._matchesTextFilter(this.loggedByFilter, logEntryEvent.LoggedByUsername__c); } _meetsLoggingLevelFilter(logEntryEvent) { @@ -153,27 +140,24 @@ export default class LogEntryEventStream extends LightningElement { } _meetsMessageFilter(logEntryEvent) { - // TODO support for regex searches in Message__c - let matches = false; - if (!this.messageFilter || logEntryEvent.Message__c.includes(this.messageFilter)) { - matches = true; - } - return matches; + return this._matchesTextFilter(this.messageFilter, logEntryEvent.Message__c); } _meetsOriginLocationFilter(logEntryEvent) { - // TODO support for regex searches in OriginLocation__c - let matches = false; - if (!this.originLocationFilter || logEntryEvent.OriginLocation__c.includes(this.originLocationFilter)) { - matches = true; - } - return matches; + return this._matchesTextFilter(this.originLocationFilter, logEntryEvent.OriginLocation__c); } _meetsOriginTypeFilter(logEntryEvent) { - // TODO support for regex searches in Message__c + return this._matchesTextFilter(this.originTypeFilter, logEntryEvent.OriginType__c); + } + + _meetsScenarioFilter(logEntryEvent) { + return this._matchesTextFilter(this.scenarioFilter, logEntryEvent.Scenario__c); + } + + _matchesTextFilter(filterCriteria = '', text = '') { let matches = false; - if (!this.originTypeFilter || logEntryEvent.OriginType__c === this.originTypeFilter) { + if (!filterCriteria || text.includes(filterCriteria) || text.match(filterCriteria)) { matches = true; } return matches; diff --git a/package.json b/package.json index 64b8e30b5..83497f3f6 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "test": "npm run test:lwc && npm run test:apex", "test:apex": "sfdx force:apex:test:run --verbose --testlevel RunLocalTests --wait 30 --resultformat human --codecoverage --detailedcoverage --outputdir ./tests/apex", "test:apex:suites": "sfdx force:apex:test:run --verbose --suitenames LoggerConfiguration,LoggerEngine,LoggerLogManagement,LoggerPluginFramework --wait 30 --resultformat human --codecoverage --detailedcoverage --outputdir ./tests/apex", - "test:lwc": "sfdx-lwc-jest --coverage" + "test:lwc": "sfdx-lwc-jest --coverage --skipApiVersionCheck" }, "dependencies": { "set-value": ">=4.0.1",