[TASK] Improve database analyzer UX 55/58355/3
authorChristian Kuhn <lolli@schwarzbu.ch>
Thu, 20 Sep 2018 16:53:20 +0000 (18:53 +0200)
committerWouter Wolters <typo3@wouterwolters.nl>
Thu, 20 Sep 2018 17:36:45 +0000 (19:36 +0200)
Give earlier feedback when opening the database analyzer
modal, block the buttons again if executing changes and
update the progress bar with what is currently going on.

Resolves: #86335
Releases: master
Change-Id: Ib1e01427fc7bb364d9a030ca1978804a7c1a8b49
Reviewed-on: https://review.typo3.org/58355
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
typo3/sysext/install/Classes/Controller/MaintenanceController.php
typo3/sysext/install/Resources/Public/JavaScript/Modules/DatabaseAnalyzer.js

index 5ad4da1..aec64e2 100644 (file)
@@ -160,21 +160,34 @@ class MaintenanceController extends AbstractController
     }
 
     /**
-     * Analyze current database situation
+     * Get main database analyzer modal HTML
      *
      * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function databaseAnalyzerAnalyzeAction(ServerRequestInterface $request): ResponseInterface
+    public function databaseAnalyzerAction(ServerRequestInterface $request): ResponseInterface
     {
         $view = $this->initializeStandaloneView($request, 'Maintenance/DatabaseAnalyzer.html');
         $formProtection = FormProtectionFactory::get(InstallToolFormProtection::class);
         $view->assignMultiple([
             'databaseAnalyzerExecuteToken' => $formProtection->generateToken('installTool', 'databaseAnalyzerExecute'),
         ]);
+        return new JsonResponse([
+            'success' => true,
+            'html' => $view->render(),
+        ]);
+    }
+
+    /**
+     * Analyze current database situation
+     *
+     * @param ServerRequestInterface $request
+     * @return ResponseInterface
+     */
+    public function databaseAnalyzerAnalyzeAction(ServerRequestInterface $request): ResponseInterface
+    {
         $this->loadExtLocalconfDatabaseAndExtTables();
         $messageQueue = new FlashMessageQueue('install');
-
         $suggestions = [];
         try {
             $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
@@ -307,11 +320,6 @@ class MaintenanceController extends AbstractController
                 }
                 $suggestions[] = $suggestion;
             }
-
-            $messageQueue->enqueue(new FlashMessage(
-                '',
-                'Analyzed current database'
-            ));
         } catch (StatementException $e) {
             $messageQueue->enqueue(new FlashMessage(
                 $e->getMessage(),
@@ -323,7 +331,6 @@ class MaintenanceController extends AbstractController
             'success' => true,
             'status' => $messageQueue,
             'suggestions' => $suggestions,
-            'html' => $view->render(),
         ]);
     }
 
index 04e3fd9..8561cc8 100644 (file)
@@ -26,7 +26,6 @@ define([
   'use strict';
 
   return {
-
     selectorModalBody: '.t3js-modal-body',
     selectorModuleContent: '.t3js-module-content',
     selectorAnalyzeTrigger: '.t3js-databaseAnalyzer-analyze',
@@ -41,7 +40,7 @@ define([
     initialize: function(currentModal) {
       var self = this;
       this.currentModal = currentModal;
-      this.analyzeAjax();
+      this.getData();
 
       // Select / deselect all checkboxes
       currentModal.on('click', '.t3js-databaseAnalyzer-suggestion-block-checkbox', function(e) {
@@ -55,21 +54,44 @@ define([
         e.preventDefault();
         self.execute();
       });
-
     },
 
-    analyze: function() {
-      this.currentModal.find(this.selectorOutputContainer).empty();
-      this.analyzeAjax();
+    getData: function() {
+      var self = this;
+      var modalContent = this.currentModal.find(this.selectorModalBody);
+      $.ajax({
+        url: Router.getUrl('databaseAnalyzer'),
+        cache: false,
+        success: function(data) {
+          if (data.success === true) {
+            modalContent.empty().append(data.html);
+            self.analyze();
+          } else {
+            Notification.error('Something went wrong');
+          }
+        },
+        error: function(xhr) {
+          Router.handleAjaxError(xhr, modalContent);
+        }
+      });
     },
 
-    analyzeAjax: function() {
+    analyze: function() {
       var self = this;
       var modalContent = this.currentModal.find(this.selectorModalBody);
-      var message = ProgressBar.render(Severity.loading, 'Loading...', '');
-      modalContent.find(this.selectorOutputContainer).append(message);
-      $(this.selectorExecuteTrigger).prop('disabled', true);
-      $(this.selectorAnalyzeTrigger).prop('disabled', true);
+      var outputContainer = modalContent.find(this.selectorOutputContainer);
+      var executeTrigger = modalContent.find(this.selectorExecuteTrigger);
+      var analyzeTrigger = modalContent.find(this.selectorAnalyzeTrigger);
+
+      outputContainer.empty().append(ProgressBar.render(Severity.loading, 'Analyzing current database schema...', ''));
+
+      analyzeTrigger.prop('disabled', true);
+      executeTrigger.prop('disabled', true);
+
+      outputContainer.on('change', 'input[type="checkbox"]', function() {
+        var hasCheckedCheckboxes = outputContainer.find(':checked').length > 0;
+        executeTrigger.prop('disabled', !hasCheckedCheckboxes);
+      });
 
       $.ajax({
         url: Router.getUrl('databaseAnalyzerAnalyze'),
@@ -77,13 +99,12 @@ define([
         success: function(data) {
           if (data.success === true) {
             if (Array.isArray(data.status)) {
+              outputContainer.find('.alert-loading').remove();
               data.status.forEach(function(element) {
                 var message = InfoBox.render(element.severity, element.title, element.message);
-                modalContent.find(self.selectorOutputContainer).find('.alert-loading').remove();
-                modalContent.find(self.selectorOutputContainer).append(message);
+                outputContainer.append(message);
               });
             }
-            modalContent.empty().append(data.html);
             if (Array.isArray(data.suggestions)) {
               data.suggestions.forEach(function(element) {
                 var aBlock = modalContent.find(self.selectorSuggestionBlock).clone();
@@ -115,10 +136,15 @@ define([
                   }
                   aBlock.find(self.selectorSuggestionList).append(aLine);
                 });
-                modalContent.find(self.selectorOutputContainer).append(aBlock.html());
+                outputContainer.append(aBlock.html());
               });
-              self.currentModal.find(self.selectorExecuteTrigger).prop('disabled', false);
-              self.currentModal.find(self.selectorAnalyzeTrigger).prop('disabled', false);
+
+              var isInitiallyDisabled = outputContainer.find(':checked').length === 0;
+              analyzeTrigger.prop('disabled', false);
+              executeTrigger.prop('disabled', isInitiallyDisabled);
+            }
+            if (data.suggestions.length === 0 && data.status.length === 0) {
+              outputContainer.append(InfoBox.render(Severity.ok, 'Database schema is up to date. Good job!', ''));
             }
           } else {
             Notification.error('Something went wrong');
@@ -134,12 +160,16 @@ define([
       var self = this;
       var modalContent = this.currentModal.find(this.selectorModalBody);
       var executeToken = this.currentModal.find(this.selectorModuleContent).data('database-analyzer-execute-token');
+      var outputContainer = modalContent.find(this.selectorOutputContainer);
       var selectedHashes = [];
-      this.currentModal.find('.t3js-databaseAnalyzer-output .t3js-databaseAnalyzer-suggestion-line input:checked').each(function() {
+
+      outputContainer.find('.t3js-databaseAnalyzer-suggestion-line input:checked').each(function() {
         selectedHashes.push($(this).data('hash'));
       });
-      $(this.selectorExecuteTrigger).prop('disabled', true);
-      $(this.selectorAnalyzeTrigger).prop('disabled', true);
+      outputContainer.empty().append(ProgressBar.render(Severity.loading, 'Executing database updates...', ''));
+      modalContent.find(this.selectorExecuteTrigger).prop('disabled', true);
+      modalContent.find(this.selectorAnalyzeTrigger).prop('disabled', true);
+
       $.ajax({
         url: Router.getUrl(),
         method: 'POST',
@@ -159,7 +189,7 @@ define([
               });
             }
           }
-          self.analyzeAjax();
+          self.analyze();
         },
         error: function(xhr) {
           Router.handleAjaxError(xhr, modalContent);