CB-5790 remove template plugin (#3339)

* CB-5790 remove template plugin

* dbeaver/pro#5038 Remove connection template

* CB-5790 update yarn lock

* CB-5790 fix

* CB-5790 remove templates

* CB-5790 remove template field from fragment

* CB-5790 return access tab

---------

Co-authored-by: Ruslan <pupkinvasya7000@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
This commit is contained in:
alex
2025-04-23 12:34:53 +02:00
committed by GitHub
co-authored by Ruslan Evgenia mr-anton-t
parent 08346ebc12
commit d4e8329528
114 changed files with 150 additions and 2839 deletions
@@ -32,10 +32,8 @@ import java.util.Map;
public class WebConnectionConfig {
private String connectionId;
private String templateId;
private String driverId;
private boolean template;
private boolean readOnly;
private String host;
@@ -70,14 +68,7 @@ public class WebConnectionConfig {
public WebConnectionConfig(Map<String, Object> params) {
if (!CommonUtils.isEmpty(params)) {
connectionId = JSONUtils.getString(params, "connectionId");
templateId = JSONUtils.getString(params, "templateId");
String dataSourceId = JSONUtils.getString(params, "dataSourceId");
if (CommonUtils.isEmpty(templateId) && !CommonUtils.isEmpty(dataSourceId)) {
templateId = dataSourceId;
}
driverId = JSONUtils.getString(params, "driverId");
template = JSONUtils.getBoolean(params, "template");
readOnly = JSONUtils.getBoolean(params, "readOnly");
host = JSONUtils.getString(params, "host");
@@ -121,21 +112,11 @@ public class WebConnectionConfig {
return connectionId;
}
@Property
public String getTemplateId() {
return templateId;
}
@Property
public String getDriverId() {
return driverId;
}
@Property
public boolean isTemplate() {
return template;
}
@Property
public boolean isReadOnly() {
return readOnly;
@@ -171,11 +171,6 @@ public class WebConnectionInfo {
return dataSourceContainer.isConnected();
}
@Property
public boolean isTemplate() {
return dataSourceContainer.isTemplate();
}
@Property
public boolean isProvided() {
return dataSourceContainer.isProvided();
@@ -357,7 +357,6 @@ type ConnectionInfo {
properties: Object
template: Boolean! @deprecated
connected: Boolean!
provided: Boolean!
readOnly: Boolean!
@@ -502,8 +501,6 @@ input ConnectionConfig {
name: String
description: String
# ID of template connection
templateId: ID @deprecated
# ID of database driver
driverId: ID
@@ -529,8 +526,6 @@ input ConnectionConfig {
# Return auto-commit connection state
autocommit: Boolean
# Return template connection state
template: Boolean @deprecated
# Return read-only connection state
readOnly: Boolean
@@ -590,9 +585,6 @@ extend type Query {
# Return list of user connections
userConnections( projectId: ID, id: ID, projectIds: [ID!] ): [ ConnectionInfo! ]!
# Return list of template connections by project ID
templateConnections( projectId: ID ): [ ConnectionInfo! ]! @deprecated
# List of connection folders
connectionFolders( projectId: ID, path: ID ): [ ConnectionFolderInfo! ]!
@@ -632,9 +624,6 @@ extend type Mutation {
# Delete specified connection
deleteConnection( id: ID!, projectId: ID ): Boolean!
# Create new custom connection from template
createConnectionFromTemplate( templateId: ID!, projectId: ID!, connectionName: String ): ConnectionInfo! @deprecated
# Create new folder for connections
createConnectionFolder(parentFolderPath: ID, folderName: String!, projectId: ID ): ConnectionFolderInfo!
@@ -109,13 +109,7 @@ public class WebServiceUtils extends WebCommonUtils {
@NotNull
public static DBPDataSourceContainer createConnectionFromConfig(WebConnectionConfig config, DBPDataSourceRegistry registry) throws DBWebException {
DBPDataSourceContainer newDataSource;
if (!CommonUtils.isEmpty(config.getTemplateId())) {
DBPDataSourceContainer tpl = registry.getDataSource(config.getTemplateId());
if (tpl == null) {
throw new DBWebException("Template connection '" + config.getTemplateId() + "' not found");
}
newDataSource = registry.createDataSource(tpl);
} else if (!CommonUtils.isEmpty(config.getDriverId())) {
if (!CommonUtils.isEmpty(config.getDriverId())) {
String driverId = config.getDriverId();
if (CommonUtils.isEmpty(driverId)) {
throw new DBWebException("Driver not specified");
@@ -138,7 +132,6 @@ public class WebServiceUtils extends WebCommonUtils {
if (config.getFolder() != null) {
newDataSource.setFolder(registry.getFolder(config.getFolder()));
}
((DataSourceDescriptor)newDataSource).setTemplate(config.isTemplate());
ServletApplication app = ServletAppUtils.getServletApplication();
if (app instanceof WebApplication webApplication) {
@@ -72,10 +72,6 @@ public class ConnectionControllerCE implements ConnectionController {
webSession.addInfoMessage("Create new connection");
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
// we don't need to save credentials for templates
if (connectionConfig.isTemplate()) {
connectionConfig.setSaveCredentials(false);
}
DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
if (CommonUtils.isEmpty(newDataSource.getName())) {
@@ -70,13 +70,6 @@ public interface DBWServiceCore extends DBWService {
List<WebConnectionFolderInfo> getConnectionFolders(
@NotNull WebSession webSession, @Nullable String projectId, @Nullable String id) throws DBWebException;
@Deprecated
@WebAction
List<WebDataSourceConfig> getTemplateDataSources() throws DBWebException;
@WebAction
List<WebConnectionInfo> getTemplateConnections(@NotNull WebSession webSession, @Nullable String projectId) throws DBWebException;
@WebAction(authRequired = false)
String[] getSessionPermissions(@NotNull WebSession webSession) throws DBWebException;
@@ -151,14 +144,6 @@ public interface DBWServiceCore extends DBWService {
@Nullable @WebObjectId String projectId,
@NotNull String connectionId) throws DBWebException;
@WebAction
@Deprecated
WebConnectionInfo createConnectionFromTemplate(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String templateId,
@Nullable String connectionName) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
WebConnectionInfo copyConnectionFromNode(
@NotNull WebSession webSession,
@@ -59,11 +59,8 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
.dataFetcher("driverList", env -> getService(env).getDriverList(getWebSession(env), env.getArgument("id")))
.dataFetcher("authModels", env -> getService(env).getAuthModels(getWebSession(env)))
.dataFetcher("networkHandlers", env -> getService(env).getNetworkHandlers(getWebSession(env)))
.dataFetcher("templateDataSources", env -> getService(env).getTemplateDataSources())
.dataFetcher("userConnections", env -> getService(env).getUserConnections(
getWebSession(env), getProjectReference(env), env.getArgument("id"), env.getArgument("projectIds")))
.dataFetcher("templateConnections", env -> getService(env).getTemplateConnections(
getWebSession(env), getProjectReference(env)))
.dataFetcher("connectionFolders", env -> getService(env).getConnectionFolders(
getWebSession(env), getProjectReference(env), env.getArgument("path")))
@@ -113,11 +110,6 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
getWebSession(env), getProjectReference(env), getConnectionConfig(env)))
.dataFetcher("deleteConnection", env -> getService(env).deleteConnection(
getWebSession(env), getProjectReference(env), env.getArgument("id")))
.dataFetcher("createConnectionFromTemplate", env -> getService(env).createConnectionFromTemplate(
getWebSession(env),
getProjectReference(env),
env.getArgument("templateId"),
env.getArgument("connectionName")))
.dataFetcher("copyConnectionFromNode", env -> getService(env).copyConnectionFromNode(
getWebSession(env),
getProjectReference(env),
@@ -132,58 +132,6 @@ public class WebServiceCore implements DBWServiceCore {
.toList();
}
@Deprecated
@Override
public List<WebDataSourceConfig> getTemplateDataSources() throws DBWebException {
List<WebDataSourceConfig> result = new ArrayList<>();
DBPDataSourceRegistry dsRegistry = WebServiceUtils.getGlobalDataSourceRegistry();
for (DBPDataSourceContainer ds : dsRegistry.getDataSources()) {
if (ds.isTemplate()) {
if (WebAppUtils.getWebApplication().getDriverRegistry().getApplicableDrivers().contains(ds.getDriver())) {
result.add(new WebDataSourceConfig(ds));
} else {
log.debug("Template datasource '" + ds.getName() + "' ignored - driver is not applicable");
}
}
}
return result;
}
@Override
public List<WebConnectionInfo> getTemplateConnections(
@NotNull WebSession webSession, @Nullable String projectId
) throws DBWebException {
if (webSession.getApplication().isDistributed()) {
return List.of();
}
List<WebConnectionInfo> result = new ArrayList<>();
if (projectId == null) {
for (WebSessionProjectImpl project : webSession.getAccessibleProjects()) {
getTemplateConnectionsFromProject(webSession, project, result);
}
} else {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
getTemplateConnectionsFromProject(webSession, project, result);
}
return result;
}
private void getTemplateConnectionsFromProject(
@NotNull WebSession webSession,
@NotNull WebSessionProjectImpl project,
List<WebConnectionInfo> result
) {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
for (DBPDataSourceContainer ds : registry.getDataSources()) {
if (ds.isTemplate() && WebAppUtils.getWebApplication().getDriverRegistry().getApplicableDrivers().contains(ds.getDriver())) {
result.add(new WebConnectionInfo(webSession, ds));
}
}
}
@Override
public List<WebConnectionFolderInfo> getConnectionFolders(
@NotNull WebSession webSession, @Nullable String projectId, @Nullable String id
@@ -401,44 +349,6 @@ public class WebServiceCore implements DBWServiceCore {
}
@Override
@Deprecated
public WebConnectionInfo createConnectionFromTemplate(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String templateId,
@Nullable String connectionName
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
DBPDataSourceRegistry templateRegistry = project.getDataSourceRegistry();
DBPDataSourceContainer dataSourceTemplate = templateRegistry.getDataSource(templateId);
if (dataSourceTemplate == null) {
throw new DBWebException("Template data source '" + templateId + "' not found");
}
DBPDataSourceRegistry projectRegistry = webSession.getSingletonProject().getDataSourceRegistry();
DBPDataSourceContainer newDataSource = projectRegistry.createDataSource(dataSourceTemplate);
ServletApplication app = ServletAppUtils.getServletApplication();
if (app instanceof WebApplication webApplication) {
((DataSourceDescriptor) newDataSource).setNavigatorSettings(
webApplication.getAppConfiguration().getDefaultNavigatorSettings());
}
if (!CommonUtils.isEmpty(connectionName)) {
newDataSource.setName(connectionName);
}
try {
projectRegistry.addDataSource(newDataSource);
projectRegistry.checkForErrors();
} catch (DBException e) {
throw new DBWebException(e.getMessage(), e);
}
return project.addConnection(newDataSource);
}
@Override
public WebConnectionInfo copyConnectionFromNode(
@NotNull WebSession webSession,
@@ -255,7 +255,6 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
makeObservable<this, 'nodeIdMap'>(this, {
nodeIdMap: observable,
createFromTemplate: action,
create: action,
createFromNode: action,
add: action,
@@ -357,17 +356,6 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
return this.add(connection);
}
async createFromTemplate(projectId: string, templateId: string, connectionName: string): Promise<Connection> {
const { connection } = await this.graphQLService.sdk.createConnectionFromTemplate({
projectId,
templateId,
connectionName,
...this.getDefaultIncludes(),
...this.getIncludesMap(),
});
return this.add(connection);
}
// addList(connections: Connection[]): Connection[] {
// const newConnections = connections.filter(connection => !this.has({
// projectId: connection.projectId,
@@ -1,11 +1,8 @@
export default [
['core_connections_connections_settings_group', 'Verbindungen'],
['connections_administration_new_connection', 'Neue Verbindung'],
['connections_administration_connection_access_empty', 'Keine verfügbaren Benutzer und Teams'],
['connections_administration_configuration_wizard_step_title', 'Datenbankverbindungen'],
['connections_administration_configuration_wizard_step_description', 'Datenbankverbindungen hinzufügen'],
['connections_administration_configuration_wizard_title', 'Datenbankverbindungen hinzufügen'],
['connections_administration_connection_no_information', 'Keine Information verfügbar'],
['core_connections_new_connection', 'Neue Verbindung'],
['core_connections_connection_access_empty', 'Keine verfügbaren Benutzer und Teams'],
['core_connections_connection_no_information', 'Keine Information verfügbar'],
['connections_administration_delete_confirmation', 'Sie werden diese Verbindungen löschen: '],
['connections_administration_tools_delete_tooltip', 'Löschen Sie ausgewählte Verbindungen'],
['connections_administration_tools_refresh_success', 'Die Verbindungsliste wurde aktualisiert'],
@@ -52,7 +49,6 @@ export default [
['core_connections_settings_disable', 'Disable'],
['core_connections_settings_disable_description', 'Disable the ability to create new connections'],
['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'],
['core_connections_connection_driver_not_installed', 'Driver is not installed'],
['core_connections_connection_temporary', 'Temporary connection'],
['core_connections_connection_create_success', 'Connection was created'],
@@ -1,26 +1,12 @@
export default [
['core_connections_connections_settings_group', 'Connections'],
['connections_administration_item', 'Connection Templates'],
['connections_administration_connection_create', 'Add Database Template'],
['connections_administration_search_database_tip', "Type your hosts here, e.g. 'localhost host1.myhost.com 192.168.0.1' and press Enter"],
['connections_administration_new_connection', 'New connection'],
['connections_administration_connection_create_error', 'Create connection error'],
['connections_administration_connection_save_error', 'Save connection error'],
['connections_administration_connection_access_empty', 'No available users and teams'],
['connections_administration_configuration_wizard_step_title', 'Database connections'],
['connections_administration_configuration_wizard_step_description', 'Add database connections'],
['connections_administration_configuration_wizard_title', 'Add database connections'],
[
'connections_administration_configuration_wizard_message',
'Here you can create database connections manually or using a database server search.\nYou can skip this step and configure the connections later.',
],
['connections_administration_connection_no_information', 'No information available'],
['connections_administration_delete_confirmation', "You're going to delete these connections: "],
['connections_administration_tools_add_tooltip', 'Add new template'],
['connections_administration_tools_refresh_tooltip', 'Refresh connection list'],
['connections_administration_tools_delete_tooltip', 'Delete selected connections'],
['connections_administration_tools_refresh_success', 'Connection list was refreshed'],
['connections_administration_tools_refresh_fail', 'Connection list refresh failed'],
['core_connections_search_database_tip', "Type your hosts here, e.g. 'localhost host1.myhost.com 192.168.0.1' and press Enter"],
['core_connections_new_connection', 'New connection'],
['core_connections_connection_create_error', 'Create connection error'],
['core_connections_connection_save_error', 'Save connection error'],
['core_connections_connection_access_empty', 'No available users and teams'],
['core_connections_connection_no_information', 'No information available'],
['connections_database_authentication', 'Database Authentication'],
['connections_connection_edit_not_own_deny', 'You have no access to edit this connection.'],
['connections_connection_connect', 'Connect'],
@@ -58,7 +44,6 @@ export default [
['connections_connection_configuration', 'Configuration'],
['connections_connection_host', 'Host'],
['connections_connection_port', 'Port'],
['connections_connection_template', 'Template'],
['core_connections_connection_create_success', 'Connection was created'],
['core_connections_connection_update_success', 'Connection was updated'],
['connections_connection_test', 'Test'],
@@ -98,7 +83,6 @@ export default [
['core_connections_settings_disable', 'Disable'],
['core_connections_settings_disable_description', 'Disable the ability to create new connections'],
['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'],
['core_connections_connection_driver_not_installed', 'Driver is not installed'],
['core_connections_connection_temporary', 'Temporary connection'],
];
@@ -1,29 +1,11 @@
export default [
['core_connections_connections_settings_group', 'Connexions'],
['connections_administration_item', 'Modèles de connexion'],
['connections_administration_connection_create', 'Ajouter un modèle de base de données'],
[
'connections_administration_search_database_tip',
"Saisissez vos hôtes ici, par exemple 'localhost host1.myhost.com 192.168.0.1' et appuyez sur Entrée",
],
['connections_administration_new_connection', 'Nouvelle connexion'],
['connections_administration_connection_create_error', 'Erreur de création de connexion'],
['connections_administration_connection_save_error', 'Erreur de sauvegarde de connexion'],
['connections_administration_connection_access_empty', 'Aucun utilisateur et équipe disponibles'],
['connections_administration_configuration_wizard_step_title', 'Connexions de base de données'],
['connections_administration_configuration_wizard_step_description', 'Ajouter des connexions de base de données'],
['connections_administration_configuration_wizard_title', 'Ajouter des connexions de base de données'],
[
'connections_administration_configuration_wizard_message',
'Ici, vous pouvez créer des connexions de base de données manuellement ou en utilisant une recherche de serveur de base de données.\nVous pouvez passer cette étape et configurer les connexions plus tard.',
],
['connections_administration_connection_no_information', 'Aucune information disponible'],
['connections_administration_delete_confirmation', 'Vous allez supprimer ces connexions : '],
['connections_administration_tools_add_tooltip', 'Ajouter un nouveau modèle'],
['connections_administration_tools_refresh_tooltip', 'Actualiser la liste des connexions'],
['connections_administration_tools_delete_tooltip', 'Supprimer les connexions sélectionnées'],
['connections_administration_tools_refresh_success', 'La liste des connexions a été actualisée'],
['connections_administration_tools_refresh_fail', "Échec de l'actualisation de la liste des connexions"],
['core_connections_search_database_tip', "Saisissez vos hôtes ici, par exemple 'localhost host1.myhost.com 192.168.0.1' et appuyez sur Entrée"],
['core_connections_new_connection', 'Nouvelle connexion'],
['core_connections_connection_create_error', 'Erreur de création de connexion'],
['core_connections_connection_save_error', 'Erreur de sauvegarde de connexion'],
['core_connections_connection_access_empty', 'Aucun utilisateur et équipe disponibles'],
['core_connections_connection_no_information', 'Aucune information disponible'],
['connections_database_authentication', 'Authentification de la base de données'],
['connections_connection_edit_not_own_deny', "Vous n'avez pas accès pour modifier cette connexion."],
['connections_connection_connect', 'Connecter'],
@@ -68,7 +50,6 @@ export default [
['connections_connection_host', 'Hôte'],
['connections_connection_port', 'Port'],
['connections_connection_read_only', 'Read-only connection'],
['connections_connection_template', 'Modèle'],
['core_connections_connection_create_success', 'Connection was created'],
['core_connections_connection_update_success', 'Connection was updated'],
['connections_connection_test', 'Tester'],
@@ -107,7 +88,6 @@ export default [
['core_connections_settings_disable', 'Disable'],
['core_connections_settings_disable_description', 'Disable the ability to create new connections'],
['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'],
['core_connections_connection_driver_not_installed', 'Driver is not installed'],
['core_connections_connection_temporary', 'Temporary connection'],
];
@@ -1,24 +1,10 @@
export default [
['core_connections_connections_settings_group', 'Connections'],
['connections_administration_item', 'Connection Templates'],
['connections_administration_connection_create', 'Add Database Template'],
['connections_administration_search_database_tip', "Digita gli hosts qui, p.e. 'localhost host1.myhost.com 192.168.0.1' e premi Invio"],
['connections_administration_new_connection', 'Nuova Connessione'],
['connections_administration_connection_create_error', 'Errore di creazione connessione'],
['connections_administration_connection_save_error', 'Errore di salvataggio connessione'],
['connections_administration_configuration_wizard_step_title', 'Connessioni ai Database'],
['connections_administration_configuration_wizard_step_description', 'Aggiungi connessione al database'],
['connections_administration_configuration_wizard_title', 'Aggiungi connessione al database'],
[
'connections_administration_configuration_wizard_message',
'Qui puoi creare connessioni ai database manualmente oppure usando una ricerca di un database server.\nPuoi saltare questo step e configurare le connessioni dopo.',
],
['connections_administration_connection_no_information', 'Nessuna informazione disponibile'],
['connections_administration_tools_add_tooltip', 'Add new template'],
['connections_administration_tools_refresh_tooltip', 'Ricarica la lista di connessioni'],
['connections_administration_tools_delete_tooltip', 'Elimina le connessioni selezionate'],
['connections_administration_tools_refresh_success', 'Lista delle connessioni ricaricata'],
['connections_administration_tools_refresh_fail', 'Errore durante la ricarica della lista delle connessioni'],
['core_connections_search_database_tip', "Digita gli hosts qui, p.e. 'localhost host1.myhost.com 192.168.0.1' e premi Invio"],
['core_connections_new_connection', 'Nuova Connessione'],
['core_connections_connection_create_error', 'Errore di creazione connessione'],
['core_connections_connection_save_error', 'Errore di salvataggio connessione'],
['core_connections_connection_no_information', 'Nessuna informazione disponibile'],
['connections_database_authentication', 'Autenticazione al Database'],
['connections_connection_edit_not_own_deny', 'Questa connessione è stata creata da un amministratore. Non può essere modificata.'],
['connections_connection_connect', 'Collega'],
@@ -56,7 +42,6 @@ export default [
['connections_connection_configuration', 'Configuration'],
['connections_connection_host', 'Host'],
['connections_connection_port', 'Porta'],
['connections_connection_template', 'Template'],
['core_connections_connection_create_success', 'Connection was created'],
['core_connections_connection_update_success', 'Connection was updated'],
['connections_connection_test', 'Prova la connessione'],
@@ -96,7 +81,6 @@ export default [
['core_connections_settings_disable', 'Disable'],
['core_connections_settings_disable_description', 'Disable the ability to create new connections'],
['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'],
['core_connections_connection_driver_not_installed', 'Driver is not installed'],
['core_connections_connection_temporary', 'Temporary connection'],
];
@@ -1,20 +1,11 @@
export default [
['core_connections_connections_settings_group', 'Подключения'],
['connections_administration_item', 'Шаблоны подключений'],
['connections_administration_connection_create', 'Создание шаблона подключения'],
['connections_administration_search_database_tip', "Укажите ваши хосты, например 'localhost host1.myhost.com 192.168.0.1' и нажмите Enter"],
['connections_administration_new_connection', 'Создание подключения'],
['connections_administration_connection_create_error', 'Ошибка при создании подключения'],
['connections_administration_connection_save_error', 'Ошибка при сохранении подключения'],
['connections_administration_connection_access_empty', 'Нет доступных пользователей и подключений'],
['connections_administration_configuration_wizard_step_title', 'Подключения к базам'],
['connections_administration_configuration_wizard_step_description', 'Подключения к базам'],
[
'connections_administration_configuration_wizard_message',
'Here you can create database connections manually or using a database server search.\nYou can skip this step and configure the connections later.',
],
['connections_administration_connection_no_information', 'Нет доступной информации'],
['connections_administration_delete_confirmation', 'Вы собираетесь удалить следующие подключения: '],
['core_connections_search_database_tip', "Укажите ваши хосты, например 'localhost host1.myhost.com 192.168.0.1' и нажмите Enter"],
['core_connections_new_connection', 'Создание подключения'],
['core_connections_connection_create_error', 'Ошибка при создании подключения'],
['core_connections_connection_save_error', 'Ошибка при сохранении подключения'],
['core_connections_connection_access_empty', 'Нет доступных пользователей и подключений'],
['core_connections_connection_no_information', 'Нет доступной информации'],
['connections_administration_tools_add_tooltip', 'Добавить новый шаблон подключения'],
['connections_administration_tools_refresh_tooltip', 'Обновить список подключений'],
['connections_administration_tools_delete_tooltip', 'Удалить выбранные подключения'],
@@ -62,7 +53,6 @@ export default [
['connections_connection_configuration', 'Конфигурация'],
['connections_connection_host', 'Хост'],
['connections_connection_port', 'Порт'],
['connections_connection_template', 'Шаблон'],
['core_connections_connection_create_success', 'Подключение создано'],
['core_connections_connection_update_success', 'Подключение обновлено'],
['connections_connection_test', 'Тест'],
@@ -99,7 +89,6 @@ export default [
['core_connections_settings_disable', 'Отключить'],
['core_connections_settings_disable_description', 'Отключить возможность создания новых подключений'],
['connections_templates_deprecated_message', 'Шаблоны подключений больше не поддерживаются и будут удалены в будущих релизах'],
['core_connections_connection_driver_not_installed', 'Драйвер не установлен'],
['core_connections_connection_temporary', 'Временное подключение'],
];
@@ -1,25 +1,10 @@
export default [
['core_connections_connections_settings_group', '连接'],
['connections_administration_item', '连接模板'],
['connections_administration_connection_create', '添加数据库模板'],
['connections_administration_search_database_tip', '在此处输入您的主机,例如“localhost host1.myhost.com 192.168.0.1”然后按 Enter'],
['connections_administration_new_connection', '新连接'],
['connections_administration_connection_create_error', '创建连接失败'],
['connections_administration_connection_save_error', '保存链接失败'],
['connections_administration_configuration_wizard_step_title', '数据库连接'],
['connections_administration_configuration_wizard_step_description', '添加数据库连接'],
['connections_administration_configuration_wizard_title', '添加数据库连接'],
[
'connections_administration_configuration_wizard_message',
'您可以在此处手动创建数据库连接或使用数据库服务器搜索。您可以跳过此步骤并稍后配置连接。',
],
['connections_administration_connection_no_information', '没有可用信息'],
['connections_administration_delete_confirmation', '您将删除这些连接:'],
['connections_administration_tools_add_tooltip', 'Add new template'],
['connections_administration_tools_refresh_tooltip', '刷新连接列表'],
['connections_administration_tools_delete_tooltip', '删除选中的连接'],
['connections_administration_tools_refresh_success', '连接列表已刷新'],
['connections_administration_tools_refresh_fail', '连接列表刷新失败'],
['core_connections_search_database_tip', '在此处输入您的主机,例如“localhost host1.myhost.com 192.168.0.1”然后按 Enter'],
['core_connections_new_connection', '新连接'],
['core_connections_connection_create_error', '创建连接失败'],
['core_connections_connection_save_error', '保存链接失败'],
['core_connections_connection_no_information', '没有可用信息'],
['connections_database_authentication', '数据库认证'],
['connections_connection_edit_not_own_deny', '此连接由管理员创建。它无法更新。'],
['connections_connection_connect', '连接'],
@@ -51,7 +36,6 @@ export default [
['connections_connection_configuration', '配置'],
['connections_connection_host', '主机'],
['connections_connection_port', '端口'],
['connections_connection_template', '模板'],
['core_connections_connection_create_success', 'Connection was created'],
['core_connections_connection_update_success', 'Connection was updated'],
['connections_connection_test', '测试连接'],
@@ -88,7 +72,6 @@ export default [
['core_connections_settings_disable', 'Disable'],
['core_connections_settings_disable_description', 'Disable the ability to create new connections'],
['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'],
['core_connections_connection_driver_not_installed', 'Driver is not installed'],
['core_connections_connection_temporary', 'Temporary connection'],
];
@@ -1,16 +0,0 @@
mutation createConnectionFromTemplate(
$projectId: ID!
$templateId: ID!
$connectionName: String!
$includeAuthProperties: Boolean!
$includeNetworkHandlersConfig: Boolean!
$includeCredentialsSaved: Boolean!
$includeAuthNeeded: Boolean!
$includeProperties: Boolean!
$includeProviderProperties: Boolean!
$customIncludeOptions: Boolean!
) {
connection: createConnectionFromTemplate(projectId: $projectId, templateId: $templateId, connectionName: $connectionName) {
...DatabaseConnection
}
}
@@ -1,14 +0,0 @@
query getTemplateConnections(
$projectId: ID
$includeAuthProperties: Boolean!
$includeNetworkHandlersConfig: Boolean!
$includeCredentialsSaved: Boolean!
$includeAuthNeeded: Boolean!
$includeProperties: Boolean!
$includeProviderProperties: Boolean!
$customIncludeOptions: Boolean!
) {
connections: templateConnections(projectId: $projectId) {
...DatabaseConnection
}
}
@@ -7,7 +7,6 @@ fragment DatabaseConnection on ConnectionInfo {
keepAliveInterval
autocommit
template
connected
readOnly
@@ -11,7 +11,6 @@ fragment DatabaseConnectionCustomOptions on ConnectionInfo {
name
description
folder
template
driverId
keepAliveInterval
autocommit
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -38,13 +38,13 @@ export const DatabaseList = observer<Props>(function DatabaseList({ databases, h
}
}, [onSearch]);
const placeholderMessage = isSearched ? 'connections_not_found' : 'connections_administration_search_database_tip';
const placeholderMessage = isSearched ? 'connections_not_found' : 'core_connections_search_database_tip';
return (
<Form ref={focusedRef} className={s(styles, { form: true }, className)} onSubmit={onSearch}>
<ItemListSearch
value={hosts}
placeholder={translate('connections_administration_search_database_tip')}
placeholder={translate('core_connections_search_database_tip')}
disabled={disabled}
permanentSearchIcon
onChange={onChange}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -1,17 +0,0 @@
# dependencies
/node_modules
# testing
/coverage
# production
/lib
# misc
.DS_Store
.env*
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
@@ -1,49 +0,0 @@
{
"name": "@cloudbeaver/plugin-connection-template",
"type": "module",
"sideEffects": [
"src/**/*.css",
"src/**/*.scss",
"public/**/*"
],
"version": "0.1.0",
"description": "",
"license": "Apache-2.0",
"exports": {
".": "./lib/index.js"
},
"scripts": {
"build": "tsc -b",
"clean": "rimraf --glob lib",
"lint": "eslint ./src/ --ext .ts,.tsx",
"validate-dependencies": "core-cli-validate-dependencies"
},
"dependencies": {
"@cloudbeaver/core-authentication": "workspace:*",
"@cloudbeaver/core-blocks": "workspace:*",
"@cloudbeaver/core-connections": "workspace:*",
"@cloudbeaver/core-di": "workspace:*",
"@cloudbeaver/core-dialogs": "workspace:*",
"@cloudbeaver/core-events": "workspace:*",
"@cloudbeaver/core-localization": "workspace:*",
"@cloudbeaver/core-projects": "workspace:*",
"@cloudbeaver/core-resource": "workspace:*",
"@cloudbeaver/core-root": "workspace:*",
"@cloudbeaver/core-sdk": "workspace:*",
"@cloudbeaver/core-utils": "workspace:*",
"@cloudbeaver/core-view": "workspace:*",
"@cloudbeaver/plugin-connections": "workspace:*",
"mobx": "^6",
"mobx-react-lite": "^4",
"react": "^19",
"react-dom": "^19",
"tslib": "^2"
},
"devDependencies": {
"@cloudbeaver/core-cli": "workspace:*",
"@cloudbeaver/tsconfig": "workspace:*",
"@types/react": "^19",
"typescript": "^5",
"typescript-plugin-css-modules": "^5"
}
}
@@ -1,12 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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_CONNECTION_TEMPLATE = createAction('connection-template', {
label: 'plugin_connection_template_action_connection_template_label',
});
@@ -1,25 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.submittingForm,
.center {
display: flex;
flex: 1;
margin: auto;
}
.center {
box-sizing: border-box;
flex-direction: column;
align-items: center;
justify-content: center;
}
.connectionAuthenticationFormLoader {
align-content: center;
}
.errorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
}
@@ -1,97 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import {
CommonDialogBody,
CommonDialogFooter,
CommonDialogHeader,
CommonDialogWrapper,
ErrorMessage,
Form,
InfoItem,
s,
useAdministrationSettings,
useErrorDetails,
useFocus,
useS,
useTranslate,
} from '@cloudbeaver/core-blocks';
import type { DialogComponent } from '@cloudbeaver/core-dialogs';
import { ConnectionAuthenticationFormLoader } from '@cloudbeaver/plugin-connections';
import style from './ConnectionDialog.module.css';
import { ConnectionDialogFooter } from './ConnectionDialogFooter.js';
import { ConnectionStep } from './EConnectionStep.js';
import { TemplateConnectionSelector } from './TemplateConnectionSelector/TemplateConnectionSelector.js';
import { useConnectionDialog } from './useConnectionDialog.js';
export const ConnectionDialog: DialogComponent<null, null> = observer(function ConnectionDialog({ rejectDialog }) {
const styles = useS(style);
const translate = useTranslate();
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
const { credentialsSavingEnabled } = useAdministrationSettings();
const dialog = useConnectionDialog(rejectDialog);
const errorDetails = useErrorDetails(dialog.connectException);
const subTitle =
dialog.step === ConnectionStep.Connection ? (
dialog.template?.name
) : (
<InfoItem info={translate('connections_templates_deprecated_message')} compact />
);
return (
<CommonDialogWrapper size="large" fixedSize={dialog.step === ConnectionStep.ConnectionTemplateSelect}>
<CommonDialogHeader
title="plugin_connections_new_connection_dialog_title"
subTitle={subTitle}
icon={dialog.driver?.icon}
onReject={rejectDialog}
/>
<CommonDialogBody noBodyPadding={dialog.step === ConnectionStep.ConnectionTemplateSelect} noOverflow>
{dialog.step === ConnectionStep.ConnectionTemplateSelect && <TemplateConnectionSelector onSelect={dialog.selectTemplate} />}
{dialog.step === ConnectionStep.Connection &&
(!dialog.authModelId ? (
<center className={s(styles, { center: true })}>{dialog.processing && translate('plugin_connection_template_connecting_message')}</center>
) : (
<Form ref={focusedRef} className={s(styles, { submittingForm: true })} onSubmit={dialog.connect}>
<ConnectionAuthenticationFormLoader
config={dialog.config}
authModelId={dialog.authModelId}
networkHandlers={dialog.networkHandlers}
formId={dialog.template?.id}
allowSaveCredentials={credentialsSavingEnabled}
disabled={dialog.processing}
hideFeatures={['nonSecuredProperty']}
projectId={dialog.template?.projectId ?? null}
className={s(styles, { connectionAuthenticationFormLoader: true })}
/>
</Form>
))}
</CommonDialogBody>
{dialog.step === ConnectionStep.Connection && (
<CommonDialogFooter>
{dialog.connectException && (
<ErrorMessage
text={errorDetails.message ?? translate('core_blocks_exception_message_error_message')}
hasDetails={errorDetails.hasDetails}
className={s(styles, { errorMessage: true })}
onShowDetails={errorDetails.open}
/>
)}
<ConnectionDialogFooter
isConnecting={dialog.processing}
onBack={() => dialog.setStep(ConnectionStep.ConnectionTemplateSelect)}
onConnect={dialog.connect}
/>
</CommonDialogFooter>
)}
</CommonDialogWrapper>
);
});
@@ -1,19 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.controls {
display: flex;
flex: 1;
height: 100%;
align-items: center;
margin: auto;
gap: 24px;
}
.fill {
flex: 1;
}
@@ -1,34 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { Button, useS, useTranslate } from '@cloudbeaver/core-blocks';
import style from './ConnectionDialogFooter.module.css';
interface Props {
isConnecting: boolean;
onConnect: () => void;
onBack: () => void;
}
export const ConnectionDialogFooter = observer<Props>(function ConnectionDialogFooter({ isConnecting, onConnect, onBack }) {
const styles = useS(style);
const translate = useTranslate();
return (
<div className={styles['controls']}>
<div className={styles['fill']} />
<Button type="button" mod={['outlined']} disabled={isConnecting} onClick={onBack}>
{translate('ui_stepper_back')}
</Button>
<Button type="button" mod={['unelevated']} disabled={isConnecting} onClick={onConnect}>
{isConnecting ? translate('ui_processing_connecting') : translate('connections_connection_connect')}
</Button>
</div>
);
});
@@ -1,11 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
export enum ConnectionStep {
ConnectionTemplateSelect,
Connection,
}
@@ -1,13 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.staticImage {
box-sizing: border-box;
width: 24px;
max-height: 24px;
}
@@ -1,35 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import { ListItem, ListItemDescription, ListItemIcon, ListItemName, s, StaticImage, useS } from '@cloudbeaver/core-blocks';
import type { Connection, DBDriver } from '@cloudbeaver/core-connections';
import styles from './TemplateConnectionItem.module.css';
interface Props {
template: Connection;
dbDriver?: DBDriver;
onSelect: (connectionId: string) => void;
}
export const TemplateConnectionItem = observer<Props>(function TemplateConnectionItem({ template, dbDriver, onSelect }) {
const select = useCallback(() => onSelect(template.id), [template]);
const style = useS(styles);
return (
<ListItem onClick={select}>
<ListItemIcon>
<StaticImage className={s(style, { staticImage: true })} icon={dbDriver?.icon} />
</ListItemIcon>
<ListItemName>{template.name}</ListItemName>
<ListItemDescription title={template.description}>{template.description}</ListItemDescription>
</ListItem>
);
});
@@ -1,57 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { useMemo, useState } from 'react';
import { ItemList, ItemListSearch, useResource } from '@cloudbeaver/core-blocks';
import { DBDriverResource } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
import { TemplateConnectionsResource } from '../../TemplateConnectionsResource.js';
import { TemplateConnectionsService } from '../../TemplateConnectionsService.js';
import { TemplateConnectionItem } from './TemplateConnectionItem.js';
interface Props {
className?: string;
onSelect: (dbSourceId: string) => void;
}
export const TemplateConnectionSelector = observer<Props>(function TemplateConnectionSelector({ className, onSelect }) {
useResource(TemplateConnectionSelector, ProjectInfoResource, CachedMapAllKey, { forceSuspense: true });
useResource(TemplateConnectionSelector, TemplateConnectionsResource, undefined, { forceSuspense: true });
const dbDriverResource = useResource(TemplateConnectionSelector, DBDriverResource, CachedMapAllKey);
const templateConnectionsService = useService(TemplateConnectionsService);
const templateConnections = templateConnectionsService.projectTemplates;
const [search, setSearch] = useState('');
const filteredTemplateConnections = useMemo(() => {
if (!search) {
return templateConnections;
}
return templateConnections.filter(template => template.name.toUpperCase().includes(search.toUpperCase()));
}, [search, templateConnections]);
return (
<>
<ItemListSearch onChange={setSearch} />
<ItemList className={className}>
{filteredTemplateConnections.map(template => (
<TemplateConnectionItem
key={template.id}
template={template}
dbDriver={dbDriverResource.resource.get(template.driverId)}
onSelect={onSelect}
/>
))}
</ItemList>
</>
);
});
@@ -1,208 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { action, computed, observable } from 'mobx';
import { AuthProviderService } from '@cloudbeaver/core-authentication';
import { useObservableRef } from '@cloudbeaver/core-blocks';
import {
type Connection,
ConnectionInfoProjectKey,
ConnectionInfoResource,
type ConnectionInitConfig,
createConnectionParam,
type DBDriver,
DBDriverResource,
USER_NAME_PROPERTY_ID,
} from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { ProjectsService } from '@cloudbeaver/core-projects';
import { NetworkHandlerAuthType } from '@cloudbeaver/core-sdk';
import { getUniqueName } from '@cloudbeaver/core-utils';
import type { IConnectionAuthenticationConfig } from '@cloudbeaver/plugin-connections';
import { TemplateConnectionsService } from '../TemplateConnectionsService.js';
import { ConnectionStep } from './EConnectionStep.js';
interface IState {
readonly networkHandlers: string[];
readonly authModelId: string | null;
step: ConnectionStep;
driver: DBDriver | null;
template: Connection | null;
config: IConnectionAuthenticationConfig;
processing: boolean;
connectException: Error | null;
connect: () => Promise<void>;
setStep: (step: ConnectionStep) => void;
getConfig: (projectId: string, connectionId: string) => ConnectionInitConfig;
selectTemplate: (templateId: string) => Promise<void>;
}
function getDefaultConfig(): IConnectionAuthenticationConfig {
return {
credentials: {},
networkHandlersConfig: [],
saveCredentials: false,
};
}
export function useConnectionDialog(onConnect?: () => void) {
const notificationService = useService(NotificationService);
const connectionInfoResource = useService(ConnectionInfoResource);
const templateConnectionsService = useService(TemplateConnectionsService);
const projectsService = useService(ProjectsService);
const authProviderService = useService(AuthProviderService);
const dbDriverResource = useService(DBDriverResource);
const state: IState = useObservableRef(
() => ({
get networkHandlers() {
return this.template?.networkHandlersConfig?.filter(handler => handler.enabled && !handler.savePassword).map(handler => handler.id) || [];
},
get authModelId() {
if (this.template?.authNeeded === false || this.driver?.anonymousAccess === true) {
return null;
}
return this.template?.authModel || this.driver?.defaultAuthModel || null;
},
step: ConnectionStep.ConnectionTemplateSelect,
template: null as Connection | null,
driver: null as DBDriver | null,
processing: false,
connectException: null,
config: getDefaultConfig(),
async connect() {
if (this.processing || !this.template || !this.projectsService.userProject) {
return;
}
try {
this.connectException = null;
this.processing = true;
const connections = await this.connectionInfoResource.load(ConnectionInfoProjectKey(this.projectsService.userProject.id));
const connectionNames = connections.map(connection => connection.name);
const uniqueConnectionName = getUniqueName(this.template.name || 'Template connection', connectionNames);
const connection = await this.connectionInfoResource.createFromTemplate(this.template.projectId, this.template.id, uniqueConnectionName);
if (connection.requiredAuth) {
const state = await this.authProviderService.requireProvider(connection.requiredAuth);
if (!state) {
this.setStep(ConnectionStep.ConnectionTemplateSelect);
await this.connectionInfoResource.deleteConnection(createConnectionParam(connection));
return;
}
}
try {
await this.connectionInfoResource.init(this.getConfig(connection.projectId, connection.id));
this.notificationService.logSuccess({ title: 'plugin_connection_template_connect_success', message: connection.name });
this.onConnect?.();
} catch (exception: any) {
this.connectException = exception;
await this.connectionInfoResource.deleteConnection(createConnectionParam(connection));
}
} catch (exception: any) {
this.connectException = exception;
} finally {
this.processing = false;
}
},
getConfig(projectId: string, connectionId: string) {
const config: ConnectionInitConfig = {
projectId,
connectionId,
};
if (this.authModelId) {
if (Object.keys(this.config.credentials).length > 0) {
config.credentials = this.config.credentials;
}
config.saveCredentials = this.config.saveCredentials;
}
if (this.config.networkHandlersConfig.length > 0) {
config.networkCredentials = this.config.networkHandlersConfig;
}
return config;
},
async selectTemplate(templateId: string) {
this.template = this.templateConnectionsService.projectTemplates.find(template => template.id === templateId)!;
this.driver = await this.dbDriverResource.load(this.template.driverId);
this.config = getDefaultConfig();
if (this.template.authNeeded) {
const property = this.template.authProperties?.find(property => property.id === USER_NAME_PROPERTY_ID);
if (property?.value) {
this.config.credentials[USER_NAME_PROPERTY_ID] = property.value;
}
}
for (const id of this.networkHandlers) {
const handler = this.template.networkHandlersConfig?.find(handler => handler.id === id);
if (handler && (handler.userName || handler.authType !== NetworkHandlerAuthType.Password)) {
this.config.networkHandlersConfig.push({
id: handler.id,
authType: handler.authType,
userName: handler.userName,
password: handler.password,
savePassword: handler.savePassword,
});
}
}
this.setStep(ConnectionStep.Connection);
if (!this.authModelId) {
this.connect();
}
},
setStep(step: ConnectionStep) {
this.step = step;
this.connectException = null;
if (step === ConnectionStep.ConnectionTemplateSelect) {
this.template = null;
this.driver = null;
}
},
}),
{
step: observable.ref,
config: observable,
template: observable.ref,
driver: observable.ref,
processing: observable.ref,
connectException: observable.ref,
networkHandlers: computed,
authModelId: computed,
connect: action.bound,
selectTemplate: action.bound,
setStep: action.bound,
},
{
templateConnectionsService,
projectsService,
notificationService,
authProviderService,
connectionInfoResource,
dbDriverResource,
onConnect,
},
);
return state;
}
@@ -1,35 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { LocalizationService } from '@cloudbeaver/core-localization';
@injectable()
export class LocaleService extends Bootstrap {
constructor(private readonly localizationService: LocalizationService) {
super();
}
override register(): void {
this.localizationService.addProvider(this.provider.bind(this));
}
private async provider(locale: string) {
switch (locale) {
case 'ru':
return (await import('./locales/ru.js')).default;
case 'it':
return (await import('./locales/it.js')).default;
case 'zh':
return (await import('./locales/zh.js')).default;
case 'fr':
return (await import('./locales/fr.js')).default;
default:
return (await import('./locales/en.js')).default;
}
}
}
@@ -1,74 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { AppAuthService } from '@cloudbeaver/core-authentication';
import { importLazyComponent } from '@cloudbeaver/core-blocks';
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
import { CachedMapAllKey, getCachedDataResourceLoaderState, getCachedMapResourceLoaderState } from '@cloudbeaver/core-resource';
import { ActionService, MenuService } from '@cloudbeaver/core-view';
import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections';
import { ACTION_CONNECTION_TEMPLATE } from './Actions/ACTION_CONNECTION_TEMPLATE.js';
import { TemplateConnectionsResource } from './TemplateConnectionsResource.js';
import { TemplateConnectionsService } from './TemplateConnectionsService.js';
const ConnectionDialog = importLazyComponent(() => import('./ConnectionDialog/ConnectionDialog.js').then(m => m.ConnectionDialog));
@injectable()
export class TemplateConnectionPluginBootstrap extends Bootstrap {
constructor(
private readonly appAuthService: AppAuthService,
private readonly menuService: MenuService,
private readonly actionService: ActionService,
private readonly projectInfoResource: ProjectInfoResource,
private readonly templateConnectionsResource: TemplateConnectionsResource,
private readonly commonDialogService: CommonDialogService,
private readonly templateConnectionsService: TemplateConnectionsService,
private readonly projectsService: ProjectsService,
) {
super();
}
override register(): void | Promise<void> {
this.menuService.addCreator({
menus: [MENU_CONNECTIONS],
getItems: (context, items) => [...items, ACTION_CONNECTION_TEMPLATE],
});
this.actionService.addHandler({
id: 'connection-template',
actions: [ACTION_CONNECTION_TEMPLATE],
isHidden: () =>
!this.appAuthService.authenticated ||
!this.projectsService.userProject?.canEditDataSources ||
!this.templateConnectionsService.projectTemplates.length,
getLoader: () => [
...this.appAuthService.loaders,
getCachedMapResourceLoaderState(this.projectInfoResource, () => CachedMapAllKey),
getCachedDataResourceLoaderState(
this.templateConnectionsResource,
() => undefined,
() => undefined,
),
],
handler: async (context, action) => {
switch (action) {
case ACTION_CONNECTION_TEMPLATE: {
await this.openConnectionsDialog();
break;
}
}
},
});
}
private async openConnectionsDialog() {
await this.commonDialogService.open(ConnectionDialog, null);
}
}
@@ -1,73 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { AppAuthService } from '@cloudbeaver/core-authentication';
import { type Connection, ConnectionInfoResource } from '@cloudbeaver/core-connections';
import { injectable } from '@cloudbeaver/core-di';
import { CachedDataResource, ResourceKeyUtils } from '@cloudbeaver/core-resource';
import { SessionDataResource } from '@cloudbeaver/core-root';
import { GraphQLService } from '@cloudbeaver/core-sdk';
@injectable()
export class TemplateConnectionsResource extends CachedDataResource<Connection[]> {
constructor(
private readonly graphQLService: GraphQLService,
connectionInfoResource: ConnectionInfoResource,
sessionDataResource: SessionDataResource,
appAuthService: AppAuthService,
) {
super(() => []);
this.sync(sessionDataResource);
appAuthService.requireAuthentication(this);
connectionInfoResource.onConnectionCreate.addHandler(connection => {
if (connection.template) {
this.markOutdated();
}
});
connectionInfoResource.onDataOutdated.addHandler(key => {
const keyData = connectionInfoResource.get(key);
const connections = Array.isArray(keyData) ? keyData : [keyData];
if (connections.some(connection => connection?.template)) {
this.markOutdated();
}
});
connectionInfoResource.onItemUpdate.addHandler(list => {
const includesTemplate = connectionInfoResource.get(ResourceKeyUtils.toList(list)).some(connection => connection?.template);
if (includesTemplate) {
this.markOutdated();
}
});
connectionInfoResource.onItemDelete.addHandler(list => {
const includesTemplate = connectionInfoResource.get(ResourceKeyUtils.toList(list)).some(connection => connection?.template);
if (includesTemplate) {
this.markOutdated();
}
});
}
protected async loader(): Promise<Connection[]> {
const { connections } = await this.graphQLService.sdk.getTemplateConnections({
includeNetworkHandlersConfig: true,
includeAuthProperties: true,
includeAuthNeeded: true,
includeCredentialsSaved: false,
includeProperties: false,
includeProviderProperties: false,
customIncludeOptions: false,
});
return connections;
}
}
@@ -1,31 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 type { Connection } from '@cloudbeaver/core-connections';
import { injectable } from '@cloudbeaver/core-di';
import { ProjectsService } from '@cloudbeaver/core-projects';
import { TemplateConnectionsResource } from './TemplateConnectionsResource.js';
@injectable()
export class TemplateConnectionsService {
get projectTemplates(): Connection[] {
if (this.projectsService.userProject && this.projectsService.activeProjects.includes(this.projectsService.userProject)) {
return this.templateConnectionsResource.data;
}
// return this.templateConnectionsResource.data
// .filter(
// connection => this.projectsService.activeProjects.some(project => project.id === connection.projectId)
// );
return [];
}
constructor(
private readonly templateConnectionsResource: TemplateConnectionsResource,
private readonly projectsService: ProjectsService,
) {}
}
@@ -1,10 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { connectionTemplate } from './manifest.js';
export default connectionTemplate;
@@ -1,5 +0,0 @@
export default [
['plugin_connection_template_connecting_message', 'Connecting to database...'],
['plugin_connection_template_connect_success', 'Connection is established'],
['plugin_connection_template_action_connection_template_label', 'From a Template'],
];
@@ -1,5 +0,0 @@
export default [
['plugin_connection_template_connecting_message', 'Connexion à la base de données en cours...'],
['plugin_connection_template_connect_success', 'Connexion établie'],
['plugin_connection_template_action_connection_template_label', "À partir d'un modèle"],
];
@@ -1,5 +0,0 @@
export default [
['plugin_connection_template_connecting_message', 'Collegamento al database...'],
['plugin_connection_template_connect_success', 'Connection is established'],
['plugin_connection_template_action_connection_template_label', 'Dal Template'],
];
@@ -1,5 +0,0 @@
export default [
['plugin_connection_template_connecting_message', 'Подключение к базе...'],
['plugin_connection_template_connect_success', 'Подключение установлено'],
['plugin_connection_template_action_connection_template_label', 'Из шаблона'],
];
@@ -1,5 +0,0 @@
export default [
['plugin_connection_template_connecting_message', '连接数据库...'],
['plugin_connection_template_connect_success', '已建立连接'],
['plugin_connection_template_action_connection_template_label', '从模板创建'],
];
@@ -1,21 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 type { PluginManifest } from '@cloudbeaver/core-di';
export const connectionTemplate: PluginManifest = {
info: {
name: 'Template Connections plugin',
},
providers: [
() => import('./TemplateConnectionsResource.js').then(m => m.TemplateConnectionsResource),
() => import('./LocaleService.js').then(m => m.LocaleService),
() => import('./TemplateConnectionPluginBootstrap.js').then(m => m.TemplateConnectionPluginBootstrap),
() => import('./TemplateConnectionsService.js').then(m => m.TemplateConnectionsService),
],
};
@@ -1,67 +0,0 @@
{
"extends": "@cloudbeaver/tsconfig/tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
"tsBuildInfoFile": "lib/tsconfig.tsbuildinfo",
"composite": true
},
"references": [
{
"path": "../core-authentication"
},
{
"path": "../core-blocks"
},
{
"path": "../core-cli"
},
{
"path": "../core-connections"
},
{
"path": "../core-di"
},
{
"path": "../core-dialogs"
},
{
"path": "../core-events"
},
{
"path": "../core-localization"
},
{
"path": "../core-projects"
},
{
"path": "../core-resource"
},
{
"path": "../core-root"
},
{
"path": "../core-sdk"
},
{
"path": "../core-utils"
},
{
"path": "../core-view"
},
{
"path": "../plugin-connections"
}
],
"include": [
"__custom_mocks__/**/*",
"src/**/*",
"src/**/*.json",
"src/**/*.css",
"src/**/*.scss"
],
"exclude": [
"**/node_modules",
"lib/**/*"
]
}
@@ -14,4 +14,4 @@
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn-error.log*
@@ -25,8 +25,6 @@
"@cloudbeaver/core-connections": "workspace:*",
"@cloudbeaver/core-data-context": "workspace:*",
"@cloudbeaver/core-di": "workspace:*",
"@cloudbeaver/core-dialogs": "workspace:*",
"@cloudbeaver/core-events": "workspace:*",
"@cloudbeaver/core-executor": "workspace:*",
"@cloudbeaver/core-localization": "workspace:*",
"@cloudbeaver/core-projects": "workspace:*",
@@ -1,14 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.groupItem {
white-space: pre-wrap;
}
.error {
padding: 24px;
}
@@ -1,99 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import type { AdministrationItemContentProps } from '@cloudbeaver/core-administration';
import {
ColoredContainer,
Container,
ExceptionMessageStyles,
Group,
GroupItem,
GroupTitle,
InfoItem,
Loader,
s,
SContext,
type StyleRegistry,
ToolsAction,
ToolsPanel,
useS,
useTranslate,
} from '@cloudbeaver/core-blocks';
import ConnectionsAdministrationStyle from './ConnectionsAdministration.module.css';
import { ConnectionsTable } from './ConnectionsTable/ConnectionsTable.js';
import { useConnectionsTable } from './ConnectionsTable/useConnectionsTable.js';
import { CreateConnection } from './CreateConnection/CreateConnection.js';
const registry: StyleRegistry = [
[
ExceptionMessageStyles,
{
mode: 'append',
styles: [ConnectionsAdministrationStyle],
},
],
];
export const ConnectionsAdministration = observer<AdministrationItemContentProps>(function ConnectionsAdministration({
sub,
param,
configurationWizard,
}) {
const style = useS(ConnectionsAdministrationStyle);
const translate = useTranslate();
const state = useConnectionsTable();
return (
<ColoredContainer vertical wrap parent gap>
<Group keepSize dense>
<InfoItem info={translate('connections_templates_deprecated_message')} />
</Group>
<Group box keepSize>
<ToolsPanel rounded>
<ToolsAction
title={translate('connections_administration_tools_refresh_tooltip')}
icon="refresh"
viewBox="0 0 24 24"
disabled={state.loading}
onClick={state.update}
>
{translate('ui_refresh')}
</ToolsAction>
<ToolsAction
title={translate('connections_administration_tools_delete_tooltip')}
icon="trash"
viewBox="0 0 24 24"
disabled={!state.table.itemsSelected || state.loading}
onClick={state.delete}
>
{translate('ui_delete')}
</ToolsAction>
</ToolsPanel>
</Group>
<Container overflow gap>
{configurationWizard && (
<Group gap>
<GroupTitle>{translate('connections_administration_configuration_wizard_title')}</GroupTitle>
<GroupItem className={s(style, { groupItem: true })}>{translate('connections_administration_configuration_wizard_message')}</GroupItem>
</Group>
)}
{sub && <CreateConnection method={param} configurationWizard={configurationWizard} />}
<Group boxNoOverflow>
<SContext registry={registry}>
<Loader loading={state.loading} overlay>
<ConnectionsTable state={state} />
</Loader>
</SContext>
</Group>
</Container>
</ColoredContainer>
);
});
@@ -1,22 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { AdministrationScreenService } from '@cloudbeaver/core-administration';
import { injectable } from '@cloudbeaver/core-di';
@injectable()
export class ConnectionsAdministrationNavService {
constructor(private readonly administrationScreenService: AdministrationScreenService) {}
navToRoot() {
this.administrationScreenService.navigateToItem('connections');
}
navToCreate(method: string) {
this.administrationScreenService.navigateToItemSub('connections', 'create', method);
}
}
@@ -1,124 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 React from 'react';
import { AdministrationItemService, AdministrationItemType } from '@cloudbeaver/core-administration';
import { ConfirmationDialog, PlaceholderContainer } from '@cloudbeaver/core-blocks';
import { type ConnectionInfoOrigin, ConnectionInfoResource, type DatabaseConnection } from '@cloudbeaver/core-connections';
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs';
import { ServerConfigResource } from '@cloudbeaver/core-root';
import { CreateConnectionService } from './CreateConnectionService.js';
import { CachedMapAllKey, getCachedDataResourceLoaderState, getCachedMapResourceLoaderState } from '@cloudbeaver/core-resource';
export interface IConnectionDetailsPlaceholderProps {
connection: DatabaseConnection;
connectionOrigin?: ConnectionInfoOrigin;
}
const ConnectionsAdministration = React.lazy(async () => {
const { ConnectionsAdministration } = await import('./ConnectionsAdministration.js');
return { default: ConnectionsAdministration };
});
const ConnectionsDrawerItem = React.lazy(async () => {
const { ConnectionsDrawerItem } = await import('./ConnectionsDrawerItem.js');
return { default: ConnectionsDrawerItem };
});
const Origin = React.lazy(async () => {
const { Origin } = await import('./ConnectionsTable/ConnectionDetailsInfo/Origin.js');
return { default: Origin };
});
const SSH = React.lazy(async () => {
const { SSH } = await import('./ConnectionsTable/ConnectionDetailsInfo/SSH.js');
return { default: SSH };
});
@injectable()
export class ConnectionsAdministrationService extends Bootstrap {
readonly connectionDetailsPlaceholder = new PlaceholderContainer<IConnectionDetailsPlaceholderProps>();
constructor(
private readonly administrationItemService: AdministrationItemService,
private readonly connectionInfoResource: ConnectionInfoResource,
private readonly createConnectionService: CreateConnectionService,
private readonly commonDialogService: CommonDialogService,
private readonly serverConfigResource: ServerConfigResource,
) {
super();
}
override register(): void {
this.administrationItemService.create({
name: 'connections',
type: AdministrationItemType.Administration,
order: 5,
configurationWizardOptions: {
defaultRoute: { sub: 'create' },
description: 'connections_administration_configuration_wizard_step_description',
},
sub: [
{
name: 'create',
onActivate: this.activateCreateMethod.bind(this),
onDeActivate: this.deactivateCreateMethod.bind(this),
canDeActivate: this.canDeActivateCreate.bind(this),
},
],
getLoader: () => [
getCachedDataResourceLoaderState(this.serverConfigResource, () => undefined),
getCachedMapResourceLoaderState(this.connectionInfoResource, () => CachedMapAllKey),
],
isHidden: () => this.serverConfigResource.distributed || !this.connectionInfoResource.values.some(connection => connection.template),
getContentComponent: () => ConnectionsAdministration,
getDrawerComponent: () => ConnectionsDrawerItem,
onDeActivate: this.refreshUserConnections.bind(this),
});
this.connectionDetailsPlaceholder.add(Origin, 0);
this.connectionDetailsPlaceholder.add(SSH, 2);
}
private refreshUserConnections(configuration: boolean, outside: boolean, outsideAdminPage: boolean): void {
// TODO: we have to track users' leaving the page
if (outside) {
this.connectionInfoResource.cleanNewFlags();
// const updated = await this.connectionInfoResource.updateSessionConnections();
// if (updated) {
// this.sessionDataResource.markOutdated();
// }
}
}
private activateCreateMethod(param: string | null) {
if (!param) {
this.createConnectionService.setCreateMethod();
}
this.createConnectionService.setCreateMethod(param);
}
private deactivateCreateMethod(param: string | null, configuration: boolean, outside: boolean) {
if (outside) {
this.createConnectionService.close();
}
}
private async canDeActivateCreate() {
if (this.createConnectionService.data === null) {
return true;
}
const result = await this.commonDialogService.open(ConfirmationDialog, {
title: 'ui_changes_will_be_lost',
message: 'connections_administration_deactivate_message',
confirmActionText: 'ui_continue',
});
return result !== DialogueStateResult.Rejected;
}
}
@@ -1,26 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 type { AdministrationItemDrawerProps } from '@cloudbeaver/core-administration';
import { Translate } from '@cloudbeaver/core-blocks';
import { TabIcon, Tab, TabTitle } from '@cloudbeaver/core-ui';
export const ConnectionsDrawerItem: React.FC<AdministrationItemDrawerProps> = function ConnectionsDrawerItem({
item,
onSelect,
disabled,
configurationWizard,
}) {
return (
<Tab tabId={item.name} disabled={disabled} onOpen={() => onSelect(item.name)}>
<TabIcon icon="/icons/connection.svg" />
<TabTitle>
<Translate token={configurationWizard ? 'connections_administration_configuration_wizard_step_title' : 'connections_administration_item'} />
</TabTitle>
</Tab>
);
};
@@ -1,26 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.staticImage {
display: flex;
width: 24px;
min-width: 24px;
&:not(:last-child) {
margin-right: 16px;
}
}
.tableColumnValueExpand {
cursor: pointer;
}
.tableItemSelect {
margin-left: -10px;
margin-right: -10px;
}
@@ -1,79 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import {
Loader,
Placeholder,
s,
StaticImage,
TableColumnValue,
TableItem,
TableItemExpand,
TableItemSelect,
useResource,
useS,
} from '@cloudbeaver/core-blocks';
import { type ConnectionInfoOrigin, type DatabaseConnection, type IConnectionInfoParams } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
import { ConnectionsAdministrationService } from '../ConnectionsAdministrationService.js';
import styles from './Connection.module.css';
import { ConnectionEdit } from './ConnectionEdit.js';
interface Props {
connectionKey: IConnectionInfoParams;
connection: DatabaseConnection;
shouldDisplayProject: boolean;
connectionOrigin?: ConnectionInfoOrigin;
icon?: string;
}
export const Connection = observer<Props>(function Connection({ connectionKey, connectionOrigin, connection, shouldDisplayProject, icon }) {
const style = useS(styles);
const connectionsAdministrationService = useService(ConnectionsAdministrationService);
const projectInfoResource = useResource(Connection, ProjectInfoResource, connectionKey.projectId, { active: shouldDisplayProject });
const projectName = shouldDisplayProject ? (projectInfoResource.data?.name ?? '') : undefined;
return (
<TableItem item={connectionKey} expandElement={ConnectionEdit}>
<TableColumnValue centerContent flex>
<TableItemSelect className={s(style, { tableItemSelect: true })} />
</TableColumnValue>
<TableColumnValue className={s(style, { tableColumnValueExpand: true })} centerContent flex expand>
<TableItemExpand />
</TableColumnValue>
<TableColumnValue className={s(style, { tableColumnValueExpand: true })} centerContent flex expand>
<StaticImage className={s(style, { staticImage: true })} icon={icon} />
</TableColumnValue>
<TableColumnValue title={connection.name} className={s(style, { tableColumnValueExpand: true })} expand ellipsis>
{connection.name}
</TableColumnValue>
<TableColumnValue>
{connection.host}
{connection.host && connection.port && `:${connection.port}`}
</TableColumnValue>
{projectName !== undefined && (
<TableColumnValue title={projectName} className={s(style, { tableColumnValueExpand: true })} expand ellipsis>
{projectName}
</TableColumnValue>
)}
<TableColumnValue flex>
<Loader suspense small inline hideMessage>
<Placeholder
container={connectionsAdministrationService.connectionDetailsPlaceholder}
connectionOrigin={connectionOrigin}
connection={connection}
/>
</Loader>
</TableColumnValue>
</TableItem>
);
});
@@ -1,16 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.staticImage {
width: 24px;
height: 24px;
margin-right: 10px;
&:last-child {
margin-right: 0;
}
}
@@ -1,28 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication';
import { type PlaceholderComponent, s, StaticImage, useS } from '@cloudbeaver/core-blocks';
import type { IConnectionDetailsPlaceholderProps } from '../../ConnectionsAdministrationService.js';
import ConnectionDetailsStyles from './ConnectionDetailsStyles.module.css';
export const Origin: PlaceholderComponent<IConnectionDetailsPlaceholderProps> = observer(function Origin({ connectionOrigin }) {
const isLocal = connectionOrigin?.origin?.type === AUTH_PROVIDER_LOCAL_ID;
const style = useS(ConnectionDetailsStyles);
if (!connectionOrigin?.origin || isLocal) {
return null;
}
const icon = connectionOrigin.origin.icon;
const title = connectionOrigin.origin.displayName;
return <StaticImage className={s(style, { staticImage: true })} icon={icon} title={title} />;
});
@@ -1,34 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { type PlaceholderComponent, s, StaticImage, useResource, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { NetworkHandlerResource, SSH_TUNNEL_ID } from '@cloudbeaver/core-connections';
import type { IConnectionDetailsPlaceholderProps } from '../../ConnectionsAdministrationService.js';
import ConnectionDetailsStyles from './ConnectionDetailsStyles.module.css';
export const SSH: PlaceholderComponent<IConnectionDetailsPlaceholderProps> = observer(function SSH({ connection }) {
const translate = useTranslate();
const style = useS(ConnectionDetailsStyles);
const sshConfig = connection.networkHandlersConfig?.find(state => state.id === SSH_TUNNEL_ID);
const applicable = sshConfig?.enabled === true;
const handler = useResource(SSH, NetworkHandlerResource, SSH_TUNNEL_ID, { active: applicable });
if (!applicable) {
return null;
}
return (
<StaticImage
className={s(style, { staticImage: true })}
icon="/icons/ssh_tunnel.svg"
title={translate(handler.data?.label || 'connections_network_handler_ssh_tunnel_title')}
/>
);
});
@@ -1,22 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { type PlaceholderComponent, s, StaticImage, useS } from '@cloudbeaver/core-blocks';
import type { IConnectionDetailsPlaceholderProps } from '../../ConnectionsAdministrationService.js';
import ConnectionDetailsStyles from './ConnectionDetailsStyles.module.css';
export const Template: PlaceholderComponent<IConnectionDetailsPlaceholderProps> = observer(function Template({ connection }) {
const style = useS(ConnectionDetailsStyles);
if (!connection.template) {
return null;
}
return <StaticImage className={s(style, { staticImage: true })} icon="/icons/template_connection.svg" title="Template connection" />;
});
@@ -1,20 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.box {
composes: theme-background-secondary theme-text-on-secondary from global;
box-sizing: border-box;
padding-bottom: 24px;
display: flex;
flex-direction: column;
height: 740px;
}
.loader {
height: 100%;
}
@@ -1,42 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite';
import { Loader, s, useS } from '@cloudbeaver/core-blocks';
import { type IConnectionInfoParams } from '@cloudbeaver/core-connections';
import { ConnectionFormLoader, useConnectionFormState } from '@cloudbeaver/plugin-connections';
import styles from './ConnectionEdit.module.css';
import { FormMode } from '@cloudbeaver/core-ui';
import { runInAction } from 'mobx';
interface Props {
item: IConnectionInfoParams;
}
export const ConnectionEdit = observer<Props>(function ConnectionEditNew({ item }) {
const data = useConnectionFormState(item, state => {
state.setMode(FormMode.Edit);
runInAction(() => {
state.state.connectionId = item.connectionId;
state.state.projectId = item.projectId;
state.state.type = 'admin';
});
});
const style = useS(styles);
return (
<div className={s(style, { box: true })}>
<Loader className={s(style, { loader: true })} suspense>
<ConnectionFormLoader formState={data} />
</Loader>
</div>
);
});
@@ -1,63 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite';
import { Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useResource, useTranslate } from '@cloudbeaver/core-blocks';
import { type ConnectionInfoOrigin, ConnectionInfoOriginResource, DBDriverResource, serializeConnectionParam } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { isGlobalProject, isSharedProject, ProjectsService } from '@cloudbeaver/core-projects';
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
import { isNotNullDefined } from '@dbeaver/js-helpers';
import { Connection } from './Connection.js';
import { type IConnectionsTableState } from './useConnectionsTable.js';
interface Props {
state: IConnectionsTableState;
}
function getOriginsMap(origins: (ConnectionInfoOrigin | undefined)[]) {
return new Map(origins.filter(isNotNullDefined).map(origin => [origin.id, origin]));
}
export const ConnectionsTable = observer<Props>(function ConnectionsTable({ state }) {
const translate = useTranslate();
const projectService = useService(ProjectsService);
const dbDriverResource = useResource(ConnectionsTable, DBDriverResource, CachedMapAllKey);
const shouldDisplayProjects = projectService.activeProjects.filter(project => isGlobalProject(project) || isSharedProject(project)).length > 1;
const connectionOriginResource = useResource(ConnectionsTable, ConnectionInfoOriginResource, CachedMapAllKey);
const connectionOriginsMap = getOriginsMap(connectionOriginResource.data);
return (
<Table keys={state.keys} selectedItems={state.table.selected} expandedItems={state.table.expanded} size="big">
<TableHeader fixed>
<TableColumnHeader min flex centerContent>
<TableSelect />
</TableColumnHeader>
<TableColumnHeader min />
<TableColumnHeader min />
<TableColumnHeader>{translate('connections_connection_name')}</TableColumnHeader>
<TableColumnHeader>{translate('connections_connection_address')}</TableColumnHeader>
{shouldDisplayProjects && <TableColumnHeader>{translate('connections_connection_project')}</TableColumnHeader>}
<TableColumnHeader />
</TableHeader>
<TableBody>
{state.connections.map((connection, i) => (
<Connection
key={serializeConnectionParam(state.keys[i]!)}
connectionKey={state.keys[i]!}
connection={connection}
connectionOrigin={connectionOriginsMap.get(connection.id)}
shouldDisplayProject={shouldDisplayProjects}
icon={dbDriverResource.resource.get(connection.driverId)?.icon}
/>
))}
</TableBody>
</Table>
);
});
@@ -1,174 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { action, computed, observable } from 'mobx';
import { ConfirmationDialogDelete, TableState, useObservableRef, useResource, useTable } from '@cloudbeaver/core-blocks';
import {
compareConnectionsInfo,
compareNewConnectionsInfo,
type Connection,
ConnectionInfoActiveProjectKey,
ConnectionInfoResource,
createConnectionParam,
type IConnectionInfoParams,
} from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs';
import { NotificationService } from '@cloudbeaver/core-events';
import { LocalizationService } from '@cloudbeaver/core-localization';
import { isGlobalProject, isSharedProject, ProjectInfoResource, projectInfoSortByName, ProjectsService } from '@cloudbeaver/core-projects';
import { CachedMapAllKey, resourceKeyList } from '@cloudbeaver/core-resource';
import { isArraysEqual, isObjectsEqual } from '@cloudbeaver/core-utils';
import { isDefined } from '@dbeaver/js-helpers';
export interface IConnectionsTableState {
readonly connections: Connection[];
readonly keys: IConnectionInfoParams[];
table: TableState<IConnectionInfoParams>;
loading: boolean;
update: () => Promise<void>;
delete: () => Promise<void>;
}
export function useConnectionsTable() {
const connectionInfoResource = useResource(
useConnectionsTable,
ConnectionInfoResource,
{
key: ConnectionInfoActiveProjectKey,
includes: ['customIncludeOptions'],
},
{ forceSuspense: true },
);
const projectInfoResource = useResource(useConnectionsTable, ProjectInfoResource, CachedMapAllKey, { forceSuspense: true });
const notificationService = useService(NotificationService);
const localizationService = useService(LocalizationService);
const commonDialogService = useService(CommonDialogService);
const projectService = useService(ProjectsService);
const table = useTable<IConnectionInfoParams>();
const state: IConnectionsTableState = useObservableRef(
() => ({
get connections() {
return this.connectionInfoResource.resource
.get(ConnectionInfoActiveProjectKey)
.filter((connection): connection is Connection => {
if (!isDefined(connection)) {
return false;
}
const project = this.projectInfoResource.resource.get(connection.projectId);
return connection.template && !!project && (isSharedProject(project) || isGlobalProject(project));
})
.sort((a, b) => {
const compareNew = compareNewConnectionsInfo(a, b);
const projectA = this.projectInfoResource.resource.get(a.projectId);
const projectB = this.projectInfoResource.resource.get(b.projectId);
if (compareNew !== 0) {
return compareNew;
}
if (projectA && projectB) {
const projectSort = projectInfoSortByName(projectA, projectB);
if (projectSort !== 0) {
return projectSort;
}
}
return compareConnectionsInfo(a, b);
});
},
get keys() {
return this.connections.map(createConnectionParam);
},
loading: false,
async update() {
if (this.loading) {
return;
}
this.loading = true;
try {
await this.connectionInfoResource.resource.refresh(ConnectionInfoActiveProjectKey);
this.connectionInfoResource.resource.cleanNewFlags();
this.notificationService.logSuccess({ title: 'connections_administration_tools_refresh_success' });
} catch (exception: any) {
this.notificationService.logException(exception, 'connections_administration_tools_refresh_fail');
} finally {
this.loading = false;
}
},
async delete() {
if (this.loading) {
return;
}
const deletionList = Array.from(this.table.selected)
.filter(([_, value]) => value)
.map(([connectionId]) => connectionId);
if (deletionList.length === 0) {
return;
}
const connectionNames = deletionList.map(id => this.connectionInfoResource.resource.get(id)?.name).filter(Boolean);
const nameList = connectionNames.map(name => `"${name}"`).join(', ');
const message = `${this.localizationService.translate(
'connections_administration_delete_confirmation',
)}${nameList}. ${this.localizationService.translate('ui_are_you_sure')}`;
const result = await this.commonDialogService.open(ConfirmationDialogDelete, {
title: 'ui_data_delete_confirmation',
message,
confirmActionText: 'ui_delete',
});
if (result === DialogueStateResult.Rejected) {
return;
}
this.loading = true;
try {
await this.connectionInfoResource.resource.deleteConnection(resourceKeyList(deletionList));
this.table.unselect();
for (const id of deletionList) {
this.table.expand(id, false);
}
} catch (exception: any) {
this.notificationService.logException(exception, 'connections_administration_connection_create_error');
} finally {
this.loading = false;
}
},
}),
{
connections: computed<Connection[]>({ equals: (a, b) => isArraysEqual(a, b) }),
keys: computed<IConnectionInfoParams[]>({ equals: (a, b) => isArraysEqual(a, b, isObjectsEqual) }),
loading: observable.ref,
update: action.bound,
delete: action.bound,
},
{
table,
connectionInfoResource,
projectInfoResource,
notificationService,
localizationService,
commonDialogService,
projectService,
},
);
return state;
}
@@ -1,112 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite';
import {
ActionIconButton,
Container,
Group,
GroupClose,
GroupTitle,
Loader,
s,
SContext,
StaticImage,
type StyleRegistry,
useResource,
useS,
useTranslate,
} from '@cloudbeaver/core-blocks';
import { DBDriverResource } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { TabListStyles, TabPanelList, TabPanelStyles, TabsState, TabStyles } from '@cloudbeaver/core-ui';
import { ConnectionFormLoader, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections';
import { CreateConnectionService } from '../CreateConnectionService.js';
import styles from './shared/CreateConnection.module.css';
import CreateConnectionTab from './shared/CreateConnectionTab.module.css';
import CreateConnectionTabList from './shared/CreateConnectionTabList.module.css';
import CreateConnectionTabPanel from './shared/CreateConnectionTabPanel.module.css';
interface Props {
method: string | null | undefined;
configurationWizard: boolean;
}
const tabsRegistry: StyleRegistry = [
[TabStyles, { mode: 'append', styles: [CreateConnectionTab] }],
[TabPanelStyles, { mode: 'append', styles: [CreateConnectionTabPanel] }],
[TabListStyles, { mode: 'append', styles: [CreateConnectionTabList] }],
];
export const CreateConnection = observer<Props>(function CreateConnection({ method }) {
const style = useS(styles);
const createConnectionService = useService(CreateConnectionService);
const translate = useTranslate();
const optionsPart = createConnectionService.data ? getConnectionFormOptionsPart(createConnectionService.data) : null;
const driver = useResource(CreateConnection, DBDriverResource, optionsPart?.state.driverId || null);
if (createConnectionService.data) {
return (
<Group className={s(style, { connectionCreate: true })} vertical box boxNoOverflow noWrap>
<GroupTitle header keepSize>
<Container gap dense noWrap>
<Container keepSize>
<ActionIconButton
name="angle"
viewBox="0 0 15 8"
className={s(style, { backButton: true })}
onClick={createConnectionService.clearConnectionTemplate}
/>
</Container>
<Container keepSize center>
{driver.data?.icon && <StaticImage className={s(style, { staticImage: true })} icon={driver.data.icon} />}
</Container>
<Container keepSize center>
{translate('connections_administration_connection_create')}
</Container>
</Container>
<GroupClose onClick={createConnectionService.cancelCreate} />
</GroupTitle>
<Container overflow>
<Loader className={s(style, { loader: true })} suspense>
<ConnectionFormLoader
formState={createConnectionService.data}
onCancel={createConnectionService.clearConnectionTemplate}
onSave={createConnectionService.clearConnectionTemplate}
/>
</Loader>
</Container>
</Group>
);
}
return (
<Group className={s(style, { connectionCreate: true })} vertical box boxNoOverflow noWrap>
<TabsState
currentTabId={method}
container={createConnectionService.tabsContainer}
manual
lazy
onChange={({ tabId }) => createConnectionService.setCreateMethod(tabId)}
>
<GroupTitle keepSize>
{translate('connections_administration_connection_create')}
<GroupClose onClick={createConnectionService.cancelCreate} />
</GroupTitle>
<Container overflow>
<SContext registry={tabsRegistry}>
<TabPanelList />
</SContext>
{createConnectionService.disabled && <Loader overlay />}
</Container>
</TabsState>
</Group>
);
});
@@ -1,33 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 React from 'react';
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { CreateConnectionService } from '../CreateConnectionService.js';
const CustomConnection = React.lazy(async () => {
const { CustomConnection } = await import('./Manual/CustomConnection.js');
return { default: CustomConnection };
});
@injectable()
export class CreateConnectionBaseBootstrap extends Bootstrap {
constructor(private readonly createConnectionService: CreateConnectionService) {
super();
}
override register(): void | Promise<void> {
this.createConnectionService.tabsContainer.add({
key: 'manual',
name: 'connections_connection_create_custom',
order: 1,
panel: () => CustomConnection,
});
}
}
@@ -1,37 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { injectable } from '@cloudbeaver/core-di';
import { CreateConnectionService } from '../../CreateConnectionService.js';
@injectable()
export class ConnectionManualService {
get disabled(): boolean {
return this.createConnectionService.disabled;
}
set disabled(value: boolean) {
this.createConnectionService.disabled = value;
}
constructor(private readonly createConnectionService: CreateConnectionService) {
this.select = this.select.bind(this);
}
select(projectId: string, driverId: string): void {
this.createConnectionService.setConnectionTemplate(
projectId,
{
template: true,
driverId,
},
[driverId],
);
}
}
@@ -1,52 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { computed } from 'mobx';
import { observer } from 'mobx-react-lite';
import { useMemo } from 'react';
import { Loader, useResource } from '@cloudbeaver/core-blocks';
import { DBDriverResource } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { isSharedProject, ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
import { ConnectionManualService } from './ConnectionManualService.js';
import { DriverList } from './DriverList.js';
export const CustomConnection = observer(function CustomConnection() {
const projectsService = useService(ProjectsService);
const notificationService = useService(NotificationService);
const connectionManualService = useService(ConnectionManualService);
const dbDriverResource = useResource(CustomConnection, DBDriverResource, CachedMapAllKey);
const drivers = useMemo(
() => computed(() => dbDriverResource.resource.enabledDrivers.slice().sort(dbDriverResource.resource.compare)),
[dbDriverResource],
);
useResource(CustomConnection, ProjectInfoResource, CachedMapAllKey);
function select(driverId: string) {
const shared = projectsService.activeProjects.filter(isSharedProject);
if (shared.length > 0) {
connectionManualService.select(shared[0]!.id, driverId);
} else {
notificationService.logError({
title: 'core_projects_no_default_project',
});
}
}
return (
<Loader state={[dbDriverResource]}>
<DriverList drivers={drivers.get()} onSelect={select} />
</Loader>
);
});
@@ -1,12 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.staticImage {
box-sizing: border-box;
width: 24px;
max-height: 24px;
}
@@ -1,34 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import { ListItem, ListItemDescription, ListItemIcon, ListItemName, s, StaticImage, useS } from '@cloudbeaver/core-blocks';
import type { DBDriver } from '@cloudbeaver/core-connections';
import style from './Driver.module.css';
interface Props {
driver: DBDriver;
onSelect: (driverId: string) => void;
}
export const Driver = observer<Props>(function Driver({ driver, onSelect }) {
const select = useCallback(() => onSelect(driver.id), [driver]);
const styles = useS(style);
return (
<ListItem onClick={select}>
<ListItemIcon>
<StaticImage icon={driver.icon} className={s(styles, { staticImage: true })} />
</ListItemIcon>
<ListItemName>{driver.name}</ListItemName>
<ListItemDescription title={driver.description}>{driver.description}</ListItemDescription>
</ListItem>
);
});
@@ -1,12 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.container {
display: flex;
flex-direction: column;
overflow: auto;
}
@@ -1,45 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite';
import { useMemo, useState } from 'react';
import { ItemList, ItemListSearch, s, useFocus, useS, useTranslate } from '@cloudbeaver/core-blocks';
import type { DBDriver } from '@cloudbeaver/core-connections';
import { Driver } from './Driver.js';
import styles from './DriverList.module.css';
interface Props {
drivers: DBDriver[];
className?: string;
onSelect: (driverId: string) => void;
}
export const DriverList = observer<Props>(function DriverList({ drivers, className, onSelect }) {
const [focusedRef] = useFocus<HTMLDivElement>({ focusFirstChild: true });
const translate = useTranslate();
const [search, setSearch] = useState('');
const style = useS(styles);
const filteredDrivers = useMemo(() => {
if (!search) {
return drivers;
}
return drivers.filter(driver => driver.name?.toUpperCase().includes(search.toUpperCase()));
}, [search, drivers]);
return (
<div ref={focusedRef} className={s(style, { container: true })}>
<ItemListSearch value={search} placeholder={translate('connections_driver_search_placeholder')} onChange={setSearch} />
<ItemList className={className}>
{filteredDrivers.map(driver => (
<Driver key={driver.id} driver={driver} onSelect={onSelect} />
))}
</ItemList>
</div>
);
});
@@ -1,25 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.connectionCreate {
height: 800px;
}
.loader {
z-index: 1;
height: 100%;
}
.staticImage {
width: 24px;
max-height: 24px;
}
.backButton {
transform: rotate(90deg);
}
@@ -1,11 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.tab {
composes: theme-background-secondary theme-text-on-secondary from global;
}
@@ -1,24 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.tabList {
composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global;
border-top: solid 1px;
position: relative;
flex-shrink: 0;
align-items: center;
&:before {
content: '';
position: absolute;
bottom: 0;
width: 100%;
border-bottom: solid 2px;
border-color: inherit;
}
}
@@ -1,13 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.tabPanel {
flex-direction: column;
height: 100%;
overflow: auto;
}
@@ -1,147 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { action, makeObservable, observable } from 'mobx';
import { AdministrationScreenService } from '@cloudbeaver/core-administration';
import { injectable, IServiceProvider } from '@cloudbeaver/core-di';
import type { ConnectionConfig } from '@cloudbeaver/core-sdk';
import { TabsContainer } from '@cloudbeaver/core-ui';
import { ConnectionFormService, ConnectionFormState, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections';
import { ConnectionsAdministrationNavService } from './ConnectionsAdministrationNavService.js';
export interface ICreateMethodOptions {
configurationWizard?: {
activationPriority?: number;
};
close?: () => void;
}
@injectable()
export class CreateConnectionService {
disabled = false;
data: ConnectionFormState | null;
readonly tabsContainer: TabsContainer<void, ICreateMethodOptions>;
constructor(
private readonly connectionsAdministrationNavService: ConnectionsAdministrationNavService,
private readonly administrationScreenService: AdministrationScreenService,
private readonly serviceProvider: IServiceProvider,
private readonly connectionFormService: ConnectionFormService,
) {
this.data = null;
this.tabsContainer = new TabsContainer('Connection Creation mode');
this.setConnectionTemplate = this.setConnectionTemplate.bind(this);
this.clearConnectionTemplate = this.clearConnectionTemplate.bind(this);
this.setCreateMethod = this.setCreateMethod.bind(this);
this.cancelCreate = this.cancelCreate.bind(this);
this.create = this.create.bind(this);
makeObservable<this, 'activateMethod'>(this, {
data: observable,
disabled: observable,
setCreateMethod: action,
cancelCreate: action,
create: action,
setConnectionTemplate: action,
clearConnectionTemplate: action,
close: action,
activateMethod: action,
});
}
getDefault(): string | null {
const tabs = this.tabsContainer.getDisplayed();
if (tabs.length === 0) {
return null;
}
if (this.administrationScreenService.isConfigurationMode) {
const sorted = tabs.sort((a, b) => {
const aPriority = a.options?.configurationWizard?.activationPriority || Number.MAX_SAFE_INTEGER;
const bPriority = b.options?.configurationWizard?.activationPriority || Number.MAX_SAFE_INTEGER;
return aPriority - bPriority;
});
return sorted[0]!.key;
}
return tabs[0]!.key;
}
setCreateMethod(method?: string | null): void {
if (!method) {
const id = this.getDefault();
if (!id) {
return;
}
method = id;
}
this.activateMethod(method);
}
cancelCreate(): void {
this.clearConnectionTemplate();
this.connectionsAdministrationNavService.navToRoot();
}
create(): void {
const defaultId = this.getDefault();
if (!defaultId) {
return;
}
this.activateMethod(defaultId);
}
private get optionsPart() {
return this.data ? getConnectionFormOptionsPart(this.data) : null;
}
async setConnectionTemplate(projectId: string, config: ConnectionConfig, availableDrivers: string[]): Promise<void> {
this.clearConnectionTemplate();
this.data = new ConnectionFormState(this.serviceProvider, this.connectionFormService, {
projectId,
availableDrivers,
type: 'admin',
requiredNetworkHandlersIds: [],
connectionId: config.connectionId,
});
await this.optionsPart?.load();
await this.optionsPart?.setDriverId(config.driverId);
Object.assign(this.optionsPart!.state, config);
this.data.disposeTask.addHandler(this.cancelCreate.bind(this));
}
clearConnectionTemplate(): void {
this.data?.dispose();
this.data = null;
}
close(): void {
this.clearConnectionTemplate();
const tabs = this.tabsContainer.getDisplayed();
for (const method of tabs) {
method.options?.close?.();
}
}
private activateMethod(method: string) {
this.tabsContainer.select(method);
this.connectionsAdministrationNavService.navToCreate(method);
}
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -30,12 +30,13 @@ import type { TLocalizationToken } from '@cloudbeaver/core-localization';
import { CachedMapAllKey, CachedResourceOffsetPageListKey } from '@cloudbeaver/core-resource';
import { FormMode, type TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui';
import { getConnectionFormOptionsPart, type IConnectionFormProps } from '@cloudbeaver/plugin-connections';
import styles from './ConnectionAccess.module.css';
import { ConnectionAccessGrantedList } from './ConnectionAccessGrantedList.js';
import { ConnectionAccessList } from './ConnectionAccessList.js';
import { getConnectionFormAccessPart } from './getConnectionFormAccessPart.js';
export const ConnectionAccess: TabContainerPanelComponent<IConnectionFormProps> = observer(function ConnectionAccess({ tabId, formState }) {
import styles from './ConnectionFormAccess.module.css';
import { getConnectionFormAccessPart } from './getConnectionFormAccessPart.js';
import { ConnectionFormAccessTableGrantedList } from './ConnectionFormAccessTable/ConnectionFormAccessTableGrantedList.js';
import { ConnectionFormAccessTableList } from './ConnectionFormAccessTable/ConnectionFormAccessTableList.js';
export const ConnectionFormAccess: TabContainerPanelComponent<IConnectionFormProps> = observer(function ConnectionFormAccess({ tabId, formState }) {
const translate = useTranslate();
const style = useS(styles);
const state = useObservableRef(
@@ -56,12 +57,12 @@ export const ConnectionAccess: TabContainerPanelComponent<IConnectionFormProps>
const accessPart = getConnectionFormAccessPart(formState);
const [initialFormMode] = useState<FormMode>(formState.mode);
useAutoLoad(ConnectionAccess, accessPart, selected);
useAutoLoad(ConnectionFormAccess, accessPart, selected);
const users = useResource(ConnectionAccess, UsersResource, CachedResourceOffsetPageListKey(0, 1000).setParent(UsersResourceFilterKey()), {
const users = useResource(ConnectionFormAccess, UsersResource, CachedResourceOffsetPageListKey(0, 1000).setParent(UsersResourceFilterKey()), {
active: selected,
});
const teams = useResource(ConnectionAccess, TeamsResource, CachedMapAllKey, { active: selected });
const teams = useResource(ConnectionFormAccess, TeamsResource, CachedMapAllKey, { active: selected });
const grantedUsers = useMemo(
() => computed(() => users.resource.values.filter(user => accessPart.state.includes(user.userId))),
@@ -75,7 +76,7 @@ export const ConnectionAccess: TabContainerPanelComponent<IConnectionFormProps>
const optionsPart = getConnectionFormOptionsPart(formState);
const connectionInfoResource = useResource(
ConnectionAccess,
ConnectionFormAccess,
ConnectionInfoResource,
createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!),
{
@@ -83,7 +84,7 @@ export const ConnectionAccess: TabContainerPanelComponent<IConnectionFormProps>
},
);
const originInfoResource = useResource(
ConnectionAccess,
ConnectionFormAccess,
ConnectionInfoOriginResource,
createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!),
{
@@ -113,13 +114,13 @@ export const ConnectionAccess: TabContainerPanelComponent<IConnectionFormProps>
<ColoredContainer className={s(style, { coloredContainer: true })} parent gap vertical>
{!users.resource.values.length && !teams.resource.values.length ? (
<Group className={s(style, { group: true })} keepSize large>
<TextPlaceholder>{translate('connections_administration_connection_access_empty')}</TextPlaceholder>
<TextPlaceholder>{translate('core_connections_connection_access_empty')}</TextPlaceholder>
</Group>
) : (
<>
{info && <InfoItem info={info} />}
<Container gap overflow>
<ConnectionAccessGrantedList
<ConnectionFormAccessTableGrantedList
grantedUsers={grantedUsers.get()}
grantedTeams={grantedTeams.get()}
disabled={disabled}
@@ -127,7 +128,7 @@ export const ConnectionAccess: TabContainerPanelComponent<IConnectionFormProps>
onRevoke={accessPart.revoke}
/>
{state.editing && (
<ConnectionAccessList
<ConnectionFormAccessTableList
userList={users.resource.values}
teamList={teams.resource.values}
grantedSubjects={accessPart.state}
@@ -77,4 +77,4 @@ export class ConnectionFormAccessPart extends FormPart<string[], IConnectionForm
grant(subjectIds: string[]) {
this.state.push(...subjectIds);
}
}
}
@@ -15,13 +15,13 @@ import { ConnectionFormService, getConnectionFormOptionsPart } from '@cloudbeave
import { getConnectionFormAccessPart } from './getConnectionFormAccessPart.js';
import { getCachedDataResourceLoaderState, getCachedMapResourceLoaderState } from '@cloudbeaver/core-resource';
const ConnectionAccess = React.lazy(async () => {
const { ConnectionAccess } = await import('./ConnectionAccess.js');
return { default: ConnectionAccess };
const ConnectionFormAccess = React.lazy(async () => {
const { ConnectionFormAccess } = await import('./ConnectionFormAccess.js');
return { default: ConnectionFormAccess };
});
@injectable()
export class ConnectionAccessTabService extends Bootstrap {
export class ConnectionFormAccessTabService extends Bootstrap {
private readonly key: string;
constructor(
@@ -52,11 +52,11 @@ export class ConnectionAccessTabService extends Bootstrap {
return !optionsPart?.state.driverId || this.administrationScreenService.isConfigurationMode;
},
panel: () => ConnectionAccess,
panel: () => ConnectionFormAccess,
});
}
private isAccessTabActive(projectId: string | null): boolean {
return projectId !== null && isGlobalProject(this.projectInfoResource.get(projectId)) && this.permissionsResource.has(EAdminPermission.admin);
}
}
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -26,10 +26,10 @@
width: 100%;
}
.tableContainer {
overflow: auto;
}
.connectionAccessTableHeader {
flex: 0 0 auto;
}
.tableContainer {
overflow: auto;
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -27,11 +27,11 @@ import {
import type { TLocalizationToken } from '@cloudbeaver/core-localization';
import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk';
import styles from './ConnectionAccessGrantedList.module.css';
import { ConnectionAccessTableHeader, type IFilterState } from './ConnectionAccessTableHeader/ConnectionAccessTableHeader.js';
import { ConnectionAccessTableInnerHeader } from './ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.js';
import { ConnectionAccessTableItem } from './ConnectionAccessTableItem.js';
import { getFilteredTeams, getFilteredUsers } from './getFilteredSubjects.js';
import styles from './ConnectionFormAccessTableGrantedList.module.css';
import { getFilteredUsers, getFilteredTeams } from '../getFilteredSubjects.js';
import { ConnectionFormAccessTableHeader, type IFilterState } from './ConnectionFormAccessTableHeader/ConnectionFormAccessTableHeader.js';
import { ConnectionFormAccessTableInnerHeader } from './ConnectionFormAccessTableHeader/ConnectionFormAccessTableInnerHeader.js';
import { ConnectionFormAccessTableItem } from './ConnectionFormAccessTableItem.js';
interface Props {
grantedUsers: AdminUserInfoFragment[];
@@ -41,7 +41,7 @@ interface Props {
onEdit: () => void;
}
export const ConnectionAccessGrantedList = observer<Props>(function ConnectionAccessGrantedList({
export const ConnectionFormAccessTableGrantedList = observer<Props>(function ConnectionFormAccessTableGrantedList({
grantedUsers,
grantedTeams,
disabled,
@@ -77,23 +77,23 @@ export const ConnectionAccessGrantedList = observer<Props>(function ConnectionAc
return (
<Group className={s(style, { group: true })} box medium overflow>
<div className={s(style, { container: true })}>
<ConnectionAccessTableHeader className={s(style, { connectionAccessTableHeader: true })} filterState={filterState} disabled={disabled}>
<ConnectionFormAccessTableHeader className={s(style, { connectionAccessTableHeader: true })} filterState={filterState} disabled={disabled}>
<Button disabled={disabled || !selected} mod={['outlined']} onClick={revoke}>
{translate('ui_delete')}
</Button>
<Button disabled={disabled} mod={['unelevated']} onClick={props.onEdit}>
{translate('ui_edit')}
</Button>
</ConnectionAccessTableHeader>
</ConnectionFormAccessTableHeader>
<div className={s(style, { tableContainer: true })}>
<Table className={s(style, { table: true })} keys={keys} selectedItems={selectedSubjects}>
<ConnectionAccessTableInnerHeader disabled={disabled} />
<ConnectionFormAccessTableInnerHeader disabled={disabled} />
<TableBody>
<TableItem item="tableInfo" selectDisabled>
<TableColumnValue colSpan={5}>{translate(tableInfoText)}</TableColumnValue>
</TableItem>
{teams.map(team => (
<ConnectionAccessTableItem
<ConnectionFormAccessTableItem
key={team.teamId}
id={team.teamId}
name={team.teamName || team.teamId}
@@ -105,7 +105,7 @@ export const ConnectionAccessGrantedList = observer<Props>(function ConnectionAc
/>
))}
{users.map(user => (
<ConnectionAccessTableItem
<ConnectionFormAccessTableItem
key={user.userId}
id={user.userId}
name={user.userId}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -9,7 +9,7 @@ import { observer } from 'mobx-react-lite';
import { Filter, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import styles from './ConnectionAccessTableHeader.module.css';
import styles from './ConnectionFormAccessTableHeader.module.css';
export interface IFilterState {
filterValue: string;
@@ -21,7 +21,7 @@ interface Props {
className?: string;
}
export const ConnectionAccessTableHeader = observer<React.PropsWithChildren<Props>>(function ConnectionAccessTableHeader({
export const ConnectionFormAccessTableHeader = observer<React.PropsWithChildren<Props>>(function ConnectionFormAccessTableHeader({
filterState,
disabled,
className,
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@ interface Props {
className?: string;
}
export const ConnectionAccessTableInnerHeader = observer<Props>(function ConnectionAccessTableInnerHeader({ disabled, className }) {
export const ConnectionFormAccessTableInnerHeader = observer<Props>(function ConnectionFormAccessTableInnerHeader({ disabled, className }) {
const translate = useTranslate();
return (
<TableHeader className={className} fixed>
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -9,7 +9,7 @@ import { observer } from 'mobx-react-lite';
import { s, StaticImage, TableColumnValue, TableItem, TableItemSelect, useS } from '@cloudbeaver/core-blocks';
import styles from './ConnectionAccessTableItem.module.css';
import styles from './ConnectionFormAccessTableItem.module.css';
interface Props {
id: any;
@@ -22,7 +22,7 @@ interface Props {
className?: string;
}
export const ConnectionAccessTableItem = observer<Props>(function ConnectionAccessTableItem({
export const ConnectionFormAccessTableItem = observer<Props>(function ConnectionFormAccessTableItem({
id,
name,
description,
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -26,10 +26,10 @@
width: 100%;
}
.connectionAccessTableHeader {
flex: 0 0 auto;
}
.tableContainer {
overflow: auto;
}
.connectionAccessTableHeader {
flex: 0 0 auto;
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -26,11 +26,11 @@ import {
} from '@cloudbeaver/core-blocks';
import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk';
import styles from './ConnectionAccessList.module.css';
import { ConnectionAccessTableHeader, type IFilterState } from './ConnectionAccessTableHeader/ConnectionAccessTableHeader.js';
import { ConnectionAccessTableInnerHeader } from './ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.js';
import { ConnectionAccessTableItem } from './ConnectionAccessTableItem.js';
import { getFilteredTeams, getFilteredUsers } from './getFilteredSubjects.js';
import styles from './ConnectionFormAccessTableList.module.css';
import { getFilteredTeams, getFilteredUsers } from '../getFilteredSubjects.js';
import { ConnectionFormAccessTableHeader, type IFilterState } from './ConnectionFormAccessTableHeader/ConnectionFormAccessTableHeader.js';
import { ConnectionFormAccessTableInnerHeader } from './ConnectionFormAccessTableHeader/ConnectionFormAccessTableInnerHeader.js';
import { ConnectionFormAccessTableItem } from './ConnectionFormAccessTableItem.js';
interface Props {
userList: AdminUserInfoFragment[];
@@ -40,7 +40,13 @@ interface Props {
disabled: boolean;
}
export const ConnectionAccessList = observer<Props>(function ConnectionAccessList({ userList, teamList, grantedSubjects, onGrant, disabled }) {
export const ConnectionFormAccessTableList = observer<Props>(function ConnectionFormAccessTableList({
userList,
teamList,
grantedSubjects,
onGrant,
disabled,
}) {
const props = useObjectRef({ onGrant });
const translate = useTranslate();
const style = useS(styles);
@@ -61,11 +67,11 @@ export const ConnectionAccessList = observer<Props>(function ConnectionAccessLis
return (
<Group className={s(style, { group: true })} box medium overflow>
<div className={s(style, { container: true })}>
<ConnectionAccessTableHeader className={s(style, { connectionAccessTableHeader: true })} filterState={filterState} disabled={disabled}>
<ConnectionFormAccessTableHeader className={s(style, { connectionAccessTableHeader: true })} filterState={filterState} disabled={disabled}>
<Button disabled={disabled || !selected} mod={['unelevated']} onClick={grant}>
{translate('ui_add')}
</Button>
</ConnectionAccessTableHeader>
</ConnectionFormAccessTableHeader>
<div className={s(style, { tableContainer: true })}>
<Table
className={s(style, { table: true })}
@@ -73,7 +79,7 @@ export const ConnectionAccessList = observer<Props>(function ConnectionAccessLis
selectedItems={selectedSubjects}
isItemSelectable={item => !grantedSubjects.includes(item)}
>
<ConnectionAccessTableInnerHeader disabled={disabled} />
<ConnectionFormAccessTableInnerHeader disabled={disabled} />
<TableBody>
{!keys.length && filterState.filterValue && (
<TableItem item="tableInfo" selectDisabled>
@@ -81,7 +87,7 @@ export const ConnectionAccessList = observer<Props>(function ConnectionAccessLis
</TableItem>
)}
{teams.map(team => (
<ConnectionAccessTableItem
<ConnectionFormAccessTableItem
key={team.teamId}
id={team.teamId}
name={team.teamName || team.teamId}
@@ -93,7 +99,7 @@ export const ConnectionAccessList = observer<Props>(function ConnectionAccessLis
/>
))}
{users.map(user => (
<ConnectionAccessTableItem
<ConnectionFormAccessTableItem
key={user.userId}
id={user.userId}
name={user.userId}
@@ -1,15 +1,15 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
export interface IConnectionAccessTabState {
export interface IConnectionFormAccessTabState {
loading: boolean;
loaded: boolean;
grantedSubjects: string[];
initialGrantedSubjects: string[];
editing: boolean;
}
}
@@ -21,4 +21,4 @@ export function getConnectionFormAccessPart(formState: IFormState<IConnectionFor
return new ConnectionFormAccessPart(formState, connectionInfoResource, optionsPart);
});
}
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -1,35 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { LocalizationService } from '@cloudbeaver/core-localization';
@injectable()
export class LocaleService extends Bootstrap {
constructor(private readonly localizationService: LocalizationService) {
super();
}
override register(): void {
this.localizationService.addProvider(this.provider.bind(this));
}
private async provider(locale: string) {
switch (locale) {
case 'ru':
return (await import('./locales/ru.js')).default;
case 'it':
return (await import('./locales/it.js')).default;
case 'zh':
return (await import('./locales/zh.js')).default;
case 'fr':
return (await import('./locales/fr.js')).default;
default:
return (await import('./locales/en.js')).default;
}
}
}
@@ -1,18 +1,12 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 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 { connectionPlugin } from './manifest.js';
export * from './Administration/Connections/ConnectionsAdministration.js';
export * from './Administration/Connections/CreateConnection/Manual/ConnectionManualService.js';
export * from './Administration/Connections/ConnectionsAdministrationNavService.js';
export * from './Administration/Connections/ConnectionsAdministrationService.js';
export * from './Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.js';
export * from './Administration/Connections/CreateConnectionService.js';
export * from './ConnectionForm/ConnectionAccess/ConnectionAccessTabService.js';
export * from './ConnectionFormAccess/ConnectionFormAccessTabService.js';
export default connectionPlugin;
@@ -1,10 +0,0 @@
export default [
['plugin_connections_connection_edit_menu_item_title', 'Edit Connection'],
['plugin_connections_connection_edit_cancel_title', 'Cancel confirmation'],
['plugin_connections_connection_edit_reconnect_title', 'Connection updated'],
['plugin_connections_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'],
['plugin_connections_connection_edit_reconnect_failed', 'Failed to reconnect'],
['connections_administration_deactivate_message', "Your connection's settings will be lost. Do you want to continue?"],
['connections_administration_connection_create_error', 'Failed to create connection'],
];
@@ -1,10 +0,0 @@
export default [
['plugin_connections_connection_edit_menu_item_title', 'Modifier la connexion'],
['plugin_connections_connection_edit_cancel_title', "Confirmation d'annulation"],
['plugin_connections_connection_edit_reconnect_title', 'Connexion mise à jour'],
['plugin_connections_connection_edit_reconnect_message', 'La connexion a été mise à jour. Voulez-vous vous reconnecter ?'],
['plugin_connections_connection_edit_reconnect_failed', 'Échec de la reconnexion'],
['connections_administration_deactivate_message', 'Les paramètres de votre connexion seront perdus. Voulez-vous continuer ?'],
['connections_administration_connection_create_error', 'Failed to create connection'],
];
@@ -1,5 +0,0 @@
export default [
['plugin_connections_connection_edit_menu_item_title', 'Modifica Connessione'],
['plugin_connections_connection_edit_cancel_title', "Conferma l'annullamento"],
['connections_administration_connection_create_error', 'Failed to create connection'],
];
@@ -1,10 +0,0 @@
export default [
['plugin_connections_connection_edit_menu_item_title', 'Изменить подключение'],
['plugin_connections_connection_edit_cancel_title', 'Отмена редактирования'],
['plugin_connections_connection_edit_reconnect_title', 'Подключение обновлено'],
['plugin_connections_connection_edit_reconnect_message', 'Подключение было обновлено. Вы хотите переподключиться?'],
['plugin_connections_connection_edit_reconnect_failed', 'Не удалось переподключиться'],
['connections_administration_deactivate_message', 'Настройки вашего подключения будут потеряны. Вы хотите продолжить?'],
['connections_administration_connection_create_error', 'Не удалось создать подключение'],
];
@@ -1,10 +0,0 @@
export default [
['plugin_connections_connection_edit_menu_item_title', '编辑连接'],
['plugin_connections_connection_edit_cancel_title', '取消确认'],
['plugin_connections_connection_edit_reconnect_title', '连接已更新'],
['plugin_connections_connection_edit_reconnect_message', '连接已更新。您想重新连接吗?'],
['plugin_connections_connection_edit_reconnect_failed', '重新连接失败'],
['connections_administration_deactivate_message', '您的连接设置将丢失。您要继续吗?'],
['connections_administration_connection_create_error', 'Failed to create connection'],
];
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -12,13 +12,5 @@ export const connectionPlugin: PluginManifest = {
name: 'Connections Administration plugin',
},
providers: [
() => import('./LocaleService.js').then(m => m.LocaleService),
() => import('./Administration/Connections/ConnectionsAdministrationService.js').then(m => m.ConnectionsAdministrationService),
() => import('./Administration/Connections/ConnectionsAdministrationNavService.js').then(m => m.ConnectionsAdministrationNavService),
() => import('./Administration/Connections/CreateConnectionService.js').then(m => m.CreateConnectionService),
() => import('./Administration/Connections/CreateConnection/Manual/ConnectionManualService.js').then(m => m.ConnectionManualService),
() => import('./Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.js').then(m => m.CreateConnectionBaseBootstrap),
() => import('./ConnectionForm/ConnectionAccess/ConnectionAccessTabService.js').then(m => m.ConnectionAccessTabService),
],
providers: [() => import('./ConnectionFormAccess/ConnectionFormAccessTabService.js').then(m => m.ConnectionFormAccessTabService)],
};
@@ -31,12 +31,6 @@
{
"path": "../core-di"
},
{
"path": "../core-dialogs"
},
{
"path": "../core-events"
},
{
"path": "../core-executor"
},

Some files were not shown because too many files have changed in this diff Show More