diff --git a/README.md b/README.md index 0c1b5f7..6a02948 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Poli -[![Version](https://img.shields.io/badge/Version-0.5.0-0065FF.svg)](#) +[![Version](https://img.shields.io/badge/Version-0.6.0-0065FF.svg)](#) [![license: MIT](https://img.shields.io/badge/license-MIT-orange.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://travis-ci.org/shzlw/poli.svg?branch=master)](https://travis-ci.org/shzlw/poli) [![codecov](https://codecov.io/gh/shzlw/poli/branch/master/graph/badge.svg)](https://codecov.io/gh/shzlw/poli) diff --git a/db/schema-sqlite.sql b/db/schema-sqlite.sql index fe794da..03df60d 100644 --- a/db/schema-sqlite.sql +++ b/db/schema-sqlite.sql @@ -1,5 +1,5 @@ --- v0.5.0 +-- v0.6.0 DROP TABLE IF EXISTS p_group_report; DROP TABLE IF EXISTS p_component; DROP TABLE IF EXISTS p_report; diff --git a/pom.xml b/pom.xml index 7bdeedf..811a6c5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.shzlw.poli poli jar - 0.5.0 + 0.6.0 1.8 diff --git a/src/main/java/com/shzlw/poli/rest/JdbcQueryWs.java b/src/main/java/com/shzlw/poli/rest/JdbcQueryWs.java index 6cd95c7..b219258 100644 --- a/src/main/java/com/shzlw/poli/rest/JdbcQueryWs.java +++ b/src/main/java/com/shzlw/poli/rest/JdbcQueryWs.java @@ -10,6 +10,7 @@ import com.shzlw.poli.service.JdbcDataSourceService; import com.shzlw.poli.service.JdbcQueryService; import com.shzlw.poli.service.ReportService; +import com.shzlw.poli.util.CommonUtil; import com.shzlw.poli.util.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,7 +82,8 @@ public ResponseEntity queryComponent( @RequestMapping( value = "/component/{id}/csv", method = RequestMethod.POST) - public void downloadComponent( + @Deprecated + public void downloadCsv( @PathVariable("id") long componentId, @RequestBody List filterParams, HttpServletRequest request, @@ -89,19 +91,20 @@ public void downloadComponent( ) throws IOException { Component component = componentDao.findById(componentId); boolean isAccessValid = isComponentAccessValid(component, request); + if (!isAccessValid) { + return; + } - if (isAccessValid) { - String sql = component.getSqlQuery(); - DataSource dataSource = jdbcDataSourceService.getDataSource(component.getJdbcDataSourceId()); - QueryResult queryResult = jdbcQueryService.queryComponentByParams(dataSource, sql, filterParams); - String csvText = queryResult.getData(); - String fileName = component.getTitle() + "_" + new Date(); + String sql = component.getSqlQuery(); + DataSource dataSource = jdbcDataSourceService.getDataSource(component.getJdbcDataSourceId()); + QueryResult queryResult = jdbcQueryService.queryComponentByParams(dataSource, sql, filterParams); + String csvText = queryResult.getData(); + String fileName = component.getTitle() + "_" + CommonUtil.getCurrentReadableDateTime(); - response.setContentType("text/csv"); - response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + fileName +"\"")); + response.setContentType("text/csv"); + response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + fileName +"\"")); - response.getWriter().write(csvText); - } + response.getWriter().write(csvText); } protected boolean isComponentAccessValid(Component component, HttpServletRequest request) { diff --git a/src/main/java/com/shzlw/poli/util/CommonUtil.java b/src/main/java/com/shzlw/poli/util/CommonUtil.java index 1993370..9d6a806 100644 --- a/src/main/java/com/shzlw/poli/util/CommonUtil.java +++ b/src/main/java/com/shzlw/poli/util/CommonUtil.java @@ -5,6 +5,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.format.DateTimeFormatter; public final class CommonUtil { @@ -17,4 +18,10 @@ public static LocalDateTime fromEpoch(long epoch) { public static long toEpoch(@Nullable LocalDateTime dateTime) { return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); } + + public static String getCurrentReadableDateTime() { + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return now.format(formatter); + } } diff --git a/src/main/java/com/shzlw/poli/util/Constants.java b/src/main/java/com/shzlw/poli/util/Constants.java index 1530e63..44ad0a5 100644 --- a/src/main/java/com/shzlw/poli/util/Constants.java +++ b/src/main/java/com/shzlw/poli/util/Constants.java @@ -4,7 +4,7 @@ public final class Constants { private Constants() {} - public static final String CURRENT_VERSION = "0.5.0"; + public static final String CURRENT_VERSION = "0.6.0"; public static final String SUCCESS = "success"; public static final String GOOD = ""; diff --git a/start.bat b/start.bat index fc60bcd..04f4f64 100644 --- a/start.bat +++ b/start.bat @@ -1 +1 @@ -java -jar poli-0.5.0.jar --spring.config.name=application,poli \ No newline at end of file +java -jar poli-0.6.0.jar --spring.config.name=application,poli \ No newline at end of file diff --git a/start.sh b/start.sh index 3f430e7..3b6a7fe 100755 --- a/start.sh +++ b/start.sh @@ -1 +1 @@ -java -jar poli-0.5.0.jar --spring.config.name=application,poli +java -jar poli-0.6.0.jar --spring.config.name=application,poli diff --git a/web-app/package.json b/web-app/package.json index 533e935..779934c 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -1,6 +1,6 @@ { "name": "poli-web-app", - "version": "0.5.0", + "version": "0.6.0", "private": true, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.17", diff --git a/web-app/src/components/GridItem.js b/web-app/src/components/GridItem.js index aa39723..4facadb 100644 --- a/web-app/src/components/GridItem.js +++ b/web-app/src/components/GridItem.js @@ -71,12 +71,47 @@ class GridItem extends React.Component { this.props.onComponentEdit(componentId); } - exportCsv = (componentId) => { + exportCsv = (title, queryResult = {}) => { + const queryResultData = Util.jsonToArray(queryResult.data); + const { + columns = [], + error + } = queryResult; + if (error) { + return; + } + this.convertCsv(title, columns, queryResultData); } - exportJson = (componentId) => { + convertCsv = (title = 'poli', columns = [], data = []) => { + let csvHeader = ''; + for (let i = 0; i < columns.length; i++) { + if (i != 0) { + csvHeader += ','; + } + csvHeader += columns[i].name; + } + let csvBody = ''; + for (let i = 0; i < data.length; i++) { + const row = Object.values(data[i]); + csvBody += row.join(',') + '\r\n'; + } + + const csvData = csvHeader + '\r\n' + csvBody; + const filename = title + '.csv'; + const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' }); + const link = document.createElement("a"); + if (link.download !== undefined) { + const url = URL.createObjectURL(blob); + link.setAttribute("href", url); + link.setAttribute("download", filename); + link.style.visibility = 'hidden'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } } removeComponent = (componentId) => { @@ -264,6 +299,8 @@ class GridItem extends React.Component { isEditMode, style = {}, drillThrough, + queryResult = {}, + type } = this.props; const { @@ -308,6 +345,30 @@ class GridItem extends React.Component { backgroundColor: contentBackgroundColor } + let readModeButtonGroup; + if (!isEditMode && type === Constants.CHART) { + if (hasDrillThrough) { + readModeButtonGroup = ( +
+
this.exportCsv(title, queryResult)}> + +
+
+ +
+
+ ) + } else { + readModeButtonGroup = ( +
+
this.exportCsv(title, queryResult)}> + +
+
+ ) + } + } + return (
{ isEditMode && ( @@ -327,7 +388,7 @@ class GridItem extends React.Component { )} { isEditMode && ( -
+
this.editComponent(id)}>
@@ -337,11 +398,7 @@ class GridItem extends React.Component {
)} - { !isEditMode && hasDrillThrough && ( -
- -
- )} + {readModeButtonGroup}
{this.renderComponentContent()} diff --git a/web-app/src/components/GridLayout.css b/web-app/src/components/GridLayout.css index b99ebfa..36abd76 100644 --- a/web-app/src/components/GridLayout.css +++ b/web-app/src/components/GridLayout.css @@ -32,13 +32,15 @@ z-index: 1; } -.grid-edit-panel { +.grid-title-button-panel { position: absolute; right: 0; top: 0; background-color: transparent; padding: 4px; z-index: 2; + min-width: 20px; + height: 20px; } .grid-draggable { @@ -60,4 +62,13 @@ bottom: 0; cursor: se-resize; z-index: 10; +} + +.download-csv-button { + display: none; +} + +.grid-title-button-panel:hover .download-csv-button { + display: inline-block; + transition: 0.3s; } \ No newline at end of file