mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Merge remote-tracking branch 'origin/devel' into chore/cb-2548/product-information-design
This commit is contained in:
@@ -22,6 +22,34 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
### CloudBeaver 22.2.0 - 2022-09-06
|
||||
|
||||
Changes since 22.1.0
|
||||
- Public page:
|
||||
- administrators can create shared connections via the Connection menu.
|
||||
- Resource Manager:
|
||||
- users can group scripts into folders;
|
||||
- when internet connection is lost, script editing is disabled to prevent users from losing data;
|
||||
- users can refresh all scripts by clicking one button;
|
||||
- users can rename scripts.
|
||||
- Database Navigator:
|
||||
- users can group connections into folders.
|
||||
- SQL Editor:
|
||||
- "Link with Editor" tool is now available for the SQL Editor and synchronizes it with the element in the Database Navigator;
|
||||
- script formatting can be undone.
|
||||
- The Data Editor:
|
||||
- non-editable tables are marked;
|
||||
- users can change the coordinate system for spatial data in the Value panel.
|
||||
- Local configuration:
|
||||
- the application language can be set;
|
||||
- the number of table rows to load can be configured to prevent the application from slowing down in the following cases:
|
||||
- the default number of loaded rows when users open a table and then scroll it,
|
||||
- the minimum and maximum number of rows, which users can load at once when scrolling the table;
|
||||
- SQL query execution time limit can be changed;
|
||||
- The cookies can be disabled.
|
||||
- The product upgrade scripts were improved to avoid possible UI issues.
|
||||
- A lot of small bug fixes, enhancements and improvements have been made.
|
||||
|
||||
### CloudBeaver 22.1.4 - 2022-08-08
|
||||
- Local configuration:
|
||||
- The structure of the local configuration file has been improved to simplify the modification process;
|
||||
|
||||
@@ -22,9 +22,10 @@ package io.cloudbeaver;
|
||||
public class DBWConstants {
|
||||
|
||||
public static final String PERMISSION_PUBLIC = "public";
|
||||
|
||||
public static final String PERMISSION_ADMIN = "admin";
|
||||
|
||||
public static final String PERMISSION_CONFIGURATION_MANAGER = "configuration-manager";
|
||||
|
||||
public static final String PERMISSION_EDIT_STRUCTURE = "edit-meta";
|
||||
public static final String PERMISSION_EDIT_DATA = "edit-data";
|
||||
|
||||
|
||||
+3
-2
@@ -17,7 +17,7 @@
|
||||
package io.cloudbeaver.model.app;
|
||||
|
||||
import io.cloudbeaver.DataSourceFilter;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.VirtualProjectImpl;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.app.DBPApplication;
|
||||
@@ -27,7 +27,6 @@ import org.jkiss.dbeaver.model.rm.RMController;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.security.SMAdminController;
|
||||
import org.jkiss.dbeaver.model.security.SMController;
|
||||
import io.cloudbeaver.VirtualProjectImpl;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -41,6 +40,8 @@ public interface WebApplication extends DBPApplication {
|
||||
|
||||
Path getDataDirectory(boolean create);
|
||||
|
||||
Path getWorkspaceDirectory();
|
||||
|
||||
Path getHomeDirectory();
|
||||
|
||||
boolean isMultiNode();
|
||||
|
||||
+3
-3
@@ -204,7 +204,7 @@ public class LocalResourceController implements RMController {
|
||||
public RMProject createProject(@NotNull String name, @Nullable String description) throws DBException {
|
||||
if (!Files.exists(sharedProjectsPath)) {
|
||||
try {
|
||||
Files.createDirectory(sharedProjectsPath);
|
||||
Files.createDirectories(sharedProjectsPath);
|
||||
} catch (IOException e) {
|
||||
throw new DBException("Error creating shared project path", e);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ public class LocalResourceController implements RMController {
|
||||
throw new DBException("Project '" + name + "' already exists");
|
||||
}
|
||||
try {
|
||||
Files.createDirectory(getProjectPath(project.getId()));
|
||||
Files.createDirectories(getProjectPath(project.getId()));
|
||||
return project;
|
||||
} catch (IOException e) {
|
||||
throw new DBException("Error creating project path", e);
|
||||
@@ -354,7 +354,7 @@ public class LocalResourceController implements RMController {
|
||||
}
|
||||
try {
|
||||
if (isFolder) {
|
||||
Files.createDirectory(targetPath);
|
||||
Files.createDirectories(targetPath);
|
||||
} else {
|
||||
Files.createFile(targetPath);
|
||||
}
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2022 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package io.cloudbeaver.model.session;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.auth.SMAuthSpace;
|
||||
import org.jkiss.dbeaver.model.auth.SMAuthToken;
|
||||
import org.jkiss.dbeaver.model.auth.SMSession;
|
||||
import org.jkiss.dbeaver.model.auth.SMSessionContext;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
|
||||
public class SMWebSessionContext implements SMSessionContext {
|
||||
|
||||
private final WebSession session;
|
||||
private final SMSessionContext parentContext;
|
||||
|
||||
public SMWebSessionContext(SMSessionContext parentContext, WebSession session) {
|
||||
this.parentContext = parentContext;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SMSession getSpaceSession(@NotNull DBRProgressMonitor monitor, @NotNull SMAuthSpace space, boolean open) throws DBException {
|
||||
return parentContext.getSpaceSession(monitor, session.getSessionSpace(), open);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SMSession findSpaceSession(@NotNull SMAuthSpace space) {
|
||||
return parentContext.findSpaceSession(session.getSessionSpace());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SMAuthToken[] getSavedTokens() {
|
||||
return parentContext.getSavedTokens();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSession(@NotNull SMSession session) {
|
||||
parentContext.addSession(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeSession(@NotNull SMSession session) {
|
||||
return parentContext.removeSession(session);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -352,10 +352,9 @@ public class WebSession extends AbstractSessionPersistent implements SMSession,
|
||||
public VirtualProjectImpl createVirtualProject(RMProject project) {
|
||||
// Do not filter data sources from user project
|
||||
DataSourceFilter filter = project.getType() == RMProject.Type.USER ? x -> true : this::isDataSourceAccessible;
|
||||
SMSessionContext projectSessionContext = new SMWebSessionContext(sessionAuthContext, this);
|
||||
VirtualProjectImpl sessionProject = application.createProjectImpl(
|
||||
project,
|
||||
projectSessionContext,
|
||||
sessionAuthContext,
|
||||
this,
|
||||
filter);
|
||||
DBPDataSourceRegistry dataSourceRegistry = sessionProject.getDataSourceRegistry();
|
||||
@@ -958,8 +957,10 @@ public class WebSession extends AbstractSessionPersistent implements SMSession,
|
||||
}
|
||||
|
||||
public synchronized void updateSMAuthInfo(SMAuthInfo smAuthInfo) throws DBException {
|
||||
userContext.refresh(smAuthInfo);
|
||||
refreshUserData();
|
||||
boolean contextChanged = userContext.refresh(smAuthInfo);
|
||||
if (contextChanged) {
|
||||
refreshUserData();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
* @param smAuthInfo - auth info from security manager
|
||||
* @throws DBException - if user already authorized and new token come from another user
|
||||
*/
|
||||
public synchronized void refresh(SMAuthInfo smAuthInfo) throws DBException {
|
||||
public synchronized boolean refresh(SMAuthInfo smAuthInfo) throws DBException {
|
||||
if (smAuthInfo.getAuthStatus() != SMAuthStatus.SUCCESS) {
|
||||
throw new DBCException("Authorization did not complete successfully");
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
this.smSessionId = smAuthInfo.getAuthPermissions().getSessionId();
|
||||
setUser(authPermissions.getUserId() == null ? null : new WebUser(securityController.getUserById(authPermissions.getUserId())));
|
||||
}
|
||||
|
||||
return isSessionChanged;
|
||||
}
|
||||
|
||||
public synchronized void refreshSMSession() throws DBException {
|
||||
|
||||
-10
@@ -72,16 +72,6 @@ public class WebPlatformActivator extends Plugin {
|
||||
super.stop(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns configuration file
|
||||
*/
|
||||
public static synchronized File getConfigurationFile(String fileName) {
|
||||
if (configDir == null) {
|
||||
configDir = getInstance().getStateLocation().toFile();
|
||||
}
|
||||
return new File(configDir, fileName);
|
||||
}
|
||||
|
||||
public DBPPreferenceStore getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
@@ -456,6 +456,11 @@ public class CBApplication extends BaseWebApplication implements WebAuthApplicat
|
||||
return dataDir.toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getWorkspaceDirectory() {
|
||||
return Path.of(workspaceLocation);
|
||||
}
|
||||
|
||||
private void initializeSecurityController() throws DBException {
|
||||
securityController = createGlobalSecurityController();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import io.cloudbeaver.registry.WebDriverRegistry;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
@@ -244,7 +245,7 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public File getTempFolder(DBRProgressMonitor monitor, String name) {
|
||||
public Path getTempFolder(DBRProgressMonitor monitor, String name) {
|
||||
if (tempFolder == null) {
|
||||
// Make temp folder
|
||||
monitor.subTask("Create temp folder");
|
||||
@@ -265,13 +266,12 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
log.error("Error creating temp folder '" + folder.toAbsolutePath() + "'", e);
|
||||
}
|
||||
}
|
||||
return folder.toFile();
|
||||
return folder;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public File getConfigurationFile(String fileName) {
|
||||
return WebPlatformActivator.getConfigurationFile(fileName);
|
||||
protected Plugin getProductPlugin() {
|
||||
return WebPlatformActivator.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-6
@@ -28,9 +28,9 @@ import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
@@ -38,7 +38,7 @@ import java.util.List;
|
||||
|
||||
public class WebSQLDataLOBReceiver implements DBDDataReceiver {
|
||||
private static final Log log = Log.getLog(WebSQLDataLOBReceiver.class);
|
||||
public static final File DATA_EXPORT_FOLDER = CBPlatform.getInstance().getTempFolder(new VoidProgressMonitor(), "sql-lob-files");
|
||||
public static final Path DATA_EXPORT_FOLDER = CBPlatform.getInstance().getTempFolder(new VoidProgressMonitor(), "sql-lob-files");
|
||||
|
||||
private final String tableName;
|
||||
private final DBSDataContainer dataContainer;
|
||||
@@ -51,8 +51,12 @@ public class WebSQLDataLOBReceiver implements DBDDataReceiver {
|
||||
this.tableName = tableName;
|
||||
this.dataContainer = dataContainer;
|
||||
this.rowIndex = rowIndex;
|
||||
if (!DATA_EXPORT_FOLDER.exists()){
|
||||
DATA_EXPORT_FOLDER.mkdirs();
|
||||
if (!Files.exists(DATA_EXPORT_FOLDER)){
|
||||
try {
|
||||
Files.createDirectories(DATA_EXPORT_FOLDER);
|
||||
} catch (IOException e) {
|
||||
log.error("Error creating temp folder", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,8 +85,8 @@ public class WebSQLDataLOBReceiver implements DBDDataReceiver {
|
||||
throw new DBQuotaException(
|
||||
"Data export quota exceeded", CBConstants.QUOTA_PROP_FILE_LIMIT, fileSizeLimit.longValue(), binaryValue.length);
|
||||
}
|
||||
File file = new File(DATA_EXPORT_FOLDER, exportFileName);
|
||||
Files.write(file.toPath(), binaryValue);
|
||||
Path file = DATA_EXPORT_FOLDER.resolve(exportFileName);
|
||||
Files.write(file, binaryValue);
|
||||
return exportFileName;
|
||||
}
|
||||
|
||||
|
||||
+7
-8
@@ -17,11 +17,10 @@ import javax.servlet.annotation.MultipartConfig;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.Part;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -29,7 +28,7 @@ import java.util.regex.Pattern;
|
||||
public class WebSQLResultServlet extends WebServiceServletBase {
|
||||
|
||||
private static final Log log = Log.getLog(WebSQLResultServlet.class);
|
||||
private static final MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement(WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER.getAbsolutePath());
|
||||
private static final MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement(WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER.toAbsolutePath().toString());
|
||||
|
||||
// context-id/result-id/row-number/attribute-name
|
||||
private static final Pattern URL_PATTERN = Pattern.compile("/?([\\w]+)/([0-9]+)/([0-9]+)/([0-9]+)/(.+)[/\\?]?");
|
||||
@@ -68,18 +67,18 @@ public class WebSQLResultServlet extends WebServiceServletBase {
|
||||
valuePath = valuePath.substring(1);
|
||||
}
|
||||
|
||||
File dataFile = new File(WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER, valuePath);
|
||||
Path dataFile = WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER.resolve(valuePath);
|
||||
session.addInfoMessage("Download LOB file ...");
|
||||
response.setHeader("Content-Type", "application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + dataFile.getName() + "\"");
|
||||
response.setHeader("Content-Length", String.valueOf(dataFile.length()));
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + dataFile.getFileName().toString() + "\"");
|
||||
response.setHeader("Content-Length", String.valueOf(Files.size(dataFile)));
|
||||
response.setDateHeader("Expires", System.currentTimeMillis() + CBStaticServlet.STATIC_CACHE_SECONDS * 1000);
|
||||
response.setHeader("Cache-Control", "public, max-age=" + CBStaticServlet.STATIC_CACHE_SECONDS);
|
||||
|
||||
try (InputStream is = new FileInputStream(dataFile)) {
|
||||
try (InputStream is = Files.newInputStream(dataFile)) {
|
||||
IOUtils.copyStream(is, response.getOutputStream());
|
||||
}
|
||||
Files.deleteIfExists(dataFile.toPath());
|
||||
Files.deleteIfExists(dataFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -39,9 +39,9 @@ import org.jkiss.utils.Base64;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -211,7 +211,7 @@ public class WebSQLUtils {
|
||||
case WebSQLConstants.VALUE_TYPE_CONTENT: {
|
||||
if (map.get(WebSQLConstants.ATTR_BINARY) != null) {
|
||||
DBDContentStorage storage;
|
||||
File openFile = new File(WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER, (String) map.get("fileName"));
|
||||
Path openFile = WebSQLDataLOBReceiver.DATA_EXPORT_FOLDER.resolve((String) map.get("fileName"));
|
||||
Object tempValue = ((DBDAttributeBinding) attribute).getValueHandler().getValueFromObject(
|
||||
session,
|
||||
attribute,
|
||||
|
||||
+5
-5
@@ -14,10 +14,10 @@ import org.jkiss.utils.IOUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class WebDataTransferServlet extends WebServiceServletBase {
|
||||
|
||||
@@ -56,13 +56,13 @@ public class WebDataTransferServlet extends WebServiceServletBase {
|
||||
fileName = taskInfo.getDataFileId();
|
||||
}
|
||||
|
||||
File dataFile = taskInfo.getDataFile();
|
||||
Path dataFile = taskInfo.getDataFile();
|
||||
session.addInfoMessage("Download data ...");
|
||||
response.setHeader("Content-Type", processor.getContentType());
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
response.setHeader("Content-Length", String.valueOf(dataFile.length()));
|
||||
response.setHeader("Content-Length", String.valueOf(Files.size(dataFile)));
|
||||
|
||||
try (InputStream is = new FileInputStream(dataFile)) {
|
||||
try (InputStream is = Files.newInputStream(dataFile)) {
|
||||
IOUtils.copyStream(is, response.getOutputStream());
|
||||
}
|
||||
|
||||
|
||||
+11
-7
@@ -2,27 +2,29 @@ package io.cloudbeaver.service.data.transfer.impl;
|
||||
|
||||
import org.jkiss.dbeaver.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class WebDataTransferTaskConfig {
|
||||
|
||||
private static final Log log = Log.getLog(WebDataTransferTaskConfig.class);
|
||||
|
||||
private File dataFile;
|
||||
private Path dataFile;
|
||||
private WebDataTransferParameters parameters;
|
||||
private String exportFileName;
|
||||
|
||||
public WebDataTransferTaskConfig(File dataFile, WebDataTransferParameters parameters) {
|
||||
public WebDataTransferTaskConfig(Path dataFile, WebDataTransferParameters parameters) {
|
||||
this.dataFile = dataFile;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public File getDataFile() {
|
||||
public Path getDataFile() {
|
||||
return dataFile;
|
||||
}
|
||||
|
||||
public String getDataFileId() {
|
||||
return dataFile.getName();
|
||||
return dataFile.getFileName().toString();
|
||||
}
|
||||
|
||||
public WebDataTransferParameters getParameters() {
|
||||
@@ -38,8 +40,10 @@ public class WebDataTransferTaskConfig {
|
||||
}
|
||||
|
||||
public void deleteFile() {
|
||||
if (!dataFile.delete()) {
|
||||
log.error("Error deleting export file " + dataFile.getAbsolutePath());
|
||||
try {
|
||||
Files.delete(dataFile);
|
||||
} catch (IOException e) {
|
||||
log.error("Error deleting export file " + dataFile.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-19
@@ -51,9 +51,10 @@ import org.jkiss.dbeaver.tools.transfer.stream.StreamTransferConsumer;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -66,21 +67,19 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
|
||||
private static final Log log = Log.getLog(WebServiceDataTransfer.class);
|
||||
|
||||
private final File dataExportFolder;
|
||||
private final Path dataExportFolder;
|
||||
|
||||
public WebServiceDataTransfer() {
|
||||
dataExportFolder = CBPlatform.getInstance().getTempFolder(new VoidProgressMonitor(), "data-transfer");
|
||||
|
||||
ContentUtils.deleteFileRecursive(dataExportFolder);
|
||||
if (!dataExportFolder.mkdirs()) {
|
||||
log.error("Error re-creating temporary folder");
|
||||
try {
|
||||
Files.createDirectories(dataExportFolder);
|
||||
} catch (IOException e) {
|
||||
log.error("Error re-creating temporary folder", e);
|
||||
}
|
||||
}
|
||||
|
||||
public File getDataExportFolder() {
|
||||
return dataExportFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WebDataTransferStreamProcessor> getAvailableStreamProcessors(WebSession session) {
|
||||
List<DataTransferProcessorDescriptor> processors = DataTransferRegistry.getInstance().getAvailableProcessors(StreamTransferConsumer.class, DBSEntity.class);
|
||||
@@ -130,10 +129,12 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
if (taskInfo == null) {
|
||||
throw new DBWebException("Session task '" + dataFileId + "' not found");
|
||||
}
|
||||
File dataFile = taskInfo.getDataFile();
|
||||
Path dataFile = taskInfo.getDataFile();
|
||||
if (dataFile != null) {
|
||||
if (!dataFile.delete()) {
|
||||
log.warn("Error deleting data file '" + dataFile.getAbsolutePath() + "'");
|
||||
try {
|
||||
Files.delete(dataFile);
|
||||
} catch (IOException e) {
|
||||
log.warn("Error deleting data file '" + dataFile.toAbsolutePath() + "'", e);
|
||||
}
|
||||
}
|
||||
dtConfig.removeTask(taskInfo);
|
||||
@@ -151,13 +152,15 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
monitor.beginTask("Export data", 1);
|
||||
try {
|
||||
monitor.subTask("Export data using " + processor.getName());
|
||||
File exportFile = new File(dataExportFolder, makeUniqueFileName(sqlProcessor, processor));
|
||||
Path exportFile = dataExportFolder.resolve(makeUniqueFileName(sqlProcessor, processor));
|
||||
try {
|
||||
exportData(monitor, processor, dataContainer, parameters, resultsInfo, exportFile);
|
||||
} catch (Exception e) {
|
||||
if (exportFile.exists()) {
|
||||
if (!exportFile.delete()) {
|
||||
log.error("Error deleting export file " + exportFile.getAbsolutePath());
|
||||
if (Files.exists(exportFile)) {
|
||||
try {
|
||||
Files.delete(exportFile);
|
||||
} catch (IOException ex) {
|
||||
log.error("Error deleting export file " + exportFile.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
if (e instanceof DBException) {
|
||||
@@ -170,7 +173,7 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
taskConfig.setExportFileName(exportFileName);
|
||||
WebDataTransferUtils.getSessionDataTransferConfig(sqlProcessor.getWebSession()).addTask(taskConfig);
|
||||
|
||||
result = exportFile.getName();
|
||||
result = exportFile.getFileName().toString();
|
||||
} catch (Throwable e) {
|
||||
throw new InvocationTargetException(e);
|
||||
} finally {
|
||||
@@ -187,7 +190,7 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
DBSDataContainer dataContainer,
|
||||
WebDataTransferParameters parameters,
|
||||
WebSQLResultsInfo resultsInfo,
|
||||
File exportFile) throws DBException, IOException
|
||||
Path exportFile) throws DBException, IOException
|
||||
{
|
||||
IDataTransferProcessor processorInstance = processor.getInstance();
|
||||
if (!(processorInstance instanceof IStreamDataExporter)) {
|
||||
@@ -211,8 +214,8 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
StreamConsumerSettings settings = new StreamConsumerSettings();
|
||||
|
||||
settings.setOutputEncodingBOM(false);
|
||||
settings.setOutputFolder(exportFile.getParentFile().getAbsolutePath());
|
||||
settings.setOutputFilePattern(exportFile.getName());
|
||||
settings.setOutputFolder(exportFile.getParent().toAbsolutePath().toString());
|
||||
settings.setOutputFilePattern(exportFile.getFileName().toString());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
|
||||
|
||||
@@ -116,8 +116,9 @@ export const Loader = observer<Props>(function Loader({
|
||||
|
||||
if (loading) {
|
||||
if (element.cancel) {
|
||||
const cancelCopy = onCancel;
|
||||
onCancel = () => {
|
||||
onCancel?.();
|
||||
cancelCopy?.();
|
||||
element.cancel?.();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ export interface INotification<TProps extends INotificationExtraProps<any> = INo
|
||||
message?: string;
|
||||
timestamp: number;
|
||||
details?: string | Error | null;
|
||||
autoClose?: boolean;
|
||||
persistent?: boolean;
|
||||
state: { deleteDelay: number };
|
||||
isSilent: boolean;
|
||||
@@ -69,6 +70,7 @@ export interface INotificationOptions<TProps extends INotificationExtraProps<any
|
||||
message?: string;
|
||||
details?: string | Error | null;
|
||||
isSilent?: boolean;
|
||||
autoClose?: boolean;
|
||||
persistent?: boolean;
|
||||
extraProps?: TProps;
|
||||
timestamp?: number;
|
||||
|
||||
@@ -80,6 +80,7 @@ export class NotificationService {
|
||||
isSilent: !!options.isSilent,
|
||||
customComponent: options.customComponent,
|
||||
extraProps: options.extraProps || {} as TProps,
|
||||
autoClose: options.autoClose,
|
||||
persistent: options.persistent,
|
||||
state: observable({ deleteDelay: 0 }),
|
||||
timestamp: options.timestamp || Date.now(),
|
||||
|
||||
+6
-2
@@ -22,7 +22,7 @@ export class NotificationItemController implements IInitializableController {
|
||||
isDetailsDialogOpen = false;
|
||||
private notification!: INotification<any>;
|
||||
|
||||
constructor(private commonDialogService: CommonDialogService) {
|
||||
constructor(private readonly commonDialogService: CommonDialogService) {
|
||||
makeObservable(this, {
|
||||
isDetailsDialogOpen: observable,
|
||||
});
|
||||
@@ -35,7 +35,11 @@ export class NotificationItemController implements IInitializableController {
|
||||
this.handleShowDetails = this.showDetails.bind(this);
|
||||
}
|
||||
|
||||
if (notification.type !== ENotificationType.Error && !notification.persistent) {
|
||||
if (
|
||||
notification.type !== ENotificationType.Error
|
||||
&& !notification.persistent
|
||||
&& notification.autoClose !== false
|
||||
) {
|
||||
this.closeAfter = FadeTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -237,9 +237,7 @@ export class ConnectionOptionsTabService extends Bootstrap {
|
||||
|
||||
tempConfig.description = state.config.description;
|
||||
|
||||
if (state.projectId === PROJECT_GLOBAL_ID) {
|
||||
tempConfig.template = state.config.template;
|
||||
}
|
||||
tempConfig.template = state.projectId === PROJECT_GLOBAL_ID ? state.config.template : false;
|
||||
|
||||
tempConfig.driverId = state.config.driverId;
|
||||
|
||||
|
||||
@@ -63,9 +63,9 @@ export class LogViewerService {
|
||||
|
||||
toggle(): void {
|
||||
if (this.isActive) {
|
||||
this.stopLog();
|
||||
this.settings.active = false;
|
||||
} else {
|
||||
this.startLog();
|
||||
this.settings.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,14 +74,14 @@ export class LogViewerService {
|
||||
}
|
||||
|
||||
async startLog(): Promise<void> {
|
||||
if (this.isActive) {
|
||||
if (this.timeoutTaskId !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isLogViewerAvailable()) {
|
||||
throw new Error('Access denied');
|
||||
}
|
||||
this.failedRequestsCount = 0;
|
||||
this.settings.active = true;
|
||||
|
||||
const refreshInterval = this.logViewerSettingsService.settings.isValueDefault('refreshTimeout')
|
||||
? this.coreSettingsService.settings.getValue('app.logViewer.refreshTimeout')
|
||||
@@ -100,7 +100,6 @@ export class LogViewerService {
|
||||
clearTimeout(this.timeoutTaskId);
|
||||
this.timeoutTaskId = null;
|
||||
}
|
||||
this.settings.active = false;
|
||||
}
|
||||
|
||||
clearLog(): void {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import { observable } from 'mobx';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useObjectRef, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
@@ -22,6 +23,13 @@ interface Props {
|
||||
export function useLogViewer() {
|
||||
const logViewerService = useService(LogViewerService);
|
||||
|
||||
useEffect(() => {
|
||||
logViewerService.startLog();
|
||||
return () => {
|
||||
logViewerService.stopLog();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const props: Props = useObservableRef(
|
||||
() => ({ selectedItem: null }),
|
||||
{ selectedItem: observable.ref },
|
||||
|
||||
@@ -204,7 +204,7 @@ export class PluginBootstrap extends Bootstrap {
|
||||
this.notificationService.logInfo({
|
||||
title: 'sql_editor_upload_script_max_size_title',
|
||||
message: `Max size: ${maxSize}KB\nFile size: ${size}KB`,
|
||||
persistent: true,
|
||||
autoClose: false,
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
@@ -82,6 +82,7 @@ export function useTools(state: ISqlEditorTabState): Readonly<State> {
|
||||
this.notificationService.logInfo({
|
||||
title: 'sql_editor_upload_script_max_size_title',
|
||||
message: `Max size: ${maxSize}KB\nFile size: ${size}KB`,
|
||||
autoClose: false,
|
||||
});
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user