diff --git a/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Ajax/AjaxQueue.ts b/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Ajax/AjaxQueue.ts index 8a31afa7ca11c3b1f427e6fdd6551d88ba3470fb..92e2fbd9ec129da20a76b9256968690b470446a7 100644 --- a/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Ajax/AjaxQueue.ts +++ b/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Ajax/AjaxQueue.ts @@ -26,33 +26,35 @@ interface Payload { * Module: TYPO3/CMS/Install/Module/AjaxQueue */ class AjaxQueue { + private requests: Array<AjaxRequest> = []; private requestCount: number = 0; - private threshold: number = 10; + private threshold: number = 5; private queue: Array<Payload> = []; - public async add(payload: Payload): Promise<any> { - const oldFinally = payload.finally; - if (this.queue.length > 0 && this.requestCount <= this.threshold) { - this.sendRequest(this.queue.shift()).finally((): void => { - this.decrementRequestCount(); - }); - } else { - this.decrementRequestCount(); - } + public add(payload: Payload): void { + this.queue.push(payload); + this.handleNext(); + } - if (oldFinally) { - oldFinally(...arguments); - } + public flush(): void { + this.queue = []; + this.requests.map((request: AjaxRequest): void => { + request.abort(); + }); + this.requests = []; + } - if (this.requestCount >= this.threshold) { - this.queue.push(payload); - } else { + private handleNext(): void { + if (this.queue.length > 0 && this.requestCount < this.threshold) { this.incrementRequestCount(); - this.sendRequest(payload); + this.sendRequest(this.queue.shift()).finally((): void => { + this.decrementRequestCount(); + this.handleNext(); + }); } } - private async sendRequest(payload: Payload): Promise<any> { + private async sendRequest(payload: Payload): Promise<void> { const request = new AjaxRequest(payload.url); let response: any; if (typeof payload.method !== 'undefined' && payload.method.toUpperCase() === 'POST') { @@ -61,7 +63,11 @@ class AjaxQueue { response = request.withQueryArguments(payload.data || {}).get(); } - return response.then(payload.onfulfilled, payload.onrejected); + this.requests.push(request); + return response.then(payload.onfulfilled, payload.onrejected).then((): void => { + const idx = this.requests.indexOf(request); + delete this.requests[idx]; + }); } private incrementRequestCount(): void { diff --git a/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Module/Upgrade/ExtensionScanner.ts b/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Module/Upgrade/ExtensionScanner.ts index a9480170e352de327f65cb3226d807d1e5fa9379..afce0653dfae01b1f2b0fd28e2cbd38b32d8d697 100644 --- a/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Module/Upgrade/ExtensionScanner.ts +++ b/Build/Sources/TypeScript/install/Resources/Public/TypeScript/Module/Upgrade/ExtensionScanner.ts @@ -13,6 +13,7 @@ import 'bootstrap'; import * as $ from 'jquery'; +import AjaxRequest = require('TYPO3/CMS/Core/Ajax/AjaxRequest'); import {AjaxResponse} from 'TYPO3/CMS/Core/Ajax/AjaxResponse'; import {ResponseError} from 'TYPO3/CMS/Core/Ajax/ResponseError'; import {AbstractInteractableModule} from '../AbstractInteractableModule'; @@ -67,6 +68,8 @@ class ExtensionScanner extends AbstractInteractableModule { this.scanSingleExtension(extension); $me.data('scanned', true); } + }).on('hide.bs.modal', (): void => { + AjaxQueue.flush(); }).on('click', this.selectorScanSingleTrigger, (e: JQueryEventObject): void => { // Scan a single extension by clicking "Rescan" e.preventDefault(); @@ -83,9 +86,8 @@ class ExtensionScanner extends AbstractInteractableModule { private getData(): void { const modalContent = this.getModalBody(); - AjaxQueue.add({ - url: Router.getUrl('extensionScannerGetData'), - onfulfilled: async (response: AjaxResponse): Promise<any> => { + (new AjaxRequest(Router.getUrl('extensionScannerGetData'))).get().then( + async (response: AjaxResponse): Promise<any> => { const data = await response.resolve(); if (data.success === true) { modalContent.empty().append(data.html); @@ -94,10 +96,10 @@ class ExtensionScanner extends AbstractInteractableModule { Notification.error('Something went wrong'); } }, - onrejected: (error: ResponseError): void => { + (error: ResponseError): void => { Router.handleAjaxError(error, modalContent); - }, - }); + } + ); } private getExtensionSelector(extension: string): string { @@ -157,26 +159,24 @@ class ExtensionScanner extends AbstractInteractableModule { if (numberOfScannedExtensions === numberOfExtensions) { this.findInModal(this.selectorExtensionScanButton).removeClass('disabled').prop('disabled', false); Notification.success('Scan finished', 'All extensions have been scanned'); - AjaxQueue.add({ - url: Router.getUrl(), - method: 'POST', - data: { - install: { - action: 'extensionScannerMarkFullyScannedRestFiles', - token: this.getModuleContent().data('extension-scanner-mark-fully-scanned-rest-files-token'), - hashes: this.uniqueArray(this.listOfAffectedRestFileHashes), - }, + + (new AjaxRequest(Router.getUrl())).post({ + install: { + action: 'extensionScannerMarkFullyScannedRestFiles', + token: this.getModuleContent().data('extension-scanner-mark-fully-scanned-rest-files-token'), + hashes: this.uniqueArray(this.listOfAffectedRestFileHashes), }, - onfulfilled: async (response: AjaxResponse): Promise<any> => { + }).then( + async (response: AjaxResponse): Promise<any> => { const data = await response.resolve(); if (data.success === true) { Notification.success('Marked not affected files', 'Marked ' + data.markedAsNotAffected + ' ReST files as not affected.'); } }, - onrejected: (error: ResponseError): void => { + (error: ResponseError): void => { Router.handleAjaxError(error, modalContent); - }, - }); + } + ); } } @@ -206,139 +206,136 @@ class ExtensionScanner extends AbstractInteractableModule { $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-files').empty().text('0'); $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-lines').empty().text('0'); this.setProgressForAll(); - AjaxQueue.add({ - url: Router.getUrl(), - method: 'POST', - data: { - install: { - action: 'extensionScannerFiles', - token: executeToken, - extension: extension, - }, + (new AjaxRequest(Router.getUrl())).post({ + install: { + action: 'extensionScannerFiles', + token: executeToken, + extension: extension, }, - onfulfilled: async (response: AjaxResponse): Promise<any> => { + }).then( + async (response: AjaxResponse): Promise<any> => { const data = await response.resolve(); if (data.success === true && Array.isArray(data.files)) { const numberOfFiles = data.files.length; - if (numberOfFiles > 0) { - this.setStatusMessageForScan(extension, 0, numberOfFiles); - $extensionContainer.find('.t3js-extensionScanner-extension-body').text(''); - let doneFiles = 0; - data.files.forEach((file: string): void => { - AjaxQueue.add({ - method: 'POST', - data: { - install: { - action: 'extensionScannerScanFile', - token: this.getModuleContent().data('extension-scanner-scan-file-token'), - extension: extension, - file: file, - }, + if (numberOfFiles <= 0) { + Notification.warning('No files found', 'The extension EXT:' + extension + ' contains no files we can scan'); + return; + } + + this.setStatusMessageForScan(extension, 0, numberOfFiles); + $extensionContainer.find('.t3js-extensionScanner-extension-body').text(''); + let doneFiles = 0; + data.files.forEach((file: string): void => { + AjaxQueue.add({ + method: 'POST', + data: { + install: { + action: 'extensionScannerScanFile', + token: this.getModuleContent().data('extension-scanner-scan-file-token'), + extension: extension, + file: file, }, - url: Router.getUrl(), - onfulfilled: async (response: AjaxResponse): Promise<any> => { - const fileData: FileData = await response.resolve(); - doneFiles++; - this.setStatusMessageForScan(extension, doneFiles, numberOfFiles); - this.setProgressForScan(extension, doneFiles, numberOfFiles); - if (fileData.success && $.isArray(fileData.matches)) { - fileData.matches.forEach((match: Match): void => { - hitFound = true; - const aMatch: any = modalContent.find(hitTemplate).clone(); - aMatch.find('.t3js-extensionScanner-hit-file-panel-head').attr('href', '#collapse' + match.uniqueId); - aMatch.find('.t3js-extensionScanner-hit-file-panel-body').attr('id', 'collapse' + match.uniqueId); - aMatch.find('.t3js-extensionScanner-hit-filename').text(file); - aMatch.find('.t3js-extensionScanner-hit-message').text(match.message); - if (match.indicator === 'strong') { - aMatch.find('.t3js-extensionScanner-hit-file-panel-head .badges') - .append('<span class="badge" title="Reliable match, false positive unlikely">strong</span>'); - } else { - aMatch.find('.t3js-extensionScanner-hit-file-panel-head .badges') - .append('<span class="badge" title="Probable match, but can be a false positive">weak</span>'); - } - if (match.silenced === true) { - aMatch.find('.t3js-extensionScanner-hit-file-panel-head .badges') - .append('<span class="badge" title="Match has been annotated by extension author' + - ' as false positive match">silenced</span>'); - } - aMatch.find('.t3js-extensionScanner-hit-file-lineContent').empty().text(match.lineContent); - aMatch.find('.t3js-extensionScanner-hit-file-line').empty().text(match.line + ': '); - if ($.isArray(match.restFiles)) { - match.restFiles.forEach((restFile: RestFile): void => { - const aRest = modalContent.find(restTemplate).clone(); - aRest.find('.t3js-extensionScanner-hit-rest-panel-head').attr('href', '#collapse' + restFile.uniqueId); - aRest.find('.t3js-extensionScanner-hit-rest-panel-head .badge').empty().text(restFile.version); - aRest.find('.t3js-extensionScanner-hit-rest-panel-body').attr('id', 'collapse' + restFile.uniqueId); - aRest.find('.t3js-extensionScanner-hit-rest-headline').text(restFile.headline); - aRest.find('.t3js-extensionScanner-hit-rest-body').text(restFile.content); - aRest.addClass('panel-' + restFile.class); - aMatch.find('.t3js-extensionScanner-hit-file-rest-container').append(aRest); - this.listOfAffectedRestFileHashes.push(restFile.file_hash); - }); - } - const panelClass = - aMatch.find('.panel-breaking', '.t3js-extensionScanner-hit-file-rest-container').length > 0 - ? 'panel-danger' - : 'panel-warning'; - aMatch.addClass(panelClass); - $extensionContainer.find('.t3js-extensionScanner-extension-body').removeClass('hide').append(aMatch); - if (panelClass === 'panel-danger') { - $extensionContainer.removeClass('panel-warning').addClass(panelClass); - } - if (panelClass === 'panel-warning' && !$extensionContainer.hasClass('panel-danger')) { - $extensionContainer.addClass(panelClass); - } - }); - } - if (fileData.success) { - const currentLinesOfCode = parseInt($extensionContainer.find('.t3js-extensionScanner-extension-body-loc').text(), 10); - $extensionContainer.find('.t3js-extensionScanner-extension-body-loc').empty() - .text(currentLinesOfCode + fileData.effectiveCodeLines); - if (fileData.isFileIgnored) { - const currentIgnoredFiles = parseInt( - $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-files').text(), - 10, - ); - $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-files').empty().text(currentIgnoredFiles + 1); + }, + url: Router.getUrl(), + onfulfilled: async (response: AjaxResponse): Promise<void> => { + const fileData: FileData = await response.resolve(); + doneFiles++; + this.setStatusMessageForScan(extension, doneFiles, numberOfFiles); + this.setProgressForScan(extension, doneFiles, numberOfFiles); + if (fileData.success && $.isArray(fileData.matches)) { + fileData.matches.forEach((match: Match): void => { + hitFound = true; + const aMatch: any = modalContent.find(hitTemplate).clone(); + aMatch.find('.t3js-extensionScanner-hit-file-panel-head').attr('href', '#collapse' + match.uniqueId); + aMatch.find('.t3js-extensionScanner-hit-file-panel-body').attr('id', 'collapse' + match.uniqueId); + aMatch.find('.t3js-extensionScanner-hit-filename').text(file); + aMatch.find('.t3js-extensionScanner-hit-message').text(match.message); + if (match.indicator === 'strong') { + aMatch.find('.t3js-extensionScanner-hit-file-panel-head .badges') + .append('<span class="badge" title="Reliable match, false positive unlikely">strong</span>'); + } else { + aMatch.find('.t3js-extensionScanner-hit-file-panel-head .badges') + .append('<span class="badge" title="Probable match, but can be a false positive">weak</span>'); } - const currentIgnoredLines = parseInt( - $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-lines').text(), + if (match.silenced === true) { + aMatch.find('.t3js-extensionScanner-hit-file-panel-head .badges') + .append('<span class="badge" title="Match has been annotated by extension author' + + ' as false positive match">silenced</span>'); + } + aMatch.find('.t3js-extensionScanner-hit-file-lineContent').empty().text(match.lineContent); + aMatch.find('.t3js-extensionScanner-hit-file-line').empty().text(match.line + ': '); + if ($.isArray(match.restFiles)) { + match.restFiles.forEach((restFile: RestFile): void => { + const aRest = modalContent.find(restTemplate).clone(); + aRest.find('.t3js-extensionScanner-hit-rest-panel-head').attr('href', '#collapse' + restFile.uniqueId); + aRest.find('.t3js-extensionScanner-hit-rest-panel-head .badge').empty().text(restFile.version); + aRest.find('.t3js-extensionScanner-hit-rest-panel-body').attr('id', 'collapse' + restFile.uniqueId); + aRest.find('.t3js-extensionScanner-hit-rest-headline').text(restFile.headline); + aRest.find('.t3js-extensionScanner-hit-rest-body').text(restFile.content); + aRest.addClass('panel-' + restFile.class); + aMatch.find('.t3js-extensionScanner-hit-file-rest-container').append(aRest); + this.listOfAffectedRestFileHashes.push(restFile.file_hash); + }); + } + const panelClass = + aMatch.find('.panel-breaking', '.t3js-extensionScanner-hit-file-rest-container').length > 0 + ? 'panel-danger' + : 'panel-warning'; + aMatch.addClass(panelClass); + $extensionContainer.find('.t3js-extensionScanner-extension-body').removeClass('hide').append(aMatch); + if (panelClass === 'panel-danger') { + $extensionContainer.removeClass('panel-warning').addClass(panelClass); + } + if (panelClass === 'panel-warning' && !$extensionContainer.hasClass('panel-danger')) { + $extensionContainer.addClass(panelClass); + } + }); + } + if (fileData.success) { + const currentLinesOfCode = parseInt($extensionContainer.find('.t3js-extensionScanner-extension-body-loc').text(), 10); + $extensionContainer.find('.t3js-extensionScanner-extension-body-loc').empty() + .text(currentLinesOfCode + fileData.effectiveCodeLines); + if (fileData.isFileIgnored) { + const currentIgnoredFiles = parseInt( + $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-files').text(), 10, ); - $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-lines').empty() - .text(currentIgnoredLines + fileData.ignoredLines); + $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-files').empty().text(currentIgnoredFiles + 1); } - if (doneFiles === numberOfFiles) { - if (!hitFound) { - $extensionContainer.addClass('panel-success'); - } - $extensionContainer.addClass('t3js-extensionscan-finished'); - this.setProgressForAll(); - $extensionContainer.find('.t3js-extensionScanner-scan-single').text('Rescan').attr('disabled', null); + const currentIgnoredLines = parseInt( + $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-lines').text(), + 10, + ); + $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-lines').empty() + .text(currentIgnoredLines + fileData.ignoredLines); + } + if (doneFiles === numberOfFiles) { + if (!hitFound) { + $extensionContainer.addClass('panel-success'); } - }, - onrejected: (reason: string): void => { - doneFiles = doneFiles + 1; - this.setStatusMessageForScan(extension, doneFiles, numberOfFiles); - this.setProgressForScan(extension, doneFiles, numberOfFiles); + $extensionContainer.addClass('t3js-extensionscan-finished'); this.setProgressForAll(); - Notification.error('Oops, an error occurred', 'Please look at the console output for details'); - console.error(reason); - }, - }); + $extensionContainer.find('.t3js-extensionScanner-scan-single').text('Rescan').attr('disabled', null); + } + }, + onrejected: (reason: string): void => { + doneFiles = doneFiles + 1; + this.setStatusMessageForScan(extension, doneFiles, numberOfFiles); + this.setProgressForScan(extension, doneFiles, numberOfFiles); + this.setProgressForAll(); + console.error(reason); + }, }); - } else { - Notification.warning('No files found', 'The extension EXT:' + extension + ' contains no files we can scan'); - } + }); } else { Notification.error('Oops, an error occurred', 'Please look at the console output for details'); console.error(data); } }, - onrejected: (error: ResponseError): void => { + (error: ResponseError): void => { Router.handleAjaxError(error, modalContent); - }, - }); + } + ); } } diff --git a/typo3/sysext/install/Resources/Public/JavaScript/Ajax/AjaxQueue.js b/typo3/sysext/install/Resources/Public/JavaScript/Ajax/AjaxQueue.js index 23c88a94f77016ded269157b44a7cccec4417677..68abd1451c50697b8649bf2a78bc00f96d6967d7 100644 --- a/typo3/sysext/install/Resources/Public/JavaScript/Ajax/AjaxQueue.js +++ b/typo3/sysext/install/Resources/Public/JavaScript/Ajax/AjaxQueue.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","TYPO3/CMS/Core/Ajax/AjaxRequest"],(function(e,t,s){"use strict";return new class{constructor(){this.requestCount=0,this.threshold=10,this.queue=[]}async add(e){const t=e.finally;this.queue.length>0&&this.requestCount<=this.threshold?this.sendRequest(this.queue.shift()).finally(()=>{this.decrementRequestCount()}):this.decrementRequestCount(),t&&t(...arguments),this.requestCount>=this.threshold?this.queue.push(e):(this.incrementRequestCount(),this.sendRequest(e))}async sendRequest(e){const t=new s(e.url);let u;return(u=void 0!==e.method&&"POST"===e.method.toUpperCase()?t.post(e.data):t.withQueryArguments(e.data||{}).get()).then(e.onfulfilled,e.onrejected)}incrementRequestCount(){this.requestCount++}decrementRequestCount(){this.requestCount>0&&this.requestCount--}}})); \ No newline at end of file +define(["require","exports","TYPO3/CMS/Core/Ajax/AjaxRequest"],(function(e,t,s){"use strict";return new class{constructor(){this.requests=[],this.requestCount=0,this.threshold=5,this.queue=[]}add(e){this.queue.push(e),this.handleNext()}flush(){this.queue=[],this.requests.map(e=>{e.abort()}),this.requests=[]}handleNext(){this.queue.length>0&&this.requestCount<this.threshold&&(this.incrementRequestCount(),this.sendRequest(this.queue.shift()).finally(()=>{this.decrementRequestCount(),this.handleNext()}))}async sendRequest(e){const t=new s(e.url);let u;return u=void 0!==e.method&&"POST"===e.method.toUpperCase()?t.post(e.data):t.withQueryArguments(e.data||{}).get(),this.requests.push(t),u.then(e.onfulfilled,e.onrejected).then(()=>{const e=this.requests.indexOf(t);delete this.requests[e]})}incrementRequestCount(){this.requestCount++}decrementRequestCount(){this.requestCount>0&&this.requestCount--}}})); \ No newline at end of file diff --git a/typo3/sysext/install/Resources/Public/JavaScript/Module/Upgrade/ExtensionScanner.js b/typo3/sysext/install/Resources/Public/JavaScript/Module/Upgrade/ExtensionScanner.js index 4a9710c9706925a48ef0102034715e386fed280a..f5e66deae2d1624811f69cd4b926b745d6dd7899 100644 --- a/typo3/sysext/install/Resources/Public/JavaScript/Module/Upgrade/ExtensionScanner.js +++ b/typo3/sysext/install/Resources/Public/JavaScript/Module/Upgrade/ExtensionScanner.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","jquery","../AbstractInteractableModule","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Notification","../../Ajax/AjaxQueue","../../Router","bootstrap"],(function(e,n,t,s,i,a,o,r){"use strict";class l extends s.AbstractInteractableModule{constructor(){super(...arguments),this.listOfAffectedRestFileHashes=[],this.selectorExtensionContainer=".t3js-extensionScanner-extension",this.selectorNumberOfFiles=".t3js-extensionScanner-number-of-files",this.selectorScanSingleTrigger=".t3js-extensionScanner-scan-single",this.selectorExtensionScanButton=".t3js-extensionScanner-scan-all"}initialize(e){this.currentModal=e,this.getData(),e.on("show.bs.collapse",this.selectorExtensionContainer,e=>{const n=t(e.currentTarget);if(void 0===n.data("scanned")){const e=n.data("extension");this.scanSingleExtension(e),n.data("scanned",!0)}}).on("click",this.selectorScanSingleTrigger,e=>{e.preventDefault();const n=t(e.currentTarget).closest(this.selectorExtensionContainer).data("extension");this.scanSingleExtension(n)}).on("click",this.selectorExtensionScanButton,n=>{n.preventDefault(),t(n.currentTarget).addClass("disabled").prop("disabled",!0);const s=e.find(this.selectorExtensionContainer);this.scanAll(s)})}getData(){const e=this.getModalBody();o.add({url:r.getUrl("extensionScannerGetData"),onfulfilled:async n=>{const t=await n.resolve();!0===t.success?(e.empty().append(t.html),i.setButtons(t.buttons)):a.error("Something went wrong")},onrejected:n=>{r.handleAjaxError(n,e)}})}getExtensionSelector(e){return this.selectorExtensionContainer+"-"+e}scanAll(e){this.findInModal(this.selectorExtensionContainer).removeClass("panel-danger panel-warning panel-success").find(".panel-progress-bar").css("width",0).attr("aria-valuenow",0).find("span").text("0%"),this.setProgressForAll(),e.each((e,n)=>{const s=t(n),i=s.data("extension");this.scanSingleExtension(i),s.data("scanned",!0)})}setStatusMessageForScan(e,n,t){this.findInModal(this.getExtensionSelector(e)).find(this.selectorNumberOfFiles).text("Checked "+n+" of "+t+" files")}setProgressForScan(e,n,t){const s=n/t*100;this.findInModal(this.getExtensionSelector(e)).find(".panel-progress-bar").css("width",s+"%").attr("aria-valuenow",s).find("span").text(s+"%")}setProgressForAll(){const e=this.findInModal(this.selectorExtensionContainer).length,n=this.findInModal(this.selectorExtensionContainer+".t3js-extensionscan-finished.panel-success").length+this.findInModal(this.selectorExtensionContainer+".t3js-extensionscan-finished.panel-warning").length+this.findInModal(this.selectorExtensionContainer+".t3js-extensionscan-finished.panel-danger").length,t=n/e*100,s=this.getModalBody();this.findInModal(".t3js-extensionScanner-progress-all-extension .progress-bar").css("width",t+"%").attr("aria-valuenow",t).find("span").text(n+" of "+e+" scanned"),n===e&&(this.findInModal(this.selectorExtensionScanButton).removeClass("disabled").prop("disabled",!1),a.success("Scan finished","All extensions have been scanned"),o.add({url:r.getUrl(),method:"POST",data:{install:{action:"extensionScannerMarkFullyScannedRestFiles",token:this.getModuleContent().data("extension-scanner-mark-fully-scanned-rest-files-token"),hashes:this.uniqueArray(this.listOfAffectedRestFileHashes)}},onfulfilled:async e=>{const n=await e.resolve();!0===n.success&&a.success("Marked not affected files","Marked "+n.markedAsNotAffected+" ReST files as not affected.")},onrejected:e=>{r.handleAjaxError(e,s)}}))}uniqueArray(e){return e.filter((e,n,t)=>t.indexOf(e)===n)}scanSingleExtension(e){const n=this.getModuleContent().data("extension-scanner-files-token"),s=this.getModalBody(),i=this.findInModal(this.getExtensionSelector(e));let l=!1;i.removeClass("panel-danger panel-warning panel-success t3js-extensionscan-finished"),i.data("hasRun","true"),i.find(".t3js-extensionScanner-scan-single").text("Scanning...").attr("disabled","disabled"),i.find(".t3js-extensionScanner-extension-body-loc").empty().text("0"),i.find(".t3js-extensionScanner-extension-body-ignored-files").empty().text("0"),i.find(".t3js-extensionScanner-extension-body-ignored-lines").empty().text("0"),this.setProgressForAll(),o.add({url:r.getUrl(),method:"POST",data:{install:{action:"extensionScannerFiles",token:n,extension:e}},onfulfilled:async n=>{const d=await n.resolve();if(!0===d.success&&Array.isArray(d.files)){const n=d.files.length;if(n>0){this.setStatusMessageForScan(e,0,n),i.find(".t3js-extensionScanner-extension-body").text("");let c=0;d.files.forEach(d=>{o.add({method:"POST",data:{install:{action:"extensionScannerScanFile",token:this.getModuleContent().data("extension-scanner-scan-file-token"),extension:e,file:d}},url:r.getUrl(),onfulfilled:async a=>{const o=await a.resolve();if(c++,this.setStatusMessageForScan(e,c,n),this.setProgressForScan(e,c,n),o.success&&t.isArray(o.matches)&&o.matches.forEach(e=>{l=!0;const n=s.find("#t3js-extensionScanner-file-hit-template").clone();n.find(".t3js-extensionScanner-hit-file-panel-head").attr("href","#collapse"+e.uniqueId),n.find(".t3js-extensionScanner-hit-file-panel-body").attr("id","collapse"+e.uniqueId),n.find(".t3js-extensionScanner-hit-filename").text(d),n.find(".t3js-extensionScanner-hit-message").text(e.message),"strong"===e.indicator?n.find(".t3js-extensionScanner-hit-file-panel-head .badges").append('<span class="badge" title="Reliable match, false positive unlikely">strong</span>'):n.find(".t3js-extensionScanner-hit-file-panel-head .badges").append('<span class="badge" title="Probable match, but can be a false positive">weak</span>'),!0===e.silenced&&n.find(".t3js-extensionScanner-hit-file-panel-head .badges").append('<span class="badge" title="Match has been annotated by extension author as false positive match">silenced</span>'),n.find(".t3js-extensionScanner-hit-file-lineContent").empty().text(e.lineContent),n.find(".t3js-extensionScanner-hit-file-line").empty().text(e.line+": "),t.isArray(e.restFiles)&&e.restFiles.forEach(e=>{const t=s.find("#t3js-extensionScanner-file-hit-rest-template").clone();t.find(".t3js-extensionScanner-hit-rest-panel-head").attr("href","#collapse"+e.uniqueId),t.find(".t3js-extensionScanner-hit-rest-panel-head .badge").empty().text(e.version),t.find(".t3js-extensionScanner-hit-rest-panel-body").attr("id","collapse"+e.uniqueId),t.find(".t3js-extensionScanner-hit-rest-headline").text(e.headline),t.find(".t3js-extensionScanner-hit-rest-body").text(e.content),t.addClass("panel-"+e.class),n.find(".t3js-extensionScanner-hit-file-rest-container").append(t),this.listOfAffectedRestFileHashes.push(e.file_hash)});const a=n.find(".panel-breaking",".t3js-extensionScanner-hit-file-rest-container").length>0?"panel-danger":"panel-warning";n.addClass(a),i.find(".t3js-extensionScanner-extension-body").removeClass("hide").append(n),"panel-danger"===a&&i.removeClass("panel-warning").addClass(a),"panel-warning"!==a||i.hasClass("panel-danger")||i.addClass(a)}),o.success){const e=parseInt(i.find(".t3js-extensionScanner-extension-body-loc").text(),10);if(i.find(".t3js-extensionScanner-extension-body-loc").empty().text(e+o.effectiveCodeLines),o.isFileIgnored){const e=parseInt(i.find(".t3js-extensionScanner-extension-body-ignored-files").text(),10);i.find(".t3js-extensionScanner-extension-body-ignored-files").empty().text(e+1)}const n=parseInt(i.find(".t3js-extensionScanner-extension-body-ignored-lines").text(),10);i.find(".t3js-extensionScanner-extension-body-ignored-lines").empty().text(n+o.ignoredLines)}c===n&&(l||i.addClass("panel-success"),i.addClass("t3js-extensionscan-finished"),this.setProgressForAll(),i.find(".t3js-extensionScanner-scan-single").text("Rescan").attr("disabled",null))},onrejected:t=>{c+=1,this.setStatusMessageForScan(e,c,n),this.setProgressForScan(e,c,n),this.setProgressForAll(),a.error("Oops, an error occurred","Please look at the console output for details"),console.error(t)}})})}else a.warning("No files found","The extension EXT:"+e+" contains no files we can scan")}else a.error("Oops, an error occurred","Please look at the console output for details"),console.error(d)},onrejected:e=>{r.handleAjaxError(e,s)}})}}return new l})); \ No newline at end of file +define(["require","exports","jquery","TYPO3/CMS/Core/Ajax/AjaxRequest","../AbstractInteractableModule","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Notification","../../Ajax/AjaxQueue","../../Router","bootstrap"],(function(e,n,t,s,i,a,o,r,l){"use strict";class c extends i.AbstractInteractableModule{constructor(){super(...arguments),this.listOfAffectedRestFileHashes=[],this.selectorExtensionContainer=".t3js-extensionScanner-extension",this.selectorNumberOfFiles=".t3js-extensionScanner-number-of-files",this.selectorScanSingleTrigger=".t3js-extensionScanner-scan-single",this.selectorExtensionScanButton=".t3js-extensionScanner-scan-all"}initialize(e){this.currentModal=e,this.getData(),e.on("show.bs.collapse",this.selectorExtensionContainer,e=>{const n=t(e.currentTarget);if(void 0===n.data("scanned")){const e=n.data("extension");this.scanSingleExtension(e),n.data("scanned",!0)}}).on("hide.bs.modal",()=>{r.flush()}).on("click",this.selectorScanSingleTrigger,e=>{e.preventDefault();const n=t(e.currentTarget).closest(this.selectorExtensionContainer).data("extension");this.scanSingleExtension(n)}).on("click",this.selectorExtensionScanButton,n=>{n.preventDefault(),t(n.currentTarget).addClass("disabled").prop("disabled",!0);const s=e.find(this.selectorExtensionContainer);this.scanAll(s)})}getData(){const e=this.getModalBody();new s(l.getUrl("extensionScannerGetData")).get().then(async n=>{const t=await n.resolve();!0===t.success?(e.empty().append(t.html),a.setButtons(t.buttons)):o.error("Something went wrong")},n=>{l.handleAjaxError(n,e)})}getExtensionSelector(e){return this.selectorExtensionContainer+"-"+e}scanAll(e){this.findInModal(this.selectorExtensionContainer).removeClass("panel-danger panel-warning panel-success").find(".panel-progress-bar").css("width",0).attr("aria-valuenow",0).find("span").text("0%"),this.setProgressForAll(),e.each((e,n)=>{const s=t(n),i=s.data("extension");this.scanSingleExtension(i),s.data("scanned",!0)})}setStatusMessageForScan(e,n,t){this.findInModal(this.getExtensionSelector(e)).find(this.selectorNumberOfFiles).text("Checked "+n+" of "+t+" files")}setProgressForScan(e,n,t){const s=n/t*100;this.findInModal(this.getExtensionSelector(e)).find(".panel-progress-bar").css("width",s+"%").attr("aria-valuenow",s).find("span").text(s+"%")}setProgressForAll(){const e=this.findInModal(this.selectorExtensionContainer).length,n=this.findInModal(this.selectorExtensionContainer+".t3js-extensionscan-finished.panel-success").length+this.findInModal(this.selectorExtensionContainer+".t3js-extensionscan-finished.panel-warning").length+this.findInModal(this.selectorExtensionContainer+".t3js-extensionscan-finished.panel-danger").length,t=n/e*100,i=this.getModalBody();this.findInModal(".t3js-extensionScanner-progress-all-extension .progress-bar").css("width",t+"%").attr("aria-valuenow",t).find("span").text(n+" of "+e+" scanned"),n===e&&(this.findInModal(this.selectorExtensionScanButton).removeClass("disabled").prop("disabled",!1),o.success("Scan finished","All extensions have been scanned"),new s(l.getUrl()).post({install:{action:"extensionScannerMarkFullyScannedRestFiles",token:this.getModuleContent().data("extension-scanner-mark-fully-scanned-rest-files-token"),hashes:this.uniqueArray(this.listOfAffectedRestFileHashes)}}).then(async e=>{const n=await e.resolve();!0===n.success&&o.success("Marked not affected files","Marked "+n.markedAsNotAffected+" ReST files as not affected.")},e=>{l.handleAjaxError(e,i)}))}uniqueArray(e){return e.filter((e,n,t)=>t.indexOf(e)===n)}scanSingleExtension(e){const n=this.getModuleContent().data("extension-scanner-files-token"),i=this.getModalBody(),a=this.findInModal(this.getExtensionSelector(e));let c=!1;a.removeClass("panel-danger panel-warning panel-success t3js-extensionscan-finished"),a.data("hasRun","true"),a.find(".t3js-extensionScanner-scan-single").text("Scanning...").attr("disabled","disabled"),a.find(".t3js-extensionScanner-extension-body-loc").empty().text("0"),a.find(".t3js-extensionScanner-extension-body-ignored-files").empty().text("0"),a.find(".t3js-extensionScanner-extension-body-ignored-lines").empty().text("0"),this.setProgressForAll(),new s(l.getUrl()).post({install:{action:"extensionScannerFiles",token:n,extension:e}}).then(async n=>{const s=await n.resolve();if(!0===s.success&&Array.isArray(s.files)){const n=s.files.length;if(n<=0)return void o.warning("No files found","The extension EXT:"+e+" contains no files we can scan");this.setStatusMessageForScan(e,0,n),a.find(".t3js-extensionScanner-extension-body").text("");let d=0;s.files.forEach(s=>{r.add({method:"POST",data:{install:{action:"extensionScannerScanFile",token:this.getModuleContent().data("extension-scanner-scan-file-token"),extension:e,file:s}},url:l.getUrl(),onfulfilled:async o=>{const r=await o.resolve();if(d++,this.setStatusMessageForScan(e,d,n),this.setProgressForScan(e,d,n),r.success&&t.isArray(r.matches)&&r.matches.forEach(e=>{c=!0;const n=i.find("#t3js-extensionScanner-file-hit-template").clone();n.find(".t3js-extensionScanner-hit-file-panel-head").attr("href","#collapse"+e.uniqueId),n.find(".t3js-extensionScanner-hit-file-panel-body").attr("id","collapse"+e.uniqueId),n.find(".t3js-extensionScanner-hit-filename").text(s),n.find(".t3js-extensionScanner-hit-message").text(e.message),"strong"===e.indicator?n.find(".t3js-extensionScanner-hit-file-panel-head .badges").append('<span class="badge" title="Reliable match, false positive unlikely">strong</span>'):n.find(".t3js-extensionScanner-hit-file-panel-head .badges").append('<span class="badge" title="Probable match, but can be a false positive">weak</span>'),!0===e.silenced&&n.find(".t3js-extensionScanner-hit-file-panel-head .badges").append('<span class="badge" title="Match has been annotated by extension author as false positive match">silenced</span>'),n.find(".t3js-extensionScanner-hit-file-lineContent").empty().text(e.lineContent),n.find(".t3js-extensionScanner-hit-file-line").empty().text(e.line+": "),t.isArray(e.restFiles)&&e.restFiles.forEach(e=>{const t=i.find("#t3js-extensionScanner-file-hit-rest-template").clone();t.find(".t3js-extensionScanner-hit-rest-panel-head").attr("href","#collapse"+e.uniqueId),t.find(".t3js-extensionScanner-hit-rest-panel-head .badge").empty().text(e.version),t.find(".t3js-extensionScanner-hit-rest-panel-body").attr("id","collapse"+e.uniqueId),t.find(".t3js-extensionScanner-hit-rest-headline").text(e.headline),t.find(".t3js-extensionScanner-hit-rest-body").text(e.content),t.addClass("panel-"+e.class),n.find(".t3js-extensionScanner-hit-file-rest-container").append(t),this.listOfAffectedRestFileHashes.push(e.file_hash)});const o=n.find(".panel-breaking",".t3js-extensionScanner-hit-file-rest-container").length>0?"panel-danger":"panel-warning";n.addClass(o),a.find(".t3js-extensionScanner-extension-body").removeClass("hide").append(n),"panel-danger"===o&&a.removeClass("panel-warning").addClass(o),"panel-warning"!==o||a.hasClass("panel-danger")||a.addClass(o)}),r.success){const e=parseInt(a.find(".t3js-extensionScanner-extension-body-loc").text(),10);if(a.find(".t3js-extensionScanner-extension-body-loc").empty().text(e+r.effectiveCodeLines),r.isFileIgnored){const e=parseInt(a.find(".t3js-extensionScanner-extension-body-ignored-files").text(),10);a.find(".t3js-extensionScanner-extension-body-ignored-files").empty().text(e+1)}const n=parseInt(a.find(".t3js-extensionScanner-extension-body-ignored-lines").text(),10);a.find(".t3js-extensionScanner-extension-body-ignored-lines").empty().text(n+r.ignoredLines)}d===n&&(c||a.addClass("panel-success"),a.addClass("t3js-extensionscan-finished"),this.setProgressForAll(),a.find(".t3js-extensionScanner-scan-single").text("Rescan").attr("disabled",null))},onrejected:t=>{d+=1,this.setStatusMessageForScan(e,d,n),this.setProgressForScan(e,d,n),this.setProgressForAll(),console.error(t)}})})}else o.error("Oops, an error occurred","Please look at the console output for details"),console.error(s)},e=>{l.handleAjaxError(e,i)})}}return new c})); \ No newline at end of file