CB-3451 git integration (#1782)

* CB-3570 add manual save

* CB-3451 git settings api

* CB-3451 migrate to the new config model

* CB-3451 improve locks, update gql

* CB-3451 fix RM configuration

* CB-3570 resolve conflicts

* CB-3451 checkout remote branch

* CB-3451 review fix

* CB-3451 improve logs/fix private project access

* CB-3570 review fixes

* CB-3570 remove hasChanges flag

* CB-3570 debounce saveProperties

---------

Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
This commit is contained in:
alex
2023-07-04 21:35:38 +03:00
committed by GitHub
co-authored by Aleksandr Skoblikov
parent ba48b282fd
commit 3642bbfa41
22 changed files with 189 additions and 41 deletions
@@ -70,8 +70,10 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
}
@Override
public RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace) throws DBException {
public RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace
) throws DBException {
throw new IllegalStateException("Resource controller is not supported by " + getClass().getSimpleName());
}
@@ -53,7 +53,8 @@ public interface WebApplication extends DBPApplication {
WebProjectImpl createProjectImpl(
@NotNull WebSession webSession,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter);
@NotNull DataSourceFilter dataSourceFilter
);
SMController createSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
@@ -61,8 +62,10 @@ public interface WebApplication extends DBPApplication {
DBSSecretController getSecretController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace) throws DBException;
RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace
) throws DBException;
DBFileController createFileController(@NotNull SMCredentialsProvider credentialsProvider);
@@ -64,7 +64,7 @@ public class RMUtils {
* @return path to the project based on the name of projects and prefixes that it contains
*/
@NotNull
public static Path getProjectPathByName(@NotNull String projectId) throws DBException {
public static Path getProjectPathById(@NotNull String projectId) throws DBException {
int divPos = projectId.indexOf("_");
if (divPos <= 0) {
throw new DBException("Bad project ID");
@@ -71,7 +71,6 @@ public class LocalResourceController implements RMController {
private static final String FILE_REGEX = "(?U)[\\w.$()@/\\\\ -]+";
private static final String PROJECT_REGEX = "(?U)[\\w.$()@ -]+"; // slash not allowed in project name
public static final String DEFAULT_CHANGE_ID = "0";
private final DBPWorkspace workspace;
@@ -82,8 +81,8 @@ public class LocalResourceController implements RMController {
private final Path sharedProjectsPath;
private final String globalProjectName;
private Supplier<SMController> smControllerSupplier;
private final RMFileLockController lockController;
private final List<RMFileOperationHandler> fileHandlers;
protected final RMFileLockController lockController;
protected final List<RMFileOperationHandler> fileHandlers;
private final Map<String, BaseWebProjectImpl> projectRegistries = new LinkedHashMap<>();
@@ -121,7 +120,7 @@ public class LocalResourceController implements RMController {
return userId == null ? null : this.userProjectsPath.resolve(userId);
}
private BaseWebProjectImpl getWebProject(String projectId, boolean refresh) throws DBException {
protected BaseWebProjectImpl getWebProject(String projectId, boolean refresh) throws DBException {
synchronized (projectRegistries) {
BaseWebProjectImpl project = projectRegistries.get(projectId);
if (project == null || refresh) {
@@ -765,7 +764,7 @@ public class LocalResourceController implements RMController {
try {
Files.write(targetPath, data);
} catch (IOException e) {
throw new DBException("Error reading resource '" + resourcePath + "'", e);
throw new DBException("Error writing resource '" + resourcePath + "'", e);
}
return null;
});
@@ -777,7 +776,7 @@ public class LocalResourceController implements RMController {
return DEFAULT_CHANGE_ID;
}
private void createFolder(Path targetPath) throws DBException {
protected void createFolder(Path targetPath) throws DBException {
if (!Files.exists(targetPath)) {
try {
Files.createDirectories(targetPath);
@@ -924,34 +923,31 @@ public class LocalResourceController implements RMController {
}
private <T> T doProjectOperation(String projectId, RMFileOperation<T> operation) throws DBException {
var projectPath = getProjectPath(projectId);
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.projectOpened(projectPath);
fileHandler.projectOpened(projectId);
}
return operation.doOperation();
}
private <T> T doFileReadOperation(String projectId, Path file, RMFileOperation<T> operation) throws DBException {
var projectPath = getProjectPath(projectId);
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.beforeFileRead(projectPath, file);
fileHandler.beforeFileRead(projectId, file);
}
return operation.doOperation();
}
private <T> T doFileWriteOperation(String projectId, Path file, RMFileOperation<T> operation) throws DBException {
var projectPath = getProjectPath(projectId);
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.beforeFileChange(projectPath, file);
fileHandler.beforeFileChange(projectId, file);
}
var result = operation.doOperation();
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.afterFileChange(projectPath, file, credentialsProvider.getActiveUserCredentials());
fileHandler.afterFileChange(projectId, file, credentialsProvider.getActiveUserCredentials());
}
return result;
}
private Path getProjectPath(String projectId) throws DBException {
protected Path getProjectPath(String projectId) throws DBException {
RMProjectName project = parseProjectName(projectId);
RMProjectType type = project.getType();
String projectName = project.getName();
@@ -1179,9 +1175,16 @@ public class LocalResourceController implements RMController {
return RMProjectType.GLOBAL.getPrefix().equals(rmProjectName.getPrefix());
}
public static boolean isPrivateProject(String projectId, String userId) {
public static boolean isPrivateProject(String projectId) {
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix());
}
public static boolean isProjectOwner(String projectId, String userId) {
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix()) &&
rmProjectName.name.equals(userId);
}
}
@@ -25,23 +25,23 @@ import java.nio.file.Path;
public interface RMFileOperationHandler {
void projectOpened(@NotNull Path projectPath) throws DBException;
void projectOpened(@NotNull String projectId) throws DBException;
/**
* Executed before reading file
*/
void beforeFileRead(@NotNull Path projectPath, @NotNull Path filePath) throws DBException;
void beforeFileRead(@NotNull String projectId, @NotNull Path filePath) throws DBException;
/**
* Executed before file modification
*/
void beforeFileChange(@NotNull Path projectPath, @NotNull Path filePath) throws DBException;
void beforeFileChange(@NotNull String projectId, @NotNull Path filePath) throws DBException;
/**
* Executed after file modification
*/
void afterFileChange(
@NotNull Path projectPath,
@NotNull String projectId,
@NotNull Path filePath,
@Nullable SMCredentials smCredentials
) throws DBException;
@@ -18,6 +18,7 @@ package io.cloudbeaver.model.rm.lock;
import com.google.gson.Gson;
import io.cloudbeaver.model.app.WebApplication;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
@@ -71,7 +72,8 @@ public class RMFileLockController {
* @param operationName - executed operation name
* @return - lock
*/
public RMLock lockProject(String projectId, String operationName) throws DBException {
@NotNull
public RMLock lockProject(@NotNull String projectId,@NotNull String operationName) throws DBException {
synchronized (RMFileLockController.class) {
try {
createLockFolderIfNeeded();
@@ -91,6 +93,24 @@ public class RMFileLockController {
}
}
/**
* if the project is already locked, the operation will be executed as a child of the first lock,
* otherwise it creates its own lock.
*
* @param projectId - project to be locked
* @param operationName - executed operation name
* @return - lock
*/
@Nullable
public RMLock lockIfNotLocked(@NotNull String projectId, @NotNull String operationName) throws DBException {
synchronized (RMFileLockController.class) {
if (isProjectLocked(projectId)) {
return null;
}
return lockProject(projectId, operationName);
}
}
/**
* Check that project locked
*/
View File
@@ -17,6 +17,8 @@ import { DataSynchronizationQueue } from './DataSynchronization/DataSynchronizat
import { DataSynchronizationService } from './DataSynchronization/DataSynchronizationService';
import { ServerConfigEventHandler } from './ServerConfigEventHandler';
export const FEATURE_GIT_ID = 'git';
export type ServerConfig = Omit<SDKServerConfig, 'hostName'>;
@injectable()
@@ -0,0 +1,16 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2023 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { createKeyBinding } from '../createKeyBinding';
export const KEY_BINDING_SAVE = createKeyBinding({
id: 'save',
keysWin: ['ctrl+s'],
keysMac: ['cmd+s'],
preventDefault: true,
});
+1
View File
@@ -18,6 +18,7 @@ export * from './Action/Actions/ACTION_ZOOM_OUT';
export * from './Action/KeyBinding/Bindings/KEY_BINDING_OPEN_IN_TAB';
export * from './Action/KeyBinding/Bindings/KEY_BINDING_REDO';
export * from './Action/KeyBinding/Bindings/KEY_BINDING_UNDO';
export * from './Action/KeyBinding/Bindings/KEY_BINDING_SAVE';
export * from './Action/KeyBinding/KeyBindingService';
export * from './Action/KeyBinding/createKeyBinding';
export * from './Action/ActionService';
@@ -0,0 +1,15 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2023 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { createAction } from '@cloudbeaver/core-view';
export const ACTION_SAVE_AS_SCRIPT = createAction('save-as-script', {
label: 'plugin_sql_editor_navigation_tab_resource_save_script_title',
tooltip: 'plugin_sql_editor_navigation_tab_resource_save_script_title',
icon: '/icons/sql_script_sm.svg',
});
@@ -14,7 +14,7 @@ import { isResourceOfType, ProjectInfoResource, ProjectsService } from '@cloudbe
import { NAV_NODE_TYPE_RM_RESOURCE, ResourceManagerResource, RESOURCES_NODE_PATH } from '@cloudbeaver/core-resource-manager';
import { CachedMapAllKey } from '@cloudbeaver/core-sdk';
import { createPath, getPathName } from '@cloudbeaver/core-utils';
import { ACTION_SAVE, ActionService, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view';
import { ACTION_SAVE, ActionService, DATA_CONTEXT_MENU, KEY_BINDING_SAVE, KeyBindingService, MenuService } from '@cloudbeaver/core-view';
import { NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs';
import { getResourceKeyFromNodeId, NavResourceNodeService } from '@cloudbeaver/plugin-navigation-tree-rm';
import { ResourceManagerService } from '@cloudbeaver/plugin-resource-manager';
@@ -28,12 +28,14 @@ import {
MemorySqlDataSource,
SQL_EDITOR_TOOLS_MENU,
SqlDataSourceService,
SqlEditorService,
SqlEditorSettingsService,
} from '@cloudbeaver/plugin-sql-editor';
import { isSQLEditorTab, SqlEditorNavigatorService } from '@cloudbeaver/plugin-sql-editor-navigation-tab';
import { ResourceSqlDataSource } from './ResourceSqlDataSource';
import { SqlEditorTabResourceService } from './SqlEditorTabResourceService';
import { ACTION_SAVE_AS_SCRIPT } from './ACTION_SAVE_AS_SCRIPT';
@injectable()
export class PluginBootstrap extends Bootstrap {
@@ -53,8 +55,10 @@ export class PluginBootstrap extends Bootstrap {
private readonly menuService: MenuService,
private readonly sqlDataSourceService: SqlDataSourceService,
private readonly sqlEditorSettingsService: SqlEditorSettingsService,
private readonly sqlEditorService: SqlEditorService,
private readonly resourceManagerResource: ResourceManagerResource,
private readonly resourceManagerScriptsService: ResourceManagerScriptsService,
private readonly keyBindingService: KeyBindingService,
) {
super();
}
@@ -66,7 +70,7 @@ export class PluginBootstrap extends Bootstrap {
this.actionService.addHandler({
id: 'scripts-base-handler',
isActionApplicable: (context, action): boolean => {
if (action === ACTION_SAVE) {
if (action === ACTION_SAVE_AS_SCRIPT || action === ACTION_SAVE) {
const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE);
if (!state) {
@@ -79,7 +83,20 @@ export class PluginBootstrap extends Bootstrap {
const dataSource = this.sqlDataSourceService.get(state.editorId);
return dataSource instanceof MemorySqlDataSource || dataSource instanceof LocalStorageSqlDataSource;
if (action === ACTION_SAVE_AS_SCRIPT) {
return dataSource instanceof MemorySqlDataSource || dataSource instanceof LocalStorageSqlDataSource;
}
if (action === ACTION_SAVE) {
return dataSource instanceof ResourceSqlDataSource;
}
}
return false;
},
isHidden: (context, action) => {
if (action === ACTION_SAVE) {
return this.sqlEditorService.autoSave;
}
return false;
@@ -93,7 +110,7 @@ export class PluginBootstrap extends Bootstrap {
return;
}
if (action === ACTION_SAVE) {
if (action === ACTION_SAVE_AS_SCRIPT) {
let projectId = dataSource.executionContext?.projectId ?? null;
await this.projectInfoResource.load(CachedMapAllKey);
const name = getSqlEditorName(state, dataSource);
@@ -157,14 +174,40 @@ export class PluginBootstrap extends Bootstrap {
}
}
}
if (action === ACTION_SAVE) {
const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE);
const source = this.sqlDataSourceService.get(state.editorId) as ResourceSqlDataSource | undefined;
if (!source) {
return;
}
await source.save();
}
},
isDisabled: (context, action) => {
if (action === ACTION_SAVE) {
const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE);
const source = this.sqlDataSourceService.get(state.editorId) as ResourceSqlDataSource | undefined;
if (!source) {
return true;
}
return source.isLoading() || source.isSaved();
}
return false;
},
getActionInfo: (context, action) => {
if (action === ACTION_SAVE) {
if (action === ACTION_SAVE_AS_SCRIPT || action === ACTION_SAVE) {
return {
...action.info,
label: '',
};
}
return action.info;
},
});
@@ -176,6 +219,7 @@ export class PluginBootstrap extends Bootstrap {
if (!state) {
return false;
}
const dataSource = this.sqlDataSourceService.get(state.editorId);
return (
@@ -184,11 +228,27 @@ export class PluginBootstrap extends Bootstrap {
!!dataSource?.hasFeature(ESqlDataSourceFeatures.script)
);
},
getItems: (context, items) => [...items, ACTION_SAVE],
getItems: (context, items) => [...items, ACTION_SAVE_AS_SCRIPT, ACTION_SAVE],
});
this.keyBindingService.addKeyBindingHandler({
id: 'script-save',
binding: KEY_BINDING_SAVE,
isBindingApplicable: (context, action) => action === ACTION_SAVE,
handler: async context => {
const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE);
const source = this.sqlDataSourceService.get(state.editorId) as ResourceSqlDataSource | undefined;
if (!source) {
return;
}
await source.save();
},
});
}
load(): void | Promise<void> {}
load(): void | Promise<void> { }
private canOpenHandler(data: INodeNavigationData, contexts: IExecutionContextProvider<INodeNavigationData>): void {
const nodeInfo = contexts.getContext(this.navNodeManagerService.navigationNavNodeContext);
@@ -19,7 +19,7 @@ import { getRmResourceKey, ResourceManagerResource } from '@cloudbeaver/core-res
import { isResourceAlias, ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
import { createPath, debounce, getPathName, getPathParent, isArraysEqual, isObjectsEqual, isValuesEqual } from '@cloudbeaver/core-utils';
import { SCRIPTS_TYPE_ID } from '@cloudbeaver/plugin-resource-manager-scripts';
import { BaseSqlDataSource, ESqlDataSourceFeatures } from '@cloudbeaver/plugin-sql-editor';
import { BaseSqlDataSource, ESqlDataSourceFeatures, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
import type { IResourceSqlDataSourceState } from './IResourceSqlDataSourceState';
@@ -106,6 +106,7 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
private readonly projectInfoResource: ProjectInfoResource,
private readonly connectionInfoResource: ConnectionInfoResource,
private readonly resourceManagerResource: ResourceManagerResource,
private readonly sqlEditorService: SqlEditorService,
state: IResourceSqlDataSourceState,
) {
super();
@@ -116,6 +117,7 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
this.resourceUseKeyId = null;
this.scheduler = new TaskScheduler(() => true);
this.debouncedWrite = debounce(this.debouncedWrite.bind(this), VALUE_SYNC_DELAY);
this.debouncedSaveProperties = debounce(this.debouncedSaveProperties.bind(this), VALUE_SYNC_DELAY);
this.syncResource = this.syncResource.bind(this);
resourceManagerResource.onDataOutdated.addHandler(this.syncResource);
@@ -200,7 +202,7 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
this._script = script;
super.setScript(script);
if (previous !== script) {
if (this.sqlEditorService.autoSave && previous !== script) {
this.debouncedWrite();
}
}
@@ -264,7 +266,9 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
this.state.executionContext = toJS(executionContext);
super.setExecutionContext(executionContext);
this.saveProperties();
if (this.sqlEditorService.autoSave) {
this.debouncedSaveProperties();
}
}
}
@@ -351,6 +355,7 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
async save(): Promise<void> {
await this.write();
await this.saveProperties();
}
private async saveProperties() {
@@ -385,4 +390,8 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
private debouncedWrite() {
this.write();
}
private debouncedSaveProperties() {
this.saveProperties();
}
}
@@ -21,13 +21,12 @@ import { NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs';
import { NavResourceNodeService } from '@cloudbeaver/plugin-navigation-tree-rm';
import { ResourceManagerService } from '@cloudbeaver/plugin-resource-manager';
import { ResourceManagerScriptsService } from '@cloudbeaver/plugin-resource-manager-scripts';
import { getSqlEditorName, SqlDataSourceService } from '@cloudbeaver/plugin-sql-editor';
import { getSqlEditorName, SqlDataSourceService, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
import { SqlEditorTabService } from '@cloudbeaver/plugin-sql-editor-navigation-tab';
import type { IResourceSqlDataSourceState } from './IResourceSqlDataSourceState';
import { ResourceSqlDataSource } from './ResourceSqlDataSource';
import { SqlEditorTabResourceService } from './SqlEditorTabResourceService';
const RESOURCE_TAB_STATE = 'sql_editor_resource_tab_state';
const SYNC_DELAY = 5 * 60 * 1000;
@@ -50,6 +49,7 @@ export class ResourceSqlDataSourceBootstrap extends Bootstrap {
private readonly projectInfoResource: ProjectInfoResource,
private readonly windowEventsService: WindowEventsService,
private readonly sqlEditorTabResourceService: SqlEditorTabResourceService,
private readonly sqlEditorService: SqlEditorService,
localStorageSaveService: LocalStorageSaveService,
) {
super();
@@ -95,6 +95,7 @@ export class ResourceSqlDataSourceBootstrap extends Bootstrap {
this.projectInfoResource,
this.connectionInfoResource,
this.resourceManagerResource,
this.sqlEditorService,
this.createState(editorId),
);
@@ -169,7 +170,7 @@ export class ResourceSqlDataSourceBootstrap extends Bootstrap {
});
}
load(): void | Promise<void> {}
load(): void | Promise<void> { }
private createState(editorId: string, resourceKey?: string): IResourceSqlDataSourceState {
let state = this.dataSourceStateState.get(editorId);
@@ -1,4 +1,5 @@
export default [
['plugin_sql_editor_navigation_tab_resource_save_script_title', 'Save as script'],
['plugin_sql_editor_navigation_tab_script_state_renaming', 'Renaming script...'],
['plugin_sql_editor_navigation_tab_script_state_reading', 'Reading script...'],
['plugin_sql_editor_navigation_tab_script_state_saving', 'Saving script...'],
@@ -1,4 +1,5 @@
export default [
['plugin_sql_editor_navigation_tab_resource_save_script_title', 'Save as script'],
['plugin_sql_editor_navigation_tab_script_state_renaming', 'Renaming script...'],
['plugin_sql_editor_navigation_tab_script_state_reading', 'Reading script...'],
['plugin_sql_editor_navigation_tab_script_state_saving', 'Saving script...'],
@@ -1,4 +1,5 @@
export default [
['plugin_sql_editor_navigation_tab_resource_save_script_title', 'Сохранить как скрипт'],
['plugin_sql_editor_navigation_tab_script_state_renaming', 'Переименовывание скрипта...'],
['plugin_sql_editor_navigation_tab_script_state_reading', 'Чтение скрипта...'],
['plugin_sql_editor_navigation_tab_script_state_saving', 'Сохранение скрипта...'],
@@ -1,4 +1,5 @@
export default [
['plugin_sql_editor_navigation_tab_resource_save_script_title', 'Save as script'],
['plugin_sql_editor_navigation_tab_script_state_renaming', 'Renaming script...'],
['plugin_sql_editor_navigation_tab_script_state_reading', 'Reading script...'],
['plugin_sql_editor_navigation_tab_script_state_saving', 'Saving script...'],
@@ -76,12 +76,13 @@ export abstract class BaseSqlDataSource implements ISqlDataSource {
this.history.onNavigate.addHandler(value => this.setScript(value, SOURCE_HISTORY));
makeObservable<this, 'outdated' | 'editing'>(this, {
makeObservable<this, 'outdated' | 'editing' | 'saved'>(this, {
databaseModels: observable.ref,
exception: observable.ref,
outdated: observable.ref,
message: observable.ref,
editing: observable.ref,
saved: observable.ref,
});
}
@@ -97,6 +98,7 @@ export abstract class BaseSqlDataSource implements ISqlDataSource {
}
setExecutionContext(executionContext?: IConnectionExecutionContextInfo | undefined): void {
this.saved = false;
this.onUpdate.execute();
}
@@ -23,11 +23,13 @@ import { injectable } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
import { CachedMapAllKey, GraphQLService, SqlCompletionProposal, SqlScriptInfoFragment } from '@cloudbeaver/core-sdk';
import { FEATURE_GIT_ID, ServerConfigResource } from '@cloudbeaver/core-root';
import { getSqlEditorName } from './getSqlEditorName';
import type { ISqlEditorTabState } from './ISqlEditorTabState';
import { ESqlDataSourceFeatures } from './SqlDataSource/ESqlDataSourceFeatures';
import { SqlDataSourceService } from './SqlDataSource/SqlDataSourceService';
import { SqlEditorSettingsService } from './SqlEditorSettingsService';
export type SQLProposal = SqlCompletionProposal;
@@ -39,6 +41,10 @@ export interface IQueryChangeData {
@injectable()
export class SqlEditorService {
get autoSave() {
return this.sqlEditorSettingsService.settings.getValue('autoSave') && !this.serverConfigResource.isFeatureEnabled(FEATURE_GIT_ID, true);
}
readonly onQueryChange: ISyncExecutor<IQueryChangeData>;
constructor(
@@ -49,6 +55,8 @@ export class SqlEditorService {
private readonly connectionExecutionContextResource: ConnectionExecutionContextResource,
private readonly connectionInfoResource: ConnectionInfoResource,
private readonly sqlDataSourceService: SqlDataSourceService,
private readonly sqlEditorSettingsService: SqlEditorSettingsService,
private readonly serverConfigResource: ServerConfigResource,
) {
this.onQueryChange = new SyncExecutor();
}
@@ -11,6 +11,7 @@ import { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin';
const defaultSettings = {
maxFileSize: 10 * 1024, // kilobyte
disabled: false,
autoSave: true,
};
export type SqlEditorSettings = typeof defaultSettings;
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { injectable } from '@cloudbeaver/core-di';
import { ACTION_REDO, ACTION_UNDO, IActiveView, View } from '@cloudbeaver/core-view';
import { ACTION_REDO, ACTION_SAVE, ACTION_UNDO, IActiveView, View } from '@cloudbeaver/core-view';
import { ITab, NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs';
import { ACTION_SQL_EDITOR_EXECUTE } from './actions/ACTION_SQL_EDITOR_EXECUTE';
@@ -27,6 +27,7 @@ export class SqlEditorView extends View<ITab> {
ACTION_UNDO,
ACTION_REDO,
ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN,
ACTION_SAVE,
);
}