mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 09:03:21 +00:00 
			
		
		
		
	GUACAMOLE-334: Add support for downloading connection history search results as CSV.
This commit is contained in:
		| @@ -39,8 +39,10 @@ angular.module('settings').directive('guacSettingsConnectionHistory', [function | ||||
|             var SortOrder                     = $injector.get('SortOrder'); | ||||
|  | ||||
|             // Get required services | ||||
|             var $filter        = $injector.get('$filter'); | ||||
|             var $routeParams   = $injector.get('$routeParams'); | ||||
|             var $translate     = $injector.get('$translate'); | ||||
|             var csvService     = $injector.get('csvService'); | ||||
|             var historyService = $injector.get('historyService'); | ||||
|  | ||||
|             /** | ||||
| @@ -178,6 +180,53 @@ angular.module('settings').directive('guacSettingsConnectionHistory', [function | ||||
|  | ||||
|             }; | ||||
|              | ||||
|             /** | ||||
|              * Initiates a download of a CSV version of the displayed history | ||||
|              * search results. | ||||
|              */ | ||||
|             $scope.downloadCSV = function downloadCSV() { | ||||
|  | ||||
|                 // Translate CSV header | ||||
|                 $translate([ | ||||
|                     'SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_USERNAME', | ||||
|                     'SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_STARTDATE', | ||||
|                     'SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_DURATION', | ||||
|                     'SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_CONNECTION_NAME', | ||||
|                     'SETTINGS_CONNECTION_HISTORY.FILENAME_HISTORY_CSV' | ||||
|                 ]).then(function headerTranslated(translations) { | ||||
|  | ||||
|                     // Initialize records with translated header row | ||||
|                     var records = [[ | ||||
|                         translations['SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_USERNAME'], | ||||
|                         translations['SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_STARTDATE'], | ||||
|                         translations['SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_DURATION'], | ||||
|                         translations['SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_CONNECTION_NAME'] | ||||
|                     ]]; | ||||
|  | ||||
|                     // Add rows for all history entries, using the same sort | ||||
|                     // order as the displayed table | ||||
|                     angular.forEach( | ||||
|                         $filter('orderBy')( | ||||
|                             $scope.historyEntryWrappers, | ||||
|                             $scope.order.predicate | ||||
|                         ), | ||||
|                         function pushRecord(historyEntryWrapper) { | ||||
|                             records.push([ | ||||
|                                 historyEntryWrapper.username, | ||||
|                                 $filter('date')(historyEntryWrapper.startDate, $scope.dateFormat), | ||||
|                                 historyEntryWrapper.duration / 1000, | ||||
|                                 historyEntryWrapper.connectionName | ||||
|                             ]); | ||||
|                         } | ||||
|                     ); | ||||
|  | ||||
|                     // Save the result | ||||
|                     saveAs(csvService.toBlob(records), translations['SETTINGS_CONNECTION_HISTORY.FILENAME_HISTORY_CSV']); | ||||
|  | ||||
|                 }); | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             // Initialize search results | ||||
|             $scope.search(); | ||||
|              | ||||
|   | ||||
							
								
								
									
										106
									
								
								guacamole/src/main/webapp/app/settings/services/csvService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								guacamole/src/main/webapp/app/settings/services/csvService.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| /* | ||||
|  * Licensed to the Apache Software Foundation (ASF) under one | ||||
|  * or more contributor license agreements.  See the NOTICE file | ||||
|  * distributed with this work for additional information | ||||
|  * regarding copyright ownership.  The ASF licenses this file | ||||
|  * to you under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance | ||||
|  * with the License.  You may obtain a copy of the License at | ||||
|  * | ||||
|  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, | ||||
|  * software distributed under the License is distributed on an | ||||
|  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||
|  * KIND, either express or implied.  See the License for the | ||||
|  * specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * A service for generating downloadable CSV links given arbitrary data. | ||||
|  */ | ||||
| angular.module('settings').factory('csvService', [function csvService() { | ||||
|  | ||||
|     var service = {}; | ||||
|  | ||||
|     /** | ||||
|      * Encodes an arbitrary value for inclusion in a CSV file as an individual | ||||
|      * field. With the exception of null and undefined (which are both | ||||
|      * interpreted as equivalent to an empty string), all values are coerced to | ||||
|      * a string and, if non-numeric, included within double quotes. If the | ||||
|      * value itself includes double quotes, those quotes will be properly | ||||
|      * escaped. | ||||
|      * | ||||
|      * @param {*} field | ||||
|      *     The arbitrary value to encode. | ||||
|      * | ||||
|      * @return {String} | ||||
|      *     The provided value, coerced to a string and properly escaped for | ||||
|      *     CSV. | ||||
|      */ | ||||
|     var encodeField = function encodeField(field) { | ||||
|  | ||||
|         // Coerce field to string | ||||
|         if (field === null || field === undefined) | ||||
|             field = ''; | ||||
|         else | ||||
|             field = '' + field; | ||||
|  | ||||
|         // Do not quote numeric fields | ||||
|         if (/^[0-9.]*$/.test(field)) | ||||
|             return field; | ||||
|  | ||||
|         // Enclose all other fields in quotes, escaping any quotes therein | ||||
|         return '"' + field.replace(/"/g, '""') + '"'; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Encodes each of the provided values for inclusion in a CSV file as | ||||
|      * fields within the same record (in the manner specified by | ||||
|      * encodeField()), separated by commas. | ||||
|      * | ||||
|      * @param {*[]} fields | ||||
|      *     An array of arbitrary values which make up the record. | ||||
|      * | ||||
|      * @return {String} | ||||
|      *     A CSV record containing the each value in the given array. | ||||
|      */ | ||||
|     var encodeRecord = function encodeRecord(fields) { | ||||
|         return fields.map(encodeField).join(','); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Encodes an entire array of records as properly-formatted CSV, where each | ||||
|      * entry in the provided array is an array of arbitrary fields. | ||||
|      * | ||||
|      * @param {Array.<*[]>} records | ||||
|      *     An array of all records making up the desired CSV. | ||||
|      * | ||||
|      * @return {String} | ||||
|      *     An entire CSV containing each provided record, separated by CR+LF | ||||
|      *     line terminators. | ||||
|      */ | ||||
|     var encodeCSV = function encodeCSV(records) { | ||||
|         return records.map(encodeRecord).join('\r\n'); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Blob containing properly-formatted CSV generated from the | ||||
|      * given array of records, where each entry in the provided array is an | ||||
|      * array of arbitrary fields. | ||||
|      * | ||||
|      * @param {Array.<*[]>} records | ||||
|      *     An array of all records making up the desired CSV. | ||||
|      * | ||||
|      * @returns {Blob} | ||||
|      *     A new Blob containing each provided record in CSV format. | ||||
|      */ | ||||
|     service.toBlob = function toBlob(records) { | ||||
|         return new Blob([ encodeCSV(records) ], { type : 'text/csv' }); | ||||
|     }; | ||||
|  | ||||
|     return service; | ||||
|  | ||||
| }]); | ||||
| @@ -46,9 +46,26 @@ | ||||
|  | ||||
| } | ||||
|  | ||||
| .settings.connectionHistory .filter .search-button { | ||||
| .settings.connectionHistory .filter .search-string { | ||||
|     -ms-flex: 1 1 auto; | ||||
|     -moz-box-flex: 1; | ||||
|     -webkit-box-flex: 1; | ||||
|     -webkit-flex: 1 1 auto; | ||||
|     flex: 1 1 auto; | ||||
| } | ||||
|  | ||||
| .settings.connectionHistory .filter .search-button, | ||||
| .settings.connectionHistory .filter button { | ||||
|  | ||||
|     -ms-flex: 0 0 auto; | ||||
|     -moz-box-flex: 0; | ||||
|     -webkit-box-flex: 0; | ||||
|     -webkit-flex: 0 0 auto; | ||||
|     flex: 0 0 auto; | ||||
|  | ||||
|     margin-top: 0; | ||||
|     margin-bottom: 0; | ||||
|  | ||||
| } | ||||
|  | ||||
| .settings.connectionHistory .history-list { | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
|     <form class="filter" ng-submit="search()"> | ||||
|         <input class="search-string" type="text" placeholder="{{'SETTINGS_CONNECTION_HISTORY.FIELD_PLACEHOLDER_FILTER' | translate}}" ng-model="searchString" /> | ||||
|         <input class="search-button" type="submit" value="{{'SETTINGS_CONNECTION_HISTORY.ACTION_SEARCH' | translate}}" /> | ||||
|         <button type="button" ng-click="downloadCSV()">{{'SETTINGS_CONNECTION_HISTORY.ACTION_DOWNLOAD' | translate}}</button> | ||||
|     </form> | ||||
|  | ||||
|     <!-- Search results --> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user