Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7f30576
dbeaver/pro#7880 adds MVP for saving script to cloud storage
sergeyteleshev Apr 2, 2026
1fe973e
removes registerScriptExportController
sergeyteleshev Apr 2, 2026
be0c9c0
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
sergeyteleshev Apr 3, 2026
df24f91
finalizes the ui
sergeyteleshev Apr 3, 2026
35c8d27
adds missing locales
sergeyteleshev Apr 3, 2026
524e81d
introduces footer slot to use CommonDialog api
sergeyteleshev Apr 3, 2026
21d66bf
adds locales
sergeyteleshev Apr 3, 2026
7d26fd8
moves success message to the tab components itself
sergeyteleshev Apr 3, 2026
e2a6a83
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
sergeyteleshev Apr 7, 2026
51138cf
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
sergeyteleshev Apr 8, 2026
c343a4c
pr small fixes
sergeyteleshev Apr 8, 2026
1202f53
saves file with timestamp
sergeyteleshev Apr 8, 2026
6719762
send notification with correct filename
sergeyteleshev Apr 8, 2026
895cc1e
fixes locales
sergeyteleshev Apr 8, 2026
d1c7d51
uses different approach for handling dialog save
sergeyteleshev Apr 8, 2026
6f8f985
cleanup
sergeyteleshev Apr 8, 2026
6a36867
self review fixes
sergeyteleshev Apr 8, 2026
bae6e32
adds lazy import for export dialog
sergeyteleshev Apr 9, 2026
066d16a
uses form API to save the dialog
sergeyteleshev Apr 9, 2026
b2235f1
fixes imports (tab -> panel)
sergeyteleshev Apr 9, 2026
af18122
uses react state for filename
sergeyteleshev Apr 9, 2026
fb5008f
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
sergeyteleshev Apr 9, 2026
428f64e
build fix
sergeyteleshev Apr 9, 2026
55068a7
handles form validation
sergeyteleshev Apr 9, 2026
727dde8
sanitizes file name
sergeyteleshev Apr 9, 2026
244cc0e
removes redundant form layout
sergeyteleshev Apr 10, 2026
691f721
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
sergeyteleshev Apr 12, 2026
c04f44f
fixes bug: allows to load tree root with useTreeData
sergeyteleshev Apr 12, 2026
36704c5
uses context api to resolve export script dialog instead of throwing …
sergeyteleshev Apr 12, 2026
5feff49
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
dariamarutkina Apr 14, 2026
9e963c9
dbeaver/pro#7880 do not show notification on local export
devnaumov Apr 14, 2026
49021d3
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
dariamarutkina Apr 15, 2026
d121b49
dbeaver/pro#7880 remove notification from local export
devnaumov Apr 15, 2026
697a245
Merge branch 'devel' into 7880-save-scripts-to-custom-locations-use-i…
dariamarutkina Apr 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default [
['ui_error_message', 'Error:'],
['ui_error_close', 'Close'],
['ui_clear', 'Clear'],
['ui_file_name', 'File name'],
['ui_remove', 'Remove'],
['ui_close', 'Close'],
['ui_open', 'Open'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default [
['ui_error_message', 'Erreur :'],
['ui_error_close', 'Fermer'],
['ui_clear', 'Effacer'],
['ui_file_name', 'Nom du fichier'],
['ui_remove', 'Supprimer'],
['ui_close', 'Fermer'],
['ui_open', 'Ouvrir'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default [
['ui_error_message', 'Errore:'],
['ui_error_close', 'Chiudi'],
['ui_clear', 'Clear'],
['ui_file_name', 'Nome del file'],
['ui_remove', 'Remove'],
['ui_close', 'Chiudi'],
['ui_open', 'Open'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default [
['ui_error_message', 'Ошибка:'],
['ui_error_close', 'Закрыть'],
['ui_clear', 'Очистить'],
['ui_file_name', 'Имя файла'],
['ui_remove', 'Убрать'],
['ui_close', 'Закрыть'],
['ui_open', 'Открыть'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/vi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default [
['ui_error_message', 'Lỗi:'],
['ui_error_close', 'Đóng'],
['ui_clear', 'Xóa'],
['ui_file_name', 'Tên tệp'],
['ui_remove', 'Xóa'],
['ui_close', 'Đóng'],
['ui_open', 'Mở'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default [
['ui_error_message', '错误:'],
['ui_error_close', '关闭'],
['ui_clear', '清除'],
['ui_file_name', '文件名'],
['ui_remove', '移除'],
['ui_close', '关闭'],
['ui_open', '打开'],
Expand Down
7 changes: 4 additions & 3 deletions webapp/packages/core-ui/src/Tabs/TabPanelList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand All @@ -15,9 +15,10 @@ import { TabsContext } from './TabsContext.js';

export interface TabPanelListProps {
contents?: boolean;
className?: string;
}

export const TabPanelList = observer<React.PropsWithChildren<TabPanelListProps>>(function TabPanelList({ contents, children }) {
export const TabPanelList = observer<React.PropsWithChildren<TabPanelListProps>>(function TabPanelList({ contents, children, className }) {
const state = useContext(TabsContext);

if (!state) {
Expand All @@ -41,7 +42,7 @@ export const TabPanelList = observer<React.PropsWithChildren<TabPanelListProps>>
.map(
generateTabElement(
(tabInfo, key) => (
<TabPanel key={key} tabId={key} contents={contents}>
<TabPanel key={key} tabId={key} contents={contents} className={className}>
{renderPanel(tabInfo, key)}
</TabPanel>
),
Expand Down
47 changes: 47 additions & 0 deletions webapp/packages/plugin-script-export/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "@cloudbeaver/plugin-script-export",
"type": "module",
"sideEffects": [
"./lib/module.js",
"./lib/index.js",
"src/**/*.css",
"src/**/*.scss",
"public/**/*"
],
"version": "0.1.0",
"description": "",
"license": "Apache-2.0",
"exports": {
".": "./lib/index.js",
"./module": "./lib/module.js"
},
"scripts": {
"build": "tsc -b",
"clean": "rimraf --glob lib",
"lint": "eslint ./src/ --ext .ts,.tsx",
"test": "dbeaver-test",
"validate-dependencies": "core-cli-validate-dependencies"
},
"dependencies": {
"@cloudbeaver/core-blocks": "workspace:*",
"@cloudbeaver/core-di": "workspace:*",
"@cloudbeaver/core-dialogs": "workspace:*",
"@cloudbeaver/core-localization": "workspace:*",
"@cloudbeaver/core-ui": "workspace:*",
"mobx": "^6",
"mobx-react-lite": "^4",
"react": "^19",
"react-dom": "^19",
"tslib": "^2"
},
"devDependencies": {
"@cloudbeaver/core-cli": "workspace:*",
"@cloudbeaver/tsconfig": "workspace:*",
"@dbeaver/cli": "workspace:*",
"@types/react": "^19",
"@types/react-dom": "^19",
"rimraf": "^6",
"tslib": "^2",
"typescript": "^5"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 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 { useState } from 'react';

import {
Button,
CommonDialogBody,
CommonDialogFooter,
CommonDialogHeader,
CommonDialogWrapper,
Fill,
Form,
Translate,
useForm,
} from '@cloudbeaver/core-blocks';
import type { DialogComponent } from '@cloudbeaver/core-dialogs';
import { useService } from '@cloudbeaver/core-di';

import { ScriptExportService, type IScriptExportTabProps } from '../ScriptExportService.js';
import { TabList, TabPanelList, TabsState } from '@cloudbeaver/core-ui';

export const ExportScriptDialog: DialogComponent<IScriptExportTabProps> = observer(function ExportScriptDialog({
payload,
resolveDialog,
rejectDialog,
className,
}) {
const scriptExportService = useService(ScriptExportService);
const [selectedTabId, setSelectedTabId] = useState<string | undefined>(undefined);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like you are using this state just to pass to TabsState, you can omit it and keep only container

const form = useForm({
onSubmit() {
resolveDialog();
},
});

return (
<Form context={form}>
<CommonDialogWrapper size="large" className={className} fixedWidth>
<CommonDialogHeader title="plugin_script_export_dialog_title" icon="/icons/export.svg" onReject={rejectDialog} />
<TabsState
container={scriptExportService.tabsContainer}
currentTabId={selectedTabId}
lazy
onChange={tab => setSelectedTabId(tab.tabId)}
{...payload}
>
<CommonDialogBody noBodyPadding noOverflow>
<TabList className="theme-border-color-background tw:shrink-0 tw:px-3" underline />
<TabPanelList className="tw:flex-col tw:gap-4 tw:p-6 tw:w-full tw:overflow-auto" />
</CommonDialogBody>
<CommonDialogFooter>
<Button type="button" variant="secondary" onClick={() => rejectDialog()}>
<Translate token="ui_processing_cancel" />
</Button>
<Fill />
<Button type="button" onClick={() => form.submit()}>
<Translate token="ui_processing_save" />
</Button>
</CommonDialogFooter>
</TabsState>
</CommonDialogWrapper>
</Form>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 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 { importLazyComponent } from '@cloudbeaver/core-blocks';

export const ExportScriptDialog = importLazyComponent(() => import('./ExportScriptDialog.js').then(module => module.ExportScriptDialog));
37 changes: 37 additions & 0 deletions webapp/packages/plugin-script-export/src/LocaleService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 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(() => [LocalizationService])
export class LocaleService extends Bootstrap {
constructor(private readonly localizationService: LocalizationService) {
super();

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;
case 'vi':
return (await import('./locales/vi.js')).default;
case 'en':
default:
return (await import('./locales/en.js')).default;
}
}
}
32 changes: 32 additions & 0 deletions webapp/packages/plugin-script-export/src/ScriptExportService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 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 { TabsContainer } from '@cloudbeaver/core-ui';
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
import { ExportScriptDialog } from './ExportScriptDialog/ExportScriptDialogLazy.js';

export interface IScriptExportTabProps {
script: string;
fileName: string;
editorId: string;
projectId?: string;
connectionId?: string;
}

@injectable(() => [CommonDialogService])
export class ScriptExportService {
readonly tabsContainer: TabsContainer<IScriptExportTabProps>;
Comment thread
devnaumov marked this conversation as resolved.

constructor(private readonly commonDialogService: CommonDialogService) {
this.tabsContainer = new TabsContainer('script_export_tabs');
}

openExportDialog(props: IScriptExportTabProps) {

Check warning on line 29 in webapp/packages/plugin-script-export/src/ScriptExportService.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
return this.commonDialogService.open(ExportScriptDialog, props);
}
}
12 changes: 12 additions & 0 deletions webapp/packages/plugin-script-export/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 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 * from './ScriptExportService.js';
export * from './ExportScriptDialog/ExportScriptDialogLazy.js';

import './module.js';
1 change: 1 addition & 0 deletions webapp/packages/plugin-script-export/src/locales/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [['plugin_script_export_dialog_title', 'Export SQL Script']];
1 change: 1 addition & 0 deletions webapp/packages/plugin-script-export/src/locales/fr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [['plugin_script_export_dialog_title', 'Exporter le script SQL']];
1 change: 1 addition & 0 deletions webapp/packages/plugin-script-export/src/locales/it.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [['plugin_script_export_dialog_title', 'Esporta script SQL']];
1 change: 1 addition & 0 deletions webapp/packages/plugin-script-export/src/locales/ru.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [['plugin_script_export_dialog_title', 'Экспорт SQL-скрипта']];
1 change: 1 addition & 0 deletions webapp/packages/plugin-script-export/src/locales/vi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [['plugin_script_export_dialog_title', 'Xuất tập lệnh SQL']];
1 change: 1 addition & 0 deletions webapp/packages/plugin-script-export/src/locales/zh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [['plugin_script_export_dialog_title', '导出 SQL 脚本']];
19 changes: 19 additions & 0 deletions webapp/packages/plugin-script-export/src/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 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, ModuleRegistry } from '@cloudbeaver/core-di';
import { LocaleService } from './LocaleService.js';
import { ScriptExportService } from './ScriptExportService.js';

export default ModuleRegistry.add({
name: '@cloudbeaver/plugin-script-export',

configure: serviceCollection => {
serviceCollection.addSingleton(Bootstrap, LocaleService).addSingleton(ScriptExportService);
},
});
46 changes: 46 additions & 0 deletions webapp/packages/plugin-script-export/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"extends": "@cloudbeaver/tsconfig/tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
"tsBuildInfoFile": "lib/tsconfig.tsbuildinfo",
"composite": true
},
"references": [
{
"path": "../../common-typescript/@dbeaver/cli"
},
{
"path": "../core-blocks"
},
{
"path": "../core-cli"
},
{
"path": "../core-di"
},
{
"path": "../core-di/tsconfig.json"
},
{
"path": "../core-dialogs"
},
{
"path": "../core-localization"
},
{
"path": "../core-ui"
}
],
"include": [
"__custom_mocks__/**/*",
"src/**/*",
"src/**/*.json",
"src/**/*.css",
"src/**/*.scss"
],
"exclude": [
"**/node_modules",
"lib/**/*"
]
}
1 change: 1 addition & 0 deletions webapp/packages/plugin-set-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"@cloudbeaver/plugin-resource-manager-administration": "workspace:*",
"@cloudbeaver/plugin-resource-manager-scripts": "workspace:*",
"@cloudbeaver/plugin-root": "workspace:*",
"@cloudbeaver/plugin-script-export": "workspace:*",
"@cloudbeaver/plugin-session-expiration": "workspace:*",
"@cloudbeaver/plugin-settings-administration": "workspace:*",
"@cloudbeaver/plugin-settings-default-administration": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions webapp/packages/plugin-set-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ import pluginSqlAsyncTaskConfirmation from '@cloudbeaver/plugin-sql-async-task-c
import pluginDataViewerConditionalFormatting from '@cloudbeaver/plugin-data-viewer-conditional-formatting/module';
import pluginConnectionView from '@cloudbeaver/plugin-connection-view/module';
import pluginConnectionPreferences from '@cloudbeaver/plugin-connection-preferences/module';
import pluginScriptExport from '@cloudbeaver/plugin-script-export/module';

const core = [
coreRouting, // important, should be first because the router starts in load phase first after all plugins register phase
Expand Down Expand Up @@ -171,6 +172,7 @@ export const commonSet = [
pluginGisViewer,
pluginDdlViewer,
pluginObjectViewer,
pluginScriptExport,
pluginSqlEditor,
pluginSqlEditorNavigationTab,
pluginSqlEditorScreen,
Expand Down
Loading
Loading