Compare commits

..

93 Commits

Author SHA1 Message Date
Stela Augustinova 106344b33e Deleted Settings Modal 2025-12-01 16:26:20 +01:00
Stela Augustinova 85a2a4b873 Revert "Button for svg export"
This reverts commit 352b6cbe04.
2025-12-01 16:22:35 +01:00
Stela Augustinova 4ab694de0c Added top border for first menu item 2025-12-01 16:14:23 +01:00
Stela Augustinova 5e193c1725 Removed Other settings component 2025-12-01 16:10:30 +01:00
Stela Augustinova 2b055c028c Update theme command to open settings tab with selected item 2025-12-01 16:00:05 +01:00
Stela Augustinova 6ae381b1fd Merge branch 'master' of https://github.com/dbgate/dbgate 2025-12-01 15:45:42 +01:00
Stela Augustinova 352b6cbe04 Button for svg export 2025-12-01 15:45:16 +01:00
CI workflows e5e6d2701e chore: auto-update github workflows 2025-12-01 14:28:22 +00:00
CI workflows 9ad1924488 Update pro ref 2025-12-01 14:28:07 +00:00
SPRINX0\prochazka 2aadbfc64a v6.7.2-premium-beta.2 2025-12-01 14:51:22 +01:00
Jan Prochazka 1c5d652f93 SYNC: fixed test 2025-12-01 13:34:34 +00:00
SPRINX0\prochazka b2355a3b2d Merge branch 'feature/restore-script' 2025-12-01 14:27:29 +01:00
SPRINX0\prochazka 6bd81cbff5 restore table - comments 2025-12-01 12:17:00 +01:00
SPRINX0\prochazka b912190c5e delete part of restore script 2025-12-01 12:07:44 +01:00
Jan Prochazka 43a826e2e5 Merge pull request #1277 from dbgate/feature/handle-full-refresh
Update refresh button to handle full database refresh
2025-12-01 11:07:18 +01:00
SPRINX0\prochazka 8ae64a9dcf restore script - update 2025-12-01 11:06:18 +01:00
Stela Augustinova 4ce9faf39b Update refresh button to handle full database refresh 2025-12-01 10:42:49 +01:00
SPRINX0\prochazka d650d91d82 table restore script WIP 2025-12-01 10:08:00 +01:00
SPRINX0\prochazka d3322a4a15 Merge branch 'feature/table-backups' 2025-11-28 16:10:18 +01:00
SPRINX0\prochazka a65842e31f table backups 2025-11-28 16:07:36 +01:00
SPRINX0\prochazka 74fde66b51 lang texts 2025-11-28 15:37:34 +01:00
SPRINX0\prochazka c3ea155a7b refresh database options 2025-11-28 15:35:38 +01:00
Jan Prochazka c4b81e3d2c Merge pull request #1275 from dbgate/feature/settings-tab
Feature/settings tab
2025-11-28 13:59:41 +01:00
Stela Augustinova 6f6ed1a741 Remove unused tip styles from various settings components 2025-11-28 13:26:45 +01:00
Stela Augustinova 311680c090 Add commands for viewing application logs and managing plugins; update settings tab integration 2025-11-28 13:23:02 +01:00
SPRINX0\prochazka 5e54aa553a skip incremental analysis test for postgres 2025-11-28 12:47:59 +01:00
SPRINX0\prochazka 6913970830 postgresql primary key loading optimalization 2025-11-28 12:32:18 +01:00
Jan Prochazka 014e453e57 removed ttable incremental analysis for postgres 2025-11-28 12:13:32 +01:00
Jan Prochazka 25b5341f76 fix tests 2025-11-28 11:54:24 +01:00
SPRINX0\prochazka 1df51f9609 skip incremental analysis check 2025-11-28 11:01:22 +01:00
Jan Prochazka 65d13189b3 postgres analyser fixed - broken loading FKs in incremental analysis 2025-11-28 10:24:53 +01:00
Jan Prochazka 0913011120 test fix 2025-11-28 08:21:04 +01:00
Stela Augustinova 30ddc18eb1 Add ai settings component to SettingsTab 2025-11-27 16:35:45 +01:00
Jan Prochazka 697d755744 test fix 2025-11-27 16:25:24 +01:00
Jan Prochazka e3f23ddc79 fixed test 2025-11-27 15:44:31 +01:00
Jan Prochazka 094acc40e8 jest reporters 2025-11-27 15:13:28 +01:00
Jan Prochazka ebd4991de8 Revert "jest reporters"
This reverts commit d04a8fad4c.
2025-11-27 15:12:15 +01:00
Jan Prochazka d04a8fad4c jest reporters 2025-11-27 14:55:40 +01:00
CI workflows cb14bffc5a chore: auto-update github workflows 2025-11-27 13:48:04 +00:00
Jan Prochazka a4c4d17381 test reporters 2025-11-27 14:47:43 +01:00
Stela Augustinova 21eb27f6e3 Added new settings components, added wrapper to all setting components 2025-11-27 14:42:24 +01:00
Jan Prochazka abf0fc7942 incremental analysis in alter table tests 2025-11-27 14:06:48 +01:00
SPRINX0\prochazka c2703edfde prettier 2025-11-27 11:03:12 +01:00
SPRINX0\prochazka d14b90ab20 foreign key editor UX 2025-11-27 10:29:33 +01:00
SPRINX0\prochazka 48f4924932 prettier format 2025-11-27 09:29:39 +01:00
Stela Augustinova 765551988a Added keyboard shortcuts to settings tab 2025-11-27 09:23:36 +01:00
Stela Augustinova 4883eb0d1b Merge branch 'master' into feature/settings-tab 2025-11-27 09:12:34 +01:00
Stela Augustinova 06a9a93d1c Added translation tag for settings 2025-11-27 09:11:33 +01:00
SPRINX0\prochazka c92a0e1d43 fixed search in keyboard shortcuts #1273 2025-11-27 08:58:11 +01:00
Stela Augustinova c6b5ee164b Added settings tab and settings components 2025-11-26 16:21:07 +01:00
SPRINX0\prochazka c65075f887 v6.7.2-alpha.1 2025-11-26 14:43:54 +01:00
SPRINX0\prochazka a1f678a3a1 additional connnection options for dbmodel 2025-11-26 14:43:18 +01:00
Jan Prochazka fe3fefaa4e Merge pull request #1272 from dbgate/feature/translation4
Feature/translation4
2025-11-26 14:12:14 +01:00
Jan Prochazka 3ccebcb0d1 Merge pull request #1271 from dbgate/feature/translation-script
Feature/translation script
2025-11-26 14:10:01 +01:00
Jan Prochazka dbbae0eef2 Merge pull request #1270 from dbgate/feature/columns-filters-panel-visibility
Feature/columns filters panel visibility
2025-11-26 09:54:50 +01:00
Stela Augustinova f11c4881f3 Update gitinore 2025-11-25 16:08:36 +01:00
Stela Augustinova 6398c6d7ce Added new translations 2025-11-25 16:03:55 +01:00
Stela Augustinova 973ce8c3a7 Load OpenAI API key 2025-11-25 16:02:44 +01:00
Stela Augustinova d971869283 Add collapsed left column store for SQL editor settings 2025-11-25 15:17:16 +01:00
SPRINX0\prochazka 987002b8f3 v6.7.1 2025-11-25 14:58:33 +01:00
SPRINX0\prochazka f73fe495a5 changelog 2025-11-25 14:57:56 +01:00
Stela Augustinova fe7b0e2bc7 Add translation script using OpenAI for missing keys (not finished) 2025-11-25 14:38:23 +01:00
Stela Augustinova 23937c54e0 Added checkbox to hide columns/filters panel by default 2025-11-25 13:37:19 +01:00
SPRINX0\prochazka b3d0fd9d2f SYNC: fixed E2e test 2025-11-25 11:09:40 +00:00
SPRINX0\prochazka 497aaf6143 v6.7.1-premium-beta.5 2025-11-25 10:34:09 +01:00
SPRINX0\prochazka 9d6db3a93b v6.7.1-beta.4 2025-11-25 10:33:47 +01:00
CI workflows 8a6f3e6809 chore: auto-update github workflows 2025-11-25 09:22:33 +00:00
CI workflows 6c419716a4 Update pro ref 2025-11-25 09:22:15 +00:00
SPRINX0\prochazka d1a769205c SYNC: support additional objects in team files 2025-11-25 09:22:02 +00:00
Stela Augustinova b784e342c9 Translation - added translation tags for import/export, connection tab 2025-11-25 10:07:41 +01:00
CI workflows 0d82fd51c7 chore: auto-update github workflows 2025-11-25 08:21:06 +00:00
CI workflows 3b4d905485 Update pro ref 2025-11-25 08:20:50 +00:00
SPRINX0\prochazka 53c63f0f4b SYNC: diagrams supported in team files 2025-11-25 08:20:39 +00:00
SPRINX0\prochazka 5553e3cd8d SYNC: Handle error when saving to team files 2025-11-24 16:35:08 +00:00
Stela Augustinova 1e195e07e0 Translation - added translation tags for import/export 2025-11-24 17:02:34 +01:00
Stela Augustinova b6f0e15951 Translation - add translation tags for logs 2025-11-24 16:48:29 +01:00
Stela Augustinova da224303fe Translation - added translation tags for widgets 2025-11-24 16:29:29 +01:00
SPRINX0\prochazka 67ee130a9e japanese localization 2025-11-24 16:20:59 +01:00
CI workflows 18d908fa63 chore: auto-update github workflows 2025-11-24 14:40:35 +00:00
CI workflows c61f58854e Update pro ref 2025-11-24 14:40:16 +00:00
SPRINX0\prochazka f789ecd2f1 SYNC: japanese settings 2025-11-24 14:40:04 +00:00
CI workflows 1fdc30804a chore: auto-update github workflows 2025-11-24 14:31:03 +00:00
CI workflows 5ba10d0acb Update pro ref 2025-11-24 14:30:50 +00:00
SPRINX0\prochazka 12803d8154 SYNC: admin settings 2025-11-24 14:30:38 +00:00
CI workflows 36c391ccff chore: auto-update github workflows 2025-11-24 14:27:45 +00:00
CI workflows 765fb6297c Update pro ref 2025-11-24 14:27:06 +00:00
SPRINX0\prochazka 66255769ad SYNC: support for browser default language 2025-11-24 14:26:54 +00:00
CI workflows 04a8d38641 chore: auto-update github workflows 2025-11-24 14:20:00 +00:00
CI workflows 859d020031 Update pro ref 2025-11-24 14:19:44 +00:00
SPRINX0\prochazka 3c541117d0 SYNC: change language for Team Premium 2025-11-24 14:19:33 +00:00
SPRINX0\prochazka 80ca2e5215 Add the LANG environment variable for the web version. #1266 2025-11-24 14:26:25 +01:00
SPRINX0\prochazka 19f2aa2997 smaller upgrade button #1244 2025-11-24 10:57:57 +01:00
Jan Prochazka ec657f30c7 Merge pull request #1268 from dbgate/feature/sort-sql
Feature/sort sql
2025-11-24 09:04:06 +01:00
95 changed files with 4095 additions and 1237 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
-18
View File
@@ -42,24 +42,6 @@ jobs:
run: |
cd packages/tools
yarn test:ci
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: integration-tests/result.json
action-name: Integration tests
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/filterparser/result.json
action-name: Filter parser test results
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/datalib/result.json
action-name: Datalib (perspectives) test results
services:
postgres-integr:
image: postgres
+1
View File
@@ -24,6 +24,7 @@ docker/plugins
.env.development.local
.env.test.local
.env.production.local
.env.translation
npm-debug.log*
yarn-debug.log*
+13
View File
@@ -8,6 +8,19 @@ Builds:
- linux - application for linux
- win - application for Windows
## 6.7.1
- ADDED: LANGUAGE environment variable for the web version. #1266
- ADDED: New localizations (Italian, Portugese (Brazil), Japanese)
- ADDED: Option to detect language from browser settings in web version
- FIXED: Check updates option no longer available in 6.7.0 #1263
- FIXED: A MERGE statement must be terminated by a semi-colon (;), but dbgate stripped it. #1257
- ADDED: Show table size #552
- ADDED: Sort tables by size and by row count
- ADDED: Connect to Legacy MongoDB (Premium) #540
- FIXED: Fixed problems in saving team files in Team Premium edition
- CHANGED: Files are by default saved to team folders in Team Premium edition
- ADDED: Other files types supported in Team Premium edition (diagrams, query design, perspectives, import/export jobs, shell scripts, database compare jobs)
## 6.7.0
- ADDED: Added localization support, now you can use DbGate in multiple languages (French, Spanish, German, Czech, Slovak, Simplified Chinese) #347 #705 #939 #1079
- CHANGED: Solved many issues with binary fields, huge performance improvements in binary fields processing
+4
View File
@@ -76,6 +76,8 @@ module.exports = ({ editMenu, isMac }, currentTranslations = null) => [
{ command: 'app.zoomIn', hideDisabled: true },
{ command: 'app.zoomOut', hideDisabled: true },
{ command: 'app.zoomReset', hideDisabled: true },
{ divider: true },
{ command: 'app.showLogs', hideDisabled: true },
],
},
{
@@ -95,6 +97,8 @@ module.exports = ({ editMenu, isMac }, currentTranslations = null) => [
{ divider: true },
{ command: 'app.exportConnections', hideDisabled: true },
{ command: 'app.importConnections', hideDisabled: true },
{ divider: true },
{ command: 'app.managePlugins', hideDisabled: true },
],
},
...(isMac
+132
View File
@@ -0,0 +1,132 @@
require('dotenv').config({ path: '.env.translation' });
const fs = require('fs');
const path = require('path');
const OpenAI = require('openai');
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const translationsDir = path.join(__dirname, '../../translations');
const enFilePath = path.join(translationsDir, 'en.json');
const languageNames = {
'cs.json': 'Czech',
'de.json': 'German',
'es.json': 'Spanish',
'fr.json': 'French',
'it.json': 'Italian',
'ja.json': 'Japanese',
'pt.json': 'Portuguese',
'sk.json': 'Slovak',
'zh.json': 'Chinese'
};
// Read source (english)
const enTranslations = JSON.parse(fs.readFileSync(enFilePath, 'utf8'));
const enKeys = Object.keys(enTranslations);
// Get all translation files
const translationFiles = fs.readdirSync(translationsDir)
.filter(file => file.endsWith('.json') && file !== 'en.json')
.sort();
console.log(`Found ${enKeys.length} keys in en.json\n`);
console.log('='.repeat(80));
async function translateMissingIds({file, translations, missingIds}){
const languageName = languageNames[file];
if (!languageName) {
console.log(`No language name mapping for file: ${file}`);
return;
}
// Build object with only missing translations
const needed = {};
missingIds.forEach(key => {
needed[key] = enTranslations[key];
});
// Get all existing translations as style examples
const existingTranslations = {};
Object.keys(translations).forEach(key => {
if (translations[key] && !translations[key].startsWith('***')) {
existingTranslations[key] = {
en: enTranslations[key],
translated: translations[key]
};
}
});
const prompt = `You are a professional translator for DbGate, a database management application.
Translate the following English UI strings to ${languageName}.
IMPORTANT RULES:
1. Preserve ALL placeholders exactly as they appear: {plugin}, {columnNumber}, {0}, {1}, etc.
2. Maintain technical terminology appropriately for database software
3. Match the translation style, tone, and formality of the existing translations shown below
4. Keep the same level of brevity or verbosity as the existing translations
5. Return ONLY valid JSON - no markdown, no explanations, no code blocks
6. Use the same keys as provided
EXISTING TRANSLATIONS (for style reference):
${JSON.stringify(existingTranslations, null, 2)}
STRINGS TO TRANSLATE:
${JSON.stringify(needed, null, 2)}
Return format: {"key": "translated value", ...}`;
const response = await client.chat.completions.create({
model: 'gpt-5.1',
messages: [
{ role: 'system', content: 'You are a professional translator specializing in software localization. Match the style and tone of existing translations. Return only valid JSON.' },
{ role: 'user', content: prompt }
],
temperature: 0.2
});
let translatedJson = response.choices[0].message.content.trim();
// Remove markdown code blocks if present
translatedJson = translatedJson.replace(/^```json\n?/, '').replace(/\n?```$/, '');
return JSON.parse(translatedJson);
}
(async () => {
for (const file of translationFiles) {
const filePath = path.join(translationsDir, file);
const translations = JSON.parse(fs.readFileSync(filePath, 'utf8'));
const missingIds = enKeys.filter(key => !translations.hasOwnProperty(key) || (typeof translations[key] === 'string' && translations[key].startsWith('***')));
console.log(`\n${file.toUpperCase()}`);
console.log('-'.repeat(80));
if (missingIds.length === 0) {
console.log('✓ All translations complete!');
continue;
} else {
console.log(`Found ${missingIds.length} untranslated IDs\n`);
}
const newTranslations = await translateMissingIds({file, translations, missingIds});
if (!newTranslations) {
console.log(`Skipping file due to translation error: ${file}`);
continue;
}
for (const [key, value] of Object.entries(newTranslations)) {
translations[key] = value;
console.log(`Translated: ${key} => ${value}`);
}
fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + '\n', 'utf8');
console.log(`\n✓ Updated translations written to ${file}`);
}
console.log('\n' + '='.repeat(80));
console.log('Translation complete!\n');
})();
+1 -1
View File
@@ -60,7 +60,7 @@ describe('Data browser data', () => {
cy.contains('MyChinook').click();
cy.testid('SqlObjectList_search').clear().type('album');
cy.contains('Tables (1/11)');
cy.contains('347 rows, InnoDB');
cy.contains('347 rows, 65.5 KB, InnoDB');
cy.testid('SqlObjectList_searchMenuDropDown').click();
cy.contains('Column name').click();
cy.contains('Tables (2/11)');
@@ -12,6 +12,7 @@ const {
} = require('dbgate-tools');
function pickImportantTableInfo(engine, table) {
if (!table) return table;
const props = ['columnName', 'defaultValue'];
if (!engine.skipNullability) props.push('notNull');
if (!engine.skipAutoIncrement) props.push('autoIncrement');
@@ -25,6 +26,13 @@ function pickImportantTableInfo(engine, table) {
.map(props =>
_.omitBy(props, (v, k) => k == 'defaultValue' && v == 'NULL' && engine.setNullDefaultInsteadOfDrop)
),
// foreignKeys: table.foreignKeys
// .sort((a, b) => a.refTableName.localeCompare(b.refTableName))
// .map(fk => ({
// constraintType: fk.constraintType,
// refTableName: fk.refTableName,
// columns: fk.columns.map(col => ({ columnName: col.columnName, refColumnName: col.refColumnName })),
// })),
};
}
@@ -33,7 +41,7 @@ function checkTableStructure(engine, t1, t2) {
expect(pickImportantTableInfo(engine, t1)).toEqual(pickImportantTableInfo(engine, t2));
}
async function testTableDiff(engine, conn, driver, mangle) {
async function testTableDiff(engine, conn, driver, mangle, changedTable = 't1') {
const initQuery = formatQueryWithoutParams(driver, `create table ~t0 (~id int not null primary key)`);
await driver.query(conn, transformSqlForEngine(engine, initQuery));
@@ -68,17 +76,38 @@ async function testTableDiff(engine, conn, driver, mangle) {
await driver.query(conn, transformSqlForEngine(engine, query));
}
const tget = x => x.tables.find(y => y.pureName == 't1');
const structure1 = generateDbPairingId(extendDatabaseInfo(await driver.analyseFull(conn)));
if (!engine.skipReferences) {
const query = formatQueryWithoutParams(
driver,
`create table ~t3 (~id int not null primary key, ~fkval int ${
driver.dialect.implicitNullDeclaration ? '' : 'null'
})`
);
await driver.query(conn, transformSqlForEngine(engine, query));
}
const tget = x => x?.tables?.find(y => y.pureName == changedTable);
const structure1Source = await driver.analyseFull(conn);
const structure1 = generateDbPairingId(extendDatabaseInfo(structure1Source));
let structure2 = _.cloneDeep(structure1);
mangle(tget(structure2));
structure2 = extendDatabaseInfo(structure2);
const { sql } = getAlterTableScript(tget(structure1), tget(structure2), {}, structure1, structure2, driver);
// sleep 1s - some engines have update datetime precision only to seconds
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('RUNNING ALTER SQL', driver.engine, ':', sql);
await driver.script(conn, sql);
// if (!engine.skipIncrementalAnalysis) {
// const structure2RealIncremental = await driver.analyseIncremental(conn, structure1Source);
// checkTableStructure(engine, tget(structure2RealIncremental), tget(structure2));
// }
const structure2Real = extendDatabaseInfo(await driver.analyseFull(conn));
checkTableStructure(engine, tget(structure2Real), tget(structure2));
@@ -214,6 +243,48 @@ describe('Alter table', () => {
})
);
test.each(engines.filter(x => !x.skipReferences).map(engine => [engine.label, engine]))(
'Drop FK - %s',
testWrapper(async (conn, driver, engine) => {
await testTableDiff(
engine,
conn,
driver,
tbl => {
tbl.foreignKeys = [];
},
't2'
);
})
);
test.each(engines.filter(x => !x.skipReferences).map(engine => [engine.label, engine]))(
'Create FK - %s',
testWrapper(async (conn, driver, engine) => {
await testTableDiff(
engine,
conn,
driver,
tbl => {
tbl.foreignKeys = [
{
constraintType: 'foreignKey',
pureName: 't3',
refTableName: 't1',
columns: [
{
columnName: 'fkval',
refColumnName: 'col_ref',
},
],
},
];
},
't3'
);
})
);
// test.each(engines.map(engine => [engine.label, engine]))(
// 'Change autoincrement - %s',
// testWrapper(async (conn, driver, engine) => {
@@ -28,12 +28,14 @@ describe('Schema tests', () => {
const count = schemas1.length;
expect(structure1.tables.length).toEqual(2);
await runCommandOnDriver(conn, driver, dmp => dmp.createSchema('myschema'));
const structure2 = await driver.analyseIncremental(conn, structure1);
const schemas2 = await driver.listSchemas(conn);
expect(schemas2.find(x => x.schemaName == 'myschema')).toBeTruthy();
expect(schemas2.length).toEqual(count + 1);
expect(schemas2.find(x => x.isDefault).schemaName).toEqual(engine.defaultSchemaName);
expect(structure2).toBeNull();
if (!engine.skipIncrementalAnalysis) {
const structure2 = await driver.analyseIncremental(conn, structure1);
const schemas2 = await driver.listSchemas(conn);
expect(schemas2.find(x => x.schemaName == 'myschema')).toBeTruthy();
expect(schemas2.length).toEqual(count + 1);
expect(schemas2.find(x => x.isDefault).schemaName).toEqual(engine.defaultSchemaName);
expect(structure2).toBeNull();
}
})
);
@@ -48,10 +50,12 @@ describe('Schema tests', () => {
expect(schemas1.find(x => x.schemaName == 'myschema')).toBeTruthy();
expect(structure1.tables.length).toEqual(2);
await runCommandOnDriver(conn, driver, dmp => dmp.dropSchema('myschema'));
const structure2 = await driver.analyseIncremental(conn, structure1);
const schemas2 = await driver.listSchemas(conn);
expect(schemas2.find(x => x.schemaName == 'myschema')).toBeFalsy();
expect(structure2).toBeNull();
if (!engine.skipIncrementalAnalysis) {
const structure2 = await driver.analyseIncremental(conn, structure1);
const schemas2 = await driver.listSchemas(conn);
expect(schemas2.find(x => x.schemaName == 'myschema')).toBeFalsy();
expect(structure2).toBeNull();
}
})
);
+4 -3
View File
@@ -187,6 +187,7 @@ const mariaDbEngine = {
/** @type {import('dbgate-types').TestEngineInfo} */
const postgreSqlEngine = {
label: 'PostgreSQL',
skipIncrementalAnalysis: true,
connection: {
engine: 'postgres@dbgate-plugin-postgres',
password: 'Pwd2020Db',
@@ -757,11 +758,11 @@ const enginesOnCi = [
const enginesOnLocal = [
// all engines, which would be run on local test
// cassandraEngine,
//mysqlEngine,
// mysqlEngine,
// mariaDbEngine,
//postgreSqlEngine,
postgreSqlEngine,
//sqlServerEngine,
sqliteEngine,
// sqliteEngine,
// cockroachDbEngine,
// clickhouseEngine,
// libsqlFileEngine,
+1
View File
@@ -1,3 +1,4 @@
module.exports = {
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
reporters: ['default', 'github-actions'],
};
+1 -1
View File
@@ -18,7 +18,7 @@
},
"devDependencies": {
"cross-env": "^7.0.3",
"jest": "^27.0.1",
"jest": "^28.1.3",
"pino-pretty": "^11.2.2",
"tmp": "^0.2.3"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"private": true,
"version": "6.7.1-premium-beta.3",
"version": "6.7.2-premium-beta.2",
"name": "dbgate-all",
"workspaces": [
"packages/*",
+2
View File
@@ -71,6 +71,7 @@ module.exports = {
const isLicenseValid = checkedLicense?.status == 'ok';
const logoutUrl = storageConnectionError ? null : await authProvider.getLogoutUrl();
const adminConfig = storageConnectionError ? null : await storage.readConfig({ group: 'admin' });
const settingsConfig = storageConnectionError ? null : await storage.readConfig({ group: 'settings' });
storage.startRefreshLicense();
@@ -121,6 +122,7 @@ module.exports = {
allowPrivateCloud: platformInfo.isElectron || !!process.env.ALLOW_DBGATE_PRIVATE_CLOUD,
...currentVersion,
redirectToDbGateCloudLogin: !!process.env.REDIRECT_TO_DBGATE_CLOUD_LOGIN,
preferrendLanguage: settingsConfig?.['storage.language'] || process.env.LANGUAGE || null,
};
return configResult;
+38 -1
View File
@@ -1533,6 +1533,12 @@ module.exports = {
"columnName": "name",
"dataType": "varchar(250)",
"notNull": true
},
{
"pureName": "team_file_types",
"columnName": "format",
"dataType": "varchar(50)",
"notNull": false
}
],
"foreignKeys": [],
@@ -1549,7 +1555,38 @@ module.exports = {
"preloadedRows": [
{
"id": -1,
"name": "sql"
"name": "sql",
"format": "text"
},
{
"id": -2,
"name": "diagrams",
"format": "json"
},
{
"id": -3,
"name": "query",
"format": "json"
},
{
"id": -4,
"name": "perspectives",
"format": "json"
},
{
"id": -5,
"name": "impexp",
"format": "json"
},
{
"id": -6,
"name": "shell",
"format": "text"
},
{
"id": -7,
"name": "dbcompare",
"format": "json"
}
]
},
+1
View File
@@ -2,4 +2,5 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
reporters: ['default', 'github-actions'],
};
+14 -1
View File
@@ -35,6 +35,12 @@ program
.option('-u, --user <user>', 'user name')
.option('-p, --password <password>', 'password')
.option('-d, --database <database>', 'database name')
.option('--url <url>', 'database url')
.option('--file <file>', 'database file')
.option('--socket-path <socketPath>', 'socket path')
.option('--service-name <serviceName>', 'service name (for Oracle)')
.option('--auth-type <authType>', 'authentication type')
.option('--use-ssl', 'use SSL connection')
.option('--auto-index-foreign-keys', 'automatically adds indexes to all foreign keys')
.option(
'--load-data-condition <condition>',
@@ -48,7 +54,7 @@ program
.command('deploy <modelFolder>')
.description('Deploys model to database')
.action(modelFolder => {
const { engine, server, user, password, database, transaction } = program.opts();
const { engine, server, user, password, database, url, file, transaction } = program.opts();
// const hooks = [];
// if (program.autoIndexForeignKeys) hooks.push(dbmodel.hooks.autoIndexForeignKeys);
@@ -60,6 +66,13 @@ program
user,
password,
database,
databaseUrl: url,
useDatabaseUrl: !!url,
databaseFile: file,
socketPath: program.socketPath,
serviceName: program.serviceName,
authType: program.authType,
useSsl: program.useSsl,
},
modelFolder,
useTransaction: transaction,
+1
View File
@@ -2,4 +2,5 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
reporters: ['default', 'github-actions'],
};
+5 -2
View File
@@ -1,7 +1,7 @@
import type { SqlDumper } from 'dbgate-types';
import { Command, Select, Update, Delete, Insert } from './types';
import { dumpSqlExpression } from './dumpSqlExpression';
import { dumpSqlFromDefinition, dumpSqlSourceRef } from './dumpSqlSource';
import { dumpSqlFromDefinition, dumpSqlSourceDef, dumpSqlSourceRef } from './dumpSqlSource';
import { dumpSqlCondition } from './dumpSqlCondition';
export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) {
@@ -115,7 +115,10 @@ export function dumpSqlInsert(dmp: SqlDumper, cmd: Insert) {
cmd.fields.map(x => x.targetColumn)
);
dmp.putCollection(',', cmd.fields, x => dumpSqlExpression(dmp, x));
if (dmp.dialect.requireFromDual) {
if (cmd.whereNotExistsSource) {
dmp.put(' ^from ');
dumpSqlSourceDef(dmp, cmd.whereNotExistsSource);
} else if (dmp.dialect.requireFromDual) {
dmp.put(' ^from ^dual ');
}
dmp.put(' ^where ^not ^exists (^select * ^from %f ^where ', cmd.targetTable);
@@ -2,6 +2,7 @@ import _ from 'lodash';
import type { SqlDumper } from 'dbgate-types';
import { Expression, ColumnRefExpression } from './types';
import { dumpSqlSourceRef } from './dumpSqlSource';
import { dumpSqlSelect } from './dumpSqlCommand';
export function dumpSqlExpression(dmp: SqlDumper, expr: Expression) {
switch (expr.exprType) {
@@ -67,5 +68,11 @@ export function dumpSqlExpression(dmp: SqlDumper, expr: Expression) {
});
dmp.put(')');
break;
case 'select':
dmp.put('(');
dumpSqlSelect(dmp, expr.select);
dmp.put(')');
break;
}
}
+8 -1
View File
@@ -44,6 +44,7 @@ export interface Insert {
fields: UpdateField[];
targetTable: NamedObjectInfo;
insertWhereNotExistsCondition?: Condition;
whereNotExistsSource?: Source;
}
export interface AllowIdentityInsert {
@@ -226,6 +227,11 @@ export interface RowNumberExpression {
orderBy: OrderByExpression[];
}
export interface SelectExpression {
exprType: 'select';
select: Select;
}
export type Expression =
| ColumnRefExpression
| ValueExpression
@@ -235,7 +241,8 @@ export type Expression =
| CallExpression
| MethodCallExpression
| TranformExpression
| RowNumberExpression;
| RowNumberExpression
| SelectExpression;
export type OrderByExpression = Expression & { direction: 'ASC' | 'DESC' };
export type ResultField = Expression & { alias?: string };
+1
View File
@@ -2,4 +2,5 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
reporters: ['default', 'github-actions'],
};
+1
View File
@@ -16,6 +16,7 @@ export interface SqlDumper extends AlterProcessor {
transform(type: TransformType, dumpExpr: () => void);
createDatabase(name: string);
dropDatabase(name: string);
comment(value: string);
callableTemplate(func: CallableObjectInfo);
+1 -1
View File
@@ -61,7 +61,7 @@
initializeAppUpdates();
installCloudListeners();
refreshPublicCloudFiles();
saveSelectedLanguageToCache();
saveSelectedLanguageToCache(config.preferrendLanguage);
const electron = getElectron();
if (electron) {
@@ -1,6 +1,7 @@
<script lang="ts" context="module">
import { copyTextToClipboard } from '../utility/clipboard';
import { _t, _tval, DefferedTranslationResult } from '../translations';
import sqlFormatter from 'sql-formatter';
export const extractKey = ({ schemaName, pureName }) => (schemaName ? `${schemaName}.${pureName}` : pureName);
export const createMatcher =
@@ -88,7 +89,8 @@
isRename?: boolean;
isTruncate?: boolean;
isCopyTableName?: boolean;
isDuplicateTable?: boolean;
isTableBackup?: boolean;
isTableRestore?: boolean;
isDiagram?: boolean;
functionName?: string;
isExport?: boolean;
@@ -106,6 +108,8 @@
}
function createMenusCore(objectTypeField, driver, data): DbObjMenuItem[] {
const backupMatch = data.objectTypeField === 'tables' ? data.pureName.match(TABLE_BACKUP_REGEX) : null;
switch (objectTypeField) {
case 'tables':
return [
@@ -175,11 +179,18 @@
isCopyTableName: true,
requiresWriteAccess: false,
},
hasPermission('dbops/table/backup') && {
label: _t('dbObject.createTableBackup', { defaultMessage: 'Create table backup' }),
isDuplicateTable: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/backup') &&
!backupMatch && {
label: _t('dbObject.createTableBackup', { defaultMessage: 'Create table backup' }),
isTableBackup: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/restore') &&
backupMatch && {
label: _t('dbObject.createRestoreScript', { defaultMessage: 'Create restore script' }),
isTableRestore: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/view') && {
label: _t('dbObject.showDiagram', { defaultMessage: 'Show diagram' }),
isDiagram: true,
@@ -637,7 +648,7 @@
});
},
});
} else if (menu.isDuplicateTable) {
} else if (menu.isTableBackup) {
const driver = await getDriver();
const dmp = driver.createDumper();
const newTable = _.cloneDeep(data);
@@ -671,6 +682,25 @@
},
engine: driver.engine,
});
} else if (menu.isTableRestore) {
const backupMatch = data.objectTypeField === 'tables' ? data.pureName.match(TABLE_BACKUP_REGEX) : null;
const driver = await getDriver();
const dmp = driver.createDumper();
const db = await getDatabaseInfo(data);
if (db) {
const originalTable = db?.tables?.find(x => x.pureName == backupMatch[1] && x.schemaName == data.schemaName);
if (originalTable) {
createTableRestoreScript(data, originalTable, dmp);
newQuery({
title: _t('dbObject.restoreScript', {
defaultMessage: 'Restore {name} #',
values: { name: backupMatch[1] },
}),
initialData: sqlFormatter.format(dmp.s),
});
}
}
} else if (menu.isImport) {
const { conid, database } = data;
openImportExportTab({
@@ -1008,6 +1038,8 @@
return handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode, focusTab });
}
export const TABLE_BACKUP_REGEX = /^_(.*)_(\d\d\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)$/;
</script>
<script lang="ts">
@@ -1025,7 +1057,7 @@
} from '../stores';
import openNewTab from '../utility/openNewTab';
import { extractDbNameFromComposite, filterNameCompoud, getConnectionLabel } from 'dbgate-tools';
import { getConnectionInfo } from '../utility/metadataLoaders';
import { getConnectionInfo, getDatabaseInfo } from '../utility/metadataLoaders';
import fullDisplayName from '../utility/fullDisplayName';
import { showModal } from '../modals/modalTools';
import { findEngineDriver } from 'dbgate-tools';
@@ -1047,6 +1079,8 @@
import { getBoolSettingsValue, getOpenDetailOnArrowsSettings } from '../settings/settingsTools';
import { isProApp } from '../utility/proTools';
import formatFileSize from '../utility/formatFileSize';
import { createTableRestoreScript } from '../utility/tableRestoreScript';
import newQuery from '../query/newQuery';
export let data;
export let passProps;
@@ -1086,14 +1120,21 @@
}
$: isPinned = !!$pinnedTables.find(x => testEqual(data, x));
$: backupParsed = data.objectTypeField === 'tables' ? data.pureName.match(TABLE_BACKUP_REGEX) : null;
$: backupTitle =
backupParsed != null
? `${backupParsed[1]} (${backupParsed[2]}-${backupParsed[3]}-${backupParsed[4]} ${backupParsed[5]}:${backupParsed[6]}:${backupParsed[7]})`
: null;
</script>
<AppObjectCore
{...$$restProps}
module={$$props.module}
{data}
title={data.schemaName && !passProps?.hideSchemaName ? `${data.schemaName}.${data.pureName}` : data.pureName}
icon={databaseObjectIcons[data.objectTypeField]}
title={backupTitle ??
(data.schemaName && !passProps?.hideSchemaName ? `${data.schemaName}.${data.pureName}` : data.pureName)}
icon={backupParsed ? 'img table-backup' : databaseObjectIcons[data.objectTypeField]}
menu={createMenu}
showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin}
onPin={passProps?.ingorePin ? null : isPinned ? null : () => pinnedTables.update(list => [...list, data])}
@@ -5,6 +5,7 @@
import getElectron from '../utility/getElectron';
import InlineButtonLabel from '../buttons/InlineButtonLabel.svelte';
import resolveApi, { resolveApiHeaders } from '../utility/resolveApi';
import { _t } from '../translations';
import uuidv1 from 'uuid/v1';
@@ -49,11 +50,11 @@
</script>
{#if electron}
<InlineButton on:click={handleOpenElectronFile} title="Open file" data-testid={$$props['data-testid']}>
<InlineButton on:click={handleOpenElectronFile} title={_t('files.openFile', { defaultMessage: "Open file" })} data-testid={$$props['data-testid']}>
<FontIcon {icon} />
</InlineButton>
{:else}
<InlineButtonLabel on:click={() => {}} title="Upload file" data-testid={$$props['data-testid']} htmlFor={inputId}>
<InlineButtonLabel on:click={() => {}} title={_t('files.uploadFile', { defaultMessage: "Upload file" })} data-testid={$$props['data-testid']} htmlFor={inputId}>
<FontIcon {icon} />
</InlineButtonLabel>
{/if}
+2 -1
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import FormStyledButtonLikeLabel from '../buttons/FormStyledButtonLikeLabel.svelte';
import uploadFiles from '../utility/uploadFiles';
import { _t } from '../translations';
const handleChange = e => {
const files = [...e.target.files];
@@ -9,6 +10,6 @@
</script>
<div class="m-1">
<FormStyledButtonLikeLabel htmlFor="uploadFileButton">Upload file</FormStyledButtonLikeLabel>
<FormStyledButtonLikeLabel htmlFor="uploadFileButton">{_t('files.uploadFile', { defaultMessage: "Upload file" })}</FormStyledButtonLikeLabel>
<input type="file" id="uploadFileButton" hidden on:change={handleChange} />
</div>
@@ -3,7 +3,7 @@ import { currentDatabase, getCurrentDatabase } from '../stores';
import getElectron from '../utility/getElectron';
import registerCommand from './registerCommand';
import { apiCall } from '../utility/api';
import { switchCurrentDatabase } from '../utility/common';
import { getDatabasStatusMenu, switchCurrentDatabase } from '../utility/common';
import { __t } from '../translations';
registerCommand({
@@ -18,33 +18,7 @@ registerCommand({
conid: connection._id,
database: name,
};
return [
{
text: 'Sync model (incremental)',
onClick: () => {
apiCall('database-connections/sync-model', dbid);
},
},
{
text: 'Sync model (full)',
onClick: () => {
apiCall('database-connections/sync-model', { ...dbid, isFullRefresh: true });
},
},
{
text: 'Reopen',
onClick: () => {
apiCall('database-connections/refresh', dbid);
},
},
{
text: 'Disconnect',
onClick: () => {
const electron = getElectron();
if (electron) apiCall('database-connections/disconnect', dbid);
switchCurrentDatabase(null);
},
},
];
return getDatabasStatusMenu(dbid);
},
});
+76 -19
View File
@@ -11,11 +11,11 @@ import {
promoWidgetPreview,
visibleToolbar,
visibleWidgetSideBar,
selectedWidget,
} from '../stores';
import registerCommand from './registerCommand';
import { get } from 'svelte/store';
import AboutModal from '../modals/AboutModal.svelte';
import SettingsModal from '../settings/SettingsModal.svelte';
import SqlGeneratorModal from '../modals/SqlGeneratorModal.svelte';
import { showModal } from '../modals/modalTools';
import newQuery, { newDiagram, newPerspective, newQueryDesign } from '../query/newQuery';
@@ -73,7 +73,14 @@ registerCommand({
category: __t('command.theme', { defaultMessage: 'Theme' }),
name: __t('command.theme.change', { defaultMessage: 'Change' }),
toolbarName: __t('command.theme.changeToolbar', { defaultMessage: 'Change theme' }),
onClick: () => showModal(SettingsModal, { selectedTab: 'theme' }),
onClick: () => openNewTab({
title: 'Settings',
icon: 'icon settings',
tabComponent: 'SettingsTab',
props: {
selectedItem: 'theme',
},
}),
// getSubCommands: () => get(extensions).themes.map(themeCommand),
});
@@ -115,13 +122,13 @@ registerCommand({
toolbar: true,
icon: 'icon new-connection',
toolbarName: __t('command.new.connection', { defaultMessage: 'Add connection' }),
category: __t('command.new', { defaultMessage: 'New'}),
category: __t('command.new', { defaultMessage: 'New' }),
toolbarOrder: 1,
name: __t('command.new.connection', { defaultMessage: 'Connection' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: () => {
openNewTab({
title: 'New Connection',
title: _t('common.newConnection', { defaultMessage: 'New Connection' }),
icon: 'img connection',
tabComponent: 'ConnectionTab',
});
@@ -140,7 +147,7 @@ registerCommand({
!getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase && !!getCloudSigninTokenHolder(),
onClick: () => {
openNewTab({
title: 'New Connection on Cloud',
title: _t('common.newConnectionCloud', { defaultMessage: 'New Connection on Cloud' }),
icon: 'img cloud-connection',
tabComponent: 'ConnectionTab',
props: {
@@ -561,7 +568,10 @@ registerCommand({
testEnabled: () => true,
onClick: () => {
showModal(ConfirmModal, {
message: _t('command.file.resetLayoutConfirm', { defaultMessage: 'Really reset layout data? All opened tabs, settings and layout data will be lost. Connections and saved files will be preserved. After this, restart DbGate for applying changes.' }),
message: _t('command.file.resetLayoutConfirm', {
defaultMessage:
'Really reset layout data? All opened tabs, settings and layout data will be lost. Connections and saved files will be preserved. After this, restart DbGate for applying changes.',
}),
onConfirm: async () => {
await apiCall('config/delete-settings');
localStorage.clear();
@@ -665,7 +675,9 @@ registerCommand({
'currentArchive',
];
for (const key of keys) removeLocalStorage(key);
showSnackbarSuccess(_t('command.view.restart', { defaultMessage: 'Restart DbGate (or reload on web) for applying changes' }));
showSnackbarSuccess(
_t('command.view.restart', { defaultMessage: 'Restart DbGate (or reload on web) for applying changes' })
);
},
});
@@ -762,6 +774,19 @@ if (isProApp()) {
}
if (hasPermission('settings/change')) {
registerCommand({
id: 'settings.settingsTab',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.settingsTab', { defaultMessage: 'Settings tab' }),
onClick: () => {
openNewTab({
title: _t('command.settings.settingsTab', { defaultMessage: 'Settings tab' }),
icon: 'icon settings',
tabComponent: 'SettingsTab',
props: {},
});
},
});
registerCommand({
id: 'settings.commands',
category: __t('command.settings', { defaultMessage: 'Settings' }),
@@ -777,14 +802,14 @@ if (hasPermission('settings/change')) {
testEnabled: () => hasPermission('settings/change'),
});
registerCommand({
id: 'settings.show',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.change', { defaultMessage: 'Change' }),
toolbarName: __t('command.settings', { defaultMessage: 'Settings' }),
onClick: () => showModal(SettingsModal),
testEnabled: () => hasPermission('settings/change'),
});
// registerCommand({
// id: 'settings.show',
// category: __t('command.settings', { defaultMessage: 'Settings' }),
// name: __t('command.settings.change', { defaultMessage: 'Change' }),
// toolbarName: __t('command.settings', { defaultMessage: 'Settings' }),
// onClick: () => showModal(SettingsModal),
// testEnabled: () => hasPermission('settings/change'),
// });
}
registerCommand({
@@ -799,7 +824,9 @@ registerCommand({
registerCommand({
id: 'file.exit',
category: __t('command.file', { defaultMessage: 'File' }),
name: isMac() ? __t('command.file.quit', { defaultMessage: 'Quit' }) : __t('command.file.exit', { defaultMessage: 'Exit' }),
name: isMac()
? __t('command.file.quit', { defaultMessage: 'Quit' })
: __t('command.file.exit', { defaultMessage: 'Exit' }),
// keyText: isMac() ? 'Command+Q' : null,
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('quit-app'),
@@ -862,6 +889,7 @@ export function registerFileCommands({
undoRedo = false,
executeAdditionalCondition = null,
copyPaste = false,
defaultTeamFolder = false,
}) {
if (save) {
registerCommand({
@@ -874,7 +902,7 @@ export function registerFileCommands({
toolbar: true,
isRelatedToTab: true,
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save', folder, format, fileExtension),
onClick: () => saveTabFile(getCurrentEditor(), 'save', folder, format, fileExtension, defaultTeamFolder),
});
registerCommand({
id: idPrefix + '.saveAs',
@@ -882,14 +910,14 @@ export function registerFileCommands({
category,
name: __t('command.saveAs', { defaultMessage: 'Save As' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save-as', folder, format, fileExtension),
onClick: () => saveTabFile(getCurrentEditor(), 'save-as', folder, format, fileExtension, defaultTeamFolder),
});
registerCommand({
id: idPrefix + '.saveToDisk',
category,
name: __t('command.saveToDisk', { defaultMessage: 'Save to disk' }),
testEnabled: () => getCurrentEditor() != null && getElectron() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save-to-disk', folder, format, fileExtension),
onClick: () => saveTabFile(getCurrentEditor(), 'save-to-disk', folder, format, fileExtension, defaultTeamFolder),
});
}
@@ -1202,6 +1230,35 @@ registerCommand({
},
});
if ( hasPermission('application-log'))
{
registerCommand({
id: 'app.showLogs',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.showLogs', { defaultMessage: 'View application logs' }),
onClick: () => {
openNewTab({
title: 'Application log',
icon: 'img applog',
tabComponent: 'AppLogTab',
});
},
});
}
if (hasPermission('widgets/plugins'))
{
registerCommand({
id: 'app.managePlugins',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.managePlugins', { defaultMessage: 'Manage plugins' }),
onClick: () => {
selectedWidget.set('plugins');
visibleWidgetSideBar.set(true);
},
});
}
const electron = getElectron();
if (electron) {
electron.addEventListener('run-command', (e, commandId) => runCommand(commandId));
@@ -17,6 +17,7 @@
import moveDrag from '../utility/moveDrag';
import ColumnLine from './ColumnLine.svelte';
import DomTableRef from './DomTableRef';
import { _t } from '../translations';
export let conid;
export let database;
@@ -185,8 +186,8 @@
const handleSetTableAlias = () => {
showModal(InputTextModal, {
value: alias || '',
label: 'New alias',
header: 'Set table alias',
label: _t('designerTable.newAlias', { defaultMessage: 'New alias' }),
header: _t('designerTable.setTableAlias', { defaultMessage: 'Set table alias' }),
onConfirm: newAlias => {
onChangeTable({
...table,
@@ -210,13 +211,13 @@
return settings?.tableMenu({ designer, designerId, onRemoveTable });
}
return [
{ text: 'Remove', onClick: () => onRemoveTable({ designerId }) },
{ text: _t('common.remove', { defaultMessage: 'Remove' }), onClick: () => onRemoveTable({ designerId }) },
{ divider: true },
settings?.allowTableAlias &&
!isMultipleTableSelection && [
{ text: 'Set table alias', onClick: handleSetTableAlias },
{ text: _t('designerTable.setTableAlias', { defaultMessage: 'Set table alias' }), onClick: handleSetTableAlias },
alias && {
text: 'Remove table alias',
text: _t('designerTable.removeTableAlias', { defaultMessage: 'Remove table alias' }),
onClick: () =>
onChangeTable({
...table,
@@ -225,11 +226,11 @@
},
],
settings?.allowAddAllReferences &&
!isMultipleTableSelection && { text: 'Add references', onClick: () => onAddAllReferences(table) },
settings?.allowChangeColor && { text: 'Change color', onClick: () => onChangeTableColor(table) },
!isMultipleTableSelection && { text: _t('designerTable.addReferences', { defaultMessage: 'Add references' }), onClick: () => onAddAllReferences(table) },
settings?.allowChangeColor && { text: _t('designerTable.changeColor', { defaultMessage: 'Change color' }), onClick: () => onChangeTableColor(table) },
settings?.allowDefineVirtualReferences &&
!isMultipleTableSelection && {
text: 'Define virtual foreign key',
text: _t('designerTable.defineVirtualForeignKey', { defaultMessage: 'Define virtual foreign key' }),
onClick: () => handleDefineVirtualForeignKey(table),
},
settings?.appendTableSystemMenu &&
@@ -0,0 +1,169 @@
<script lang="ts">
import _ from 'lodash';
import HorizontalSplitter from './HorizontalSplitter.svelte';
interface MenuItemDef {
label: string;
slot?: number;
component?: any;
props?: any;
testid?: string;
identifier?: string;
}
export let items: MenuItemDef[];
export let value: string | number = 0;
export let containerMaxWidth = undefined;
export let containerMaxHeight = undefined;
export let flex1 = true;
export let flexColContainer = false;
export let maxHeight100 = false;
export let scrollableContentContainer = false;
export let contentTestId = undefined;
export let onUserChange = null;
export function setValue(index) {
value = index;
}
export function getValue() {
return value;
}
</script>
<div class="main" class:maxHeight100 class:flex1>
<HorizontalSplitter initialValue="20%">
<svelte:fragment slot="1">
<div class="menu">
{#each _.compact(items) as item, index}
<div
class="menu-item"
class:selected={value == (item.identifier ?? index)}
on:click={() => {
value = item.identifier ?? index;
onUserChange?.(item.identifier ?? index);
}}
data-testid={item.testid}
>
<span class="ml-2 noselect">
{item.label}
</span>
</div>
{/each}
</div>
</svelte:fragment>
<svelte:fragment slot="2">
<div
class="content-container"
class:scrollableContentContainer
style:max-height={containerMaxHeight}
data-testid={contentTestId}
>
{#each _.compact(items) as item, index}
<div
class="container"
class:flexColContainer
class:maxHeight100
class:itemVisible={(item.identifier ?? index) == value}
style:max-width={containerMaxWidth}
>
<svelte:component
this={item.component}
{...item.props}
itemVisible={(item.identifier ?? index) == value}
menuControlHiddenItem={(item.identifier ?? index) != value}
/>
</div>
{/each}
</div>
</svelte:fragment>
</HorizontalSplitter>
</div>
<style>
.main {
display: flex;
flex: 1;
}
.main.flex1 {
flex: 1;
max-height: 100%;
}
.main.maxHeight100 {
max-height: 100%;
}
.menu {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
background-color: var(--theme-bg-2);
overflow-x: auto;
}
.menu::-webkit-scrollbar {
width: 7px;
}
.menu-item {
white-space: nowrap;
padding: 12px 20px;
display: flex;
align-items: center;
cursor: pointer;
border-bottom: 1px solid var(--theme-border);
transition: background-color 0.2s ease;
}
.menu-item:first-child {
border-top: 1px solid var(--theme-border);
}
.menu-item:hover {
background-color: var(--theme-bg-hover);
}
.menu-item.selected {
background-color: var(--theme-bg-1);
font-weight: 600;
border-left: 3px solid var(--theme-font-link);
}
.content-container {
flex: 1;
position: relative;
overflow: hidden;
height: 100%;
}
.scrollableContentContainer {
overflow-y: auto;
}
.container.maxHeight100 {
max-height: 100%;
}
.container.flexColContainer {
display: flex;
flex-direction: column;
}
.container {
position: absolute;
display: flex;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow-y: auto;
padding: 20px;
}
.container:not(.itemVisible) {
visibility: hidden;
}
</style>
@@ -7,6 +7,7 @@
import { getFormContext } from './FormProviderCore.svelte';
import FormSelectField from './FormSelectField.svelte';
import { _t } from '../translations';
export let folderName;
export let name;
@@ -28,10 +29,10 @@
<div>
<FormStyledButton
type="button"
value="All files"
value={_t('common.allFiles', { defaultMessage: "All files" })}
on:click={() => setFieldValue(name, _.uniq([...($values[name] || []), ...($files && $files.map(x => x.name))]))}
/>
<FormStyledButton type="button" value="Remove all" on:click={() => setFieldValue(name, [])} />
<FormStyledButton type="button" value={_t('common.removeAll', { defaultMessage: "Remove all" })} on:click={() => setFieldValue(name, [])} />
</div>
</div>
+1
View File
@@ -353,6 +353,7 @@
'img data-deploy': 'mdi mdi-database-settings color-icon-green',
'img arrow-start-here': 'mdi mdi-arrow-down-bold-circle color-icon-green',
'img team-file': 'mdi mdi-account-file color-icon-red',
'img table-backup': 'mdi mdi-cube color-icon-yellow',
};
</script>
+3 -2
View File
@@ -23,6 +23,7 @@
import ElectronFilesInput from './ElectronFilesInput.svelte';
import { addFilesToSourceList } from './ImportExportConfigurator.svelte';
import UploadButton from '../buttons/UploadButton.svelte';
import { _t } from '../translations';
export let setPreviewSource = undefined;
@@ -55,10 +56,10 @@
{:else}
<UploadButton />
{/if}
<FormStyledButton value="Add web URL" on:click={handleAddUrl} />
<FormStyledButton value={_t('importExport.addWebUrl', { defaultMessage: "Add web URL" })} on:click={handleAddUrl} />
</div>
<div class="wrapper">Drag &amp; drop imported files here</div>
<div class="wrapper">{_t('importExport.dragDropImportedFilesHere', { defaultMessage: "Drag & drop imported files here" })}</div>
</div>
<style>
@@ -6,6 +6,7 @@
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
import { _t } from '../translations';
export let conidName;
export let databaseName;
@@ -41,7 +42,7 @@
{#if $dbinfo && $dbinfo[field]?.length > 0}
<FormStyledButton
type="button"
value={`All ${field}`}
value={_t('common.allFields', { defaultMessage: 'All {field}', values: { field } })}
data-testid={`FormTablesSelect_buttonAll_${field}`}
on:click={() =>
setFieldValue(
@@ -52,7 +53,7 @@
{/if}
{/each}
<FormStyledButton type="button" value="Remove all" on:click={() => setFieldValue(name, [])} />
<FormStyledButton type="button" value={_t('common.removeAll', { defaultMessage: "Remove all" })} on:click={() => setFieldValue(name, [])} />
</div>
</div>
@@ -77,6 +77,7 @@
import createRef from '../utility/createRef';
import DropDownButton from '../buttons/DropDownButton.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { _t } from '../translations';
// export let uploadedFile = undefined;
// export let openedFile = undefined;
@@ -211,7 +212,7 @@
</div>
<div class="m-2">
<div class="title"><FontIcon icon="icon tables" /> Map source tables/files</div>
<div class="title"><FontIcon icon="icon tables" /> {_t('importExport.mapSourceTablesFiles', { defaultMessage: "Map source tables/files" })}</div>
{#key targetEditKey}
{#key progressHolder}
@@ -220,34 +221,34 @@
columns={[
{
fieldName: 'source',
header: 'Source',
header: _t('importExport.source', { defaultMessage: "Source" }),
component: SourceName,
getProps: row => ({ name: row }),
},
{
fieldName: 'action',
header: 'Action',
header: _t('importExport.action', { defaultMessage: "Action" }),
component: SourceAction,
getProps: row => ({ name: row, targetDbinfo }),
},
{
fieldName: 'target',
header: 'Target',
header: _t('importExport.target', { defaultMessage: "Target" }),
slot: 1,
},
supportsPreview && {
fieldName: 'preview',
header: 'Preview',
header: _t('importExport.preview', { defaultMessage: "Preview" }),
slot: 0,
},
!!progressHolder && {
fieldName: 'status',
header: 'Status',
header: _t('importExport.status', { defaultMessage: "Status" }),
slot: 3,
},
{
fieldName: 'columns',
header: 'Columns',
header: _t('importExport.columns', { defaultMessage: "Columns" }),
slot: 2,
},
]}
@@ -73,19 +73,19 @@
<div class="column">
{#if direction == 'source'}
<div class="title">
<FontIcon icon="icon import" /> Source configuration
<FontIcon icon="icon import" /> {_t('importExport.sourceConfiguration', { defaultMessage: 'Source configuration' })}
</div>
{/if}
{#if direction == 'target'}
<div class="title">
<FontIcon icon="icon export" /> Target configuration
<FontIcon icon="icon export" /> {_t('importExport.targetConfiguration', { defaultMessage: 'Target configuration' })}
</div>
{/if}
<div class="buttons">
{#if $currentDatabase}
<FormStyledButton
value="Current DB"
value={_t('importExport.currentDatabase', { defaultMessage: "Current DB" })}
on:click={() => {
values.update(x => ({
...x,
@@ -97,7 +97,7 @@
/>
{/if}
<FormStyledButton
value="Current archive"
value={_t('importExport.currentArchive', { defaultMessage: "Current archive" })}
data-testid={direction == 'source'
? 'SourceTargetConfig_buttonCurrentArchive_source'
: 'SourceTargetConfig_buttonCurrentArchive_target'}
@@ -111,7 +111,7 @@
/>
{#if direction == 'target'}
<FormStyledButton
value="New archive"
value={_t('importExport.newArchive', { defaultMessage: "New archive" })}
on:click={() => {
showModal(InputTextModal, {
header: 'Archive',
@@ -133,7 +133,7 @@
<FormSelectField
options={types.filter(x => x.directions.includes(direction))}
name={storageTypeField}
label="Storage type"
label={_t('importExport.storageType', { defaultMessage: "Storage type" })}
/>
{#if format && isProApp()}
@@ -172,9 +172,9 @@
{/if}
{#if storageType == 'database' || storageType == 'query'}
<FormConnectionSelect name={connectionIdField} label="Server" {direction} />
<FormConnectionSelect name={connectionIdField} label={_t('common.server', { defaultMessage: 'Server' })} {direction} />
{#if !$connectionInfo?.singleDatabase}
<FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} label="Database" />
<FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} label={_t('common.database', { defaultMessage: 'Database' })} />
{/if}
{/if}
{#if storageType == 'database'}
@@ -210,7 +210,7 @@
{#if storageType == 'archive'}
<FormArchiveFolderSelect
label="Archive folder"
label={_t('importExport.archiveFolder', { defaultMessage: "Archive folder" })}
name={archiveFolderField}
additionalFolders={_.compact([$values[archiveFolderField]])}
allowCreateNew={direction == 'target'}
+28 -13
View File
@@ -14,6 +14,8 @@
import { closeCurrentModal, showModal } from './modalTools';
import FormCloudFolderSelect from '../forms/FormCloudFolderSelect.svelte';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import { useConfig } from '../utility/metadataLoaders';
import { showSnackbarError } from '../utility/snackbar';
export let data;
export let name;
@@ -24,26 +26,39 @@
export let onSave = undefined;
export let folid;
export let skipLocal = false;
export let defaultTeamFolder = false;
// export let cntid;
const values = writable({ name, cloudFolder: folid ?? '__local' });
const configValue = useConfig();
const values = writable({
name,
cloudFolder: folid ?? '__local',
saveToTeamFolder: !!(getCurrentConfig()?.storageDatabase && defaultTeamFolder),
});
const electron = getElectron();
const handleSubmit = async e => {
const { name, cloudFolder } = e.detail;
if ($values['saveToTeamFolder']) {
const { teamFileId } = await apiCall('team-files/create-new', { fileType: folder, file: name, data });
closeCurrentModal();
if (onSave) {
onSave(name, {
savedFile: name,
savedFolder: folder,
savedFilePath: null,
savedCloudFolderId: null,
savedCloudContentId: null,
savedTeamFileId: teamFileId,
});
const resp = await apiCall('team-files/create-new', { fileType: folder, file: name, data });
if (resp?.apiErrorMessage) {
showSnackbarError(resp.apiErrorMessage);
} else if (resp?.teamFileId) {
closeCurrentModal();
if (onSave) {
onSave(name, {
savedFile: name,
savedFolder: folder,
savedFilePath: null,
savedCloudFolderId: null,
savedCloudContentId: null,
savedTeamFileId: resp.teamFileId,
});
}
} else {
showSnackbarError('Failed to save to team folder.');
}
} else if (cloudFolder === '__local') {
await apiCall('files/save', { folder, file: name, data, format });
@@ -124,7 +139,7 @@
]}
/>
{/if}
{#if getCurrentConfig().storageDatabase}
{#if $configValue?.storageDatabase}
<FormCheckboxField label="Save to team folder" name="saveToTeamFolder" />
{/if}
@@ -8,6 +8,7 @@
import WidgetsInnerContainer from '../widgets/WidgetsInnerContainer.svelte';
import PluginsList from './PluginsList.svelte';
import { filterName } from 'dbgate-tools';
import { _t } from '../translations';
let filter = '';
// let search = '';
@@ -20,7 +21,7 @@
</script>
<SearchBoxWrapper>
<SearchInput placeholder="Search extensions on web" {filter} bind:value={filter} />
<SearchInput placeholder={_t('plugins.searchExtensionsOnWeb', { defaultMessage: 'Search extensions on web' })} {filter} bind:value={filter} />
</SearchBoxWrapper>
<WidgetsInnerContainer>
{#if $plugins?.errorMessage}
@@ -0,0 +1,70 @@
<script lang="ts">
import FormCheckboxField from "../forms/FormCheckboxField.svelte";
import { _t } from "../translations";
import FontIcon from '../icons/FontIcon.svelte';
import FormValues from "../forms/FormValues.svelte";
</script>
<div class="wrapper">
<FormValues let:values>
<div class="heading">{_t('settings.behaviour', { defaultMessage: 'Behaviour' })}</div>
<FormCheckboxField
name="behaviour.useTabPreviewMode"
label={_t('settings.behaviour.useTabPreviewMode', { defaultMessage: 'Use tab preview mode' })}
defaultValue={true}
/>
<FormCheckboxField
name="behaviour.jsonPreviewWrap"
label={_t('settings.behaviour.jsonPreviewWrap', { defaultMessage: 'Wrap JSON in preview' })}
defaultValue={false}
/>
<div class="tip">
<FontIcon icon="img tip" />
{_t('settings.behaviour.singleClickPreview', {
defaultMessage:
'When you single-click or select a file in the "Tables, Views, Functions" view, it is shown in a preview mode and reuses an existing tab (preview tab). This is useful if you are quickly browsing tables and don\'t want every visited table to have its own tab. When you start editing the table or use double-click to open the table from the "Tables" view, a new tab is dedicated to that table.',
})}
</div>
<FormCheckboxField
name="behaviour.openDetailOnArrows"
label={_t('settings.behaviour.openDetailOnArrows', {
defaultMessage: 'Open detail on keyboard navigation',
})}
defaultValue={true}
disabled={values['behaviour.useTabPreviewMode'] === false}
/>
<div class="heading">{_t('settings.confirmations', { defaultMessage: 'Confirmations' })}</div>
<FormCheckboxField
name="skipConfirm.tableDataSave"
label={_t('settings.confirmations.skipConfirm.tableDataSave', {
defaultMessage: 'Skip confirmation when saving table data (SQL)',
})}
/>
<FormCheckboxField
name="skipConfirm.collectionDataSave"
label={_t('settings.confirmations.skipConfirm.collectionDataSave', {
defaultMessage: 'Skip confirmation when saving collection data (NoSQL)',
})}
/>
</FormValues>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
.tip {
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,87 @@
<script lang="ts">
import CheckboxField from "../forms/CheckboxField.svelte";
import FormCheckboxField from "../forms/FormCheckboxField.svelte";
import FormFieldTemplateLarge from "../forms/FormFieldTemplateLarge.svelte";
import FormSelectField from "../forms/FormSelectField.svelte";
import FormTextField from "../forms/FormTextField.svelte";
import FormValues from "../forms/FormValues.svelte";
import { lockedDatabaseMode } from "../stores";
import { _t } from "../translations";
</script>
<div class="wrapper">
<FormValues let:values>
<div class="heading">{_t('settings.connection', { defaultMessage: 'Connection' })}</div>
<FormFieldTemplateLarge
label={_t('settings.connection.showOnlyTabsFromSelectedDatabase', {
defaultMessage: 'Show only tabs from selected database',
})}
type="checkbox"
labelProps={{
onClick: () => {
$lockedDatabaseMode = !$lockedDatabaseMode;
},
}}
>
<CheckboxField checked={$lockedDatabaseMode} on:change={e => ($lockedDatabaseMode = e.target.checked)} />
</FormFieldTemplateLarge>
<FormCheckboxField
name="connection.autoRefresh"
label={_t('settings.connection.autoRefresh', {
defaultMessage: 'Automatic refresh of database model on background',
})}
defaultValue={false}
/>
<FormTextField
name="connection.autoRefreshInterval"
label={_t('settings.connection.autoRefreshInterval', {
defaultMessage: 'Interval between automatic DB structure reloads in seconds',
})}
defaultValue="30"
disabled={values['connection.autoRefresh'] === false}
/>
<FormSelectField
label={_t('settings.connection.sshBindHost', { defaultMessage: 'Local host address for SSH connections' })}
name="connection.sshBindHost"
isNative
defaultValue="127.0.0.1"
options={[
{ value: '127.0.0.1', label: '127.0.0.1 (IPv4)' },
{ value: '::1', label: '::1 (IPv6)' },
{ value: 'localhost', label: 'localhost (domain name)' },
]}
/>
<div class="heading">{_t('settings.session', { defaultMessage: 'Query sessions' })}</div>
<FormCheckboxField
name="session.autoClose"
label={_t('settings.session.autoClose', {
defaultMessage: 'Automatic close query sessions after period without any activity',
})}
defaultValue={true}
/>
<FormTextField
name="session.autoCloseTimeout"
label={_t('settings.session.autoCloseTimeout', {
defaultMessage: 'Interval, after which query session without activity is closed (in minutes)',
})}
defaultValue="15"
disabled={values['session.autoClose'] === false}
/>
</FormValues>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,100 @@
<script lang="ts">
import FormCheckboxField from "../forms/FormCheckboxField.svelte";
import FormSelectField from "../forms/FormSelectField.svelte";
import FormTextField from "../forms/FormTextField.svelte";
import { _t } from "../translations";
import { isProApp } from "../utility/proTools";
</script>
<div class="wrapper">
<div class="heading">{_t('settings.dataGrid.title', { defaultMessage: 'Data grid' })}</div>
<FormTextField
name="dataGrid.pageSize"
label={_t('settings.dataGrid.pageSize', {
defaultMessage: 'Page size (number of rows for incremental loading, must be between 5 and 50000)',
})}
defaultValue="100"
/>
{#if isProApp()}
<FormCheckboxField
name="dataGrid.showHintColumns"
label={_t('settings.dataGrid.showHintColumns', { defaultMessage: 'Show foreign key hints' })}
defaultValue={true}
/>
{/if}
<!-- <FormCheckboxField name="dataGrid.showHintColumns" label="Show foreign key hints" defaultValue={true} /> -->
<FormCheckboxField
name="dataGrid.thousandsSeparator"
label={_t('settings.dataGrid.thousandsSeparator', {
defaultMessage: 'Use thousands separator for numbers',
})}
/>
<FormTextField
name="dataGrid.defaultAutoRefreshInterval"
label={_t('settings.dataGrid.defaultAutoRefreshInterval', {
defaultMessage: 'Default grid auto refresh interval in seconds',
})}
defaultValue="10"
/>
<FormCheckboxField
name="dataGrid.alignNumbersRight"
label={_t('settings.dataGrid.alignNumbersRight', { defaultMessage: 'Align numbers to right' })}
defaultValue={false}
/>
<FormTextField
name="dataGrid.collectionPageSize"
label={_t('settings.dataGrid.collectionPageSize', {
defaultMessage: 'Collection page size (for MongoDB JSON view, must be between 5 and 1000)',
})}
defaultValue="50"
/>
<FormSelectField
label={_t('settings.dataGrid.coloringMode', { defaultMessage: 'Row coloring mode' })}
name="dataGrid.coloringMode"
isNative
defaultValue="36"
options={[
{
value: '36',
label: _t('settings.dataGrid.coloringMode.36', { defaultMessage: 'Every 3rd and 6th row' }),
},
{
value: '2-primary',
label: _t('settings.dataGrid.coloringMode.2-primary', {
defaultMessage: 'Every 2-nd row, primary color',
}),
},
{
value: '2-secondary',
label: _t('settings.dataGrid.coloringMode.2-secondary', {
defaultMessage: 'Every 2-nd row, secondary color',
}),
},
{ value: 'none', label: _t('settings.dataGrid.coloringMode.none', { defaultMessage: 'None' }) },
]}
/>
<FormCheckboxField
name="dataGrid.showAllColumnsWhenSearch"
label={_t('settings.dataGrid.showAllColumnsWhenSearch', {
defaultMessage: 'Show all columns when searching',
})}
defaultValue={false}
/>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,103 @@
<script lang="ts">
import FormCheckboxField from "../forms/FormCheckboxField.svelte";
import FormSelectField from "../forms/FormSelectField.svelte";
import FormValues from "../forms/FormValues.svelte";
import { _t } from "../translations";
import FormDefaultActionField from "./FormDefaultActionField.svelte";
</script>
<div class="wrapper">
<FormValues let:values>
<div class="heading">{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}</div>
<FormSelectField
label={_t('settings.defaultActions.connectionClick', { defaultMessage: 'Connection click' })}
name="defaultAction.connectionClick"
isNative
defaultValue="connect"
options={[
{
value: 'openDetails',
label: _t('settings.defaultActions.connectionClick.openDetails', {
defaultMessage: 'Edit / open details',
}),
},
{
value: 'connect',
label: _t('settings.defaultActions.connectionClick.connect', { defaultMessage: 'Connect' }),
},
{
value: 'none',
label: _t('settings.defaultActions.connectionClick.none', { defaultMessage: 'Do nothing' }),
},
]}
/>
<FormSelectField
label={_t('settings.defaultActions.databaseClick', { defaultMessage: 'Database click' })}
name="defaultAction.databaseClick"
isNative
defaultValue="switch"
options={[
{
value: 'switch',
label: _t('settings.defaultActions.databaseClick.switch', { defaultMessage: 'Switch database' }),
},
{
value: 'none',
label: _t('settings.defaultActions.databaseClick.none', { defaultMessage: 'Do nothing' }),
},
]}
/>
<FormCheckboxField
name="defaultAction.useLastUsedAction"
label={_t('settings.defaultActions.useLastUsedAction', { defaultMessage: 'Use last used action' })}
defaultValue={true}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.tableClick', { defaultMessage: 'Table click' })}
objectTypeField="tables"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.viewClick', { defaultMessage: 'View click' })}
objectTypeField="views"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.materializedViewClick', { defaultMessage: 'Materialized view click' })}
objectTypeField="matviews"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.procedureClick', { defaultMessage: 'Procedure click' })}
objectTypeField="procedures"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.functionClick', { defaultMessage: 'Function click' })}
objectTypeField="functions"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.collectionClick', { defaultMessage: 'NoSQL collection click' })}
objectTypeField="collections"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
</FormValues>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,50 @@
<script lang="ts">
import FormTextField from "../forms/FormTextField.svelte";
import { _t } from "../translations";
</script>
<div class="wrapper">
<div class="heading">{_t('settings.externalTools', { defaultMessage: 'External tools' })}</div>
<FormTextField
name="externalTools.mysqldump"
label={_t('settings.other.externalTools.mysqldump', {
defaultMessage: 'mysqldump (backup MySQL database)',
})}
defaultValue="mysqldump"
/>
<FormTextField
name="externalTools.mysql"
label={_t('settings.other.externalTools.mysql', { defaultMessage: 'mysql (restore MySQL database)' })}
defaultValue="mysql"
/>
<FormTextField
name="externalTools.mysqlPlugins"
label={_t('settings.other.externalTools.mysqlPlugins', {
defaultMessage:
'Folder with mysql plugins (for example for authentication). Set only in case of problems',
})}
defaultValue=""
/>
<FormTextField
name="externalTools.pg_dump"
label={_t('settings.other.externalTools.pg_dump', {
defaultMessage: 'pg_dump (backup PostgreSQL database)',
})}
defaultValue="pg_dump"
/>
<FormTextField
name="externalTools.psql"
label={_t('settings.other.externalTools.psql', { defaultMessage: 'psql (restore PostgreSQL database)' })}
defaultValue="psql"
/>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,126 @@
<script lang="ts">
import { internalRedirectTo } from '../clientAuth';
import CheckboxField from '../forms/CheckboxField.svelte';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import SelectField from '../forms/SelectField.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import { showModal } from '../modals/modalTools';
import { EDITOR_KEYBINDINGS_MODES } from '../query/AceEditor.svelte';
import { currentEditorKeybindigMode, currentEditorWrapEnabled } from '../stores';
import { _t, getSelectedLanguage, setSelectedLanguage } from '../translations';
import { isMac } from '../utility/common';
import getElectron from '../utility/getElectron';
import { isProApp } from '../utility/proTools';
import ConfirmModal from '../modals/ConfirmModal.svelte';
const electron = getElectron();
let restartWarning = false;
</script>
<div class="wrapper">
<div class="heading">{_t('settings.general', { defaultMessage: 'General' })}</div>
{#if electron}
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Appearance' })}</div>
<FormCheckboxField
name="app.useNativeMenu"
label={isMac()
? _t('settings.useNativeWindowTitle', { defaultMessage: 'Use native window title' })
: _t('settings.useSystemNativeMenu', { defaultMessage: 'Use system native menu' })}
on:change={() => {
restartWarning = true;
}}
/>
{#if restartWarning}
<div class="ml-5 mb-3">
<FontIcon icon="img warn" />
{_t('settings.nativeMenuRestartWarning', {
defaultMessage: 'Native menu settings will be applied after app restart',
})}
</div>
{/if}
{/if}
<FormCheckboxField
name="tabGroup.showServerName"
label={_t('settings.tabGroup.showServerName', {
defaultMessage: 'Show server name alongside database name in title of the tab group',
})}
defaultValue={false}
/>
<FormSelectField
label={_t('settings.other.autoUpdateApplication', { defaultMessage: 'Auto update application' })}
name="app.autoUpdateMode"
isNative
defaultValue=""
options={[
{
value: 'skip',
label: _t('settings.other.autoUpdateApplication.skip', {
defaultMessage: 'Do not check for new versions',
}),
},
{
value: '',
label: _t('settings.other.autoUpdateApplication.check', { defaultMessage: 'Check for new versions' }),
},
{
value: 'download',
label: _t('settings.other.autoUpdateApplication.download', {
defaultMessage: 'Check and download new versions',
}),
},
]}
/>
<div class="heading">{_t('settings.localization', { defaultMessage: 'Localization' })}</div>
<FormFieldTemplateLarge
label={_t('settings.localization.language', { defaultMessage: 'Language' })}
type="combo"
>
<SelectField
isNative
data-testid="SettingsModal_languageSelect"
options={[
{ value: 'cs', label: 'Čeština' },
{ value: 'de', label: 'Deutsch' },
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'it', label: 'Italiano' },
{ value: 'pt', label: 'Português (Brasil)' },
{ value: 'sk', label: 'Slovenčina' },
{ value: 'ja', label: '日本語' },
{ value: 'zh', label: '中文' },
]}
defaultValue={getSelectedLanguage()}
value={getSelectedLanguage()}
on:change={e => {
setSelectedLanguage(e.detail);
showModal(ConfirmModal, {
message: _t('settings.localization.reloadWarning', {
defaultMessage: 'Application will be reloaded to apply new language settings',
}),
onConfirm: () => {
setTimeout(() => {
internalRedirectTo(electron ? '/index.html' : '/');
}, 100);
},
});
}}
/>
</FormFieldTemplateLarge>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,91 @@
<script lang="ts">
import { safeFormatDate } from "dbgate-tools";
import FormStyledButton from "../buttons/FormStyledButton.svelte";
import FormTextAreaField from "../forms/FormTextAreaField.svelte";
import FontIcon from "../icons/FontIcon.svelte";
import { _t } from "../translations";
import { apiCall } from "../utility/api";
import { useSettings } from "../utility/metadataLoaders";
import { derived } from "svelte/store";
const settings = useSettings();
const settingsValues = derived(settings, $settings => {
if (!$settings) {
return {};
}
return $settings;
});
let licenseKeyCheckResult = null;
$: licenseKey = $settingsValues['other.licenseKey'];
</script>
<div class="heading">{_t('settings.other.license', { defaultMessage: 'License' })}</div>
<FormTextAreaField
name="other.licenseKey"
label={_t('settings.other.licenseKey', { defaultMessage: 'License key' })}
rows={7}
onChange={async value => {
licenseKeyCheckResult = await apiCall('config/check-license', { licenseKey: value });
}}
/>
{#if licenseKeyCheckResult}
<div class="m-3 ml-5">
{#if licenseKeyCheckResult.status == 'ok'}
<div>
<FontIcon icon="img ok" />
{_t('settings.other.licenseKey.valid', { defaultMessage: 'License key is valid' })}
</div>
{#if licenseKeyCheckResult.validTo}
<div>
{_t('settings.other.licenseKey.validTo', { defaultMessage: 'License valid to:' })}
{licenseKeyCheckResult.validTo}
</div>
{/if}
{#if licenseKeyCheckResult.expiration}
<div>
{_t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' })}
<b>{safeFormatDate(licenseKeyCheckResult.expiration)}</b>
</div>
{/if}
{:else if licenseKeyCheckResult.status == 'error'}
<div>
<FontIcon icon="img error" />
{licenseKeyCheckResult.errorMessage ??
_t('settings.other.licenseKey.invalid', { defaultMessage: 'License key is invalid' })}
{#if licenseKeyCheckResult.expiration}
<div>
{_t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' })}
<b>{safeFormatDate(licenseKeyCheckResult.expiration)}</b>
</div>
{/if}
</div>
{#if licenseKeyCheckResult.isExpired}
<div class="mt-2">
<FormStyledButton
value={_t('settings.other.licenseKey.checkForNew', {
defaultMessage: 'Check for new license key',
})}
skipWidth
on:click={async () => {
licenseKeyCheckResult = await apiCall('config/get-new-license', { oldLicenseKey: licenseKey });
if (licenseKeyCheckResult.licenseKey) {
apiCall('config/update-settings', { 'other.licenseKey': licenseKeyCheckResult.licenseKey });
}
}}
/>
</div>
{/if}
{/if}
</div>
{/if}
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,100 @@
<script lang="ts">
import CheckboxField from "../forms/CheckboxField.svelte";
import FormCheckboxField from "../forms/FormCheckboxField.svelte";
import FormFieldTemplateLarge from "../forms/FormFieldTemplateLarge.svelte";
import FormSelectField from "../forms/FormSelectField.svelte";
import FormTextField from "../forms/FormTextField.svelte";
import SelectField from "../forms/SelectField.svelte";
import { EDITOR_KEYBINDINGS_MODES } from "../query/AceEditor.svelte";
import { currentEditorKeybindigMode, currentEditorWrapEnabled } from "../stores";
import { _t } from "../translations";
</script>
<div class="wrapper">
<div class="heading">{_t('settings.sqlEditor', { defaultMessage: 'SQL editor' })}</div>
<div class="flex">
<div class="col-3">
<FormSelectField
label={_t('settings.sqlEditor.sqlCommandsCase', { defaultMessage: 'SQL commands case' })}
name="sqlEditor.sqlCommandsCase"
isNative
defaultValue="upperCase"
options={[
{ value: 'upperCase', label: 'UPPER CASE' },
{ value: 'lowerCase', label: 'lower case' },
]}
/>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.editor.keybinds', { defaultMessage: 'Editor keybinds' })}
type="combo"
>
<SelectField
isNative
defaultValue="default"
options={EDITOR_KEYBINDINGS_MODES.map(mode => ({ label: mode.label, value: mode.value }))}
value={$currentEditorKeybindigMode}
on:change={e => ($currentEditorKeybindigMode = e.detail)}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.editor.wordWrap', { defaultMessage: 'Enable word wrap' })}
type="combo"
>
<CheckboxField
checked={$currentEditorWrapEnabled}
on:change={e => ($currentEditorWrapEnabled = e.target.checked)}
/>
</FormFieldTemplateLarge>
</div>
</div>
<FormTextField
name="sqlEditor.limitRows"
label={_t('settings.sqlEditor.limitRows', { defaultMessage: 'Return only N rows from query' })}
placeholder={_t('settings.sqlEditor.limitRowsPlaceholder', { defaultMessage: '(No rows limit)' })}
/>
<FormCheckboxField
name="sqlEditor.showTableAliasesInCodeCompletion"
label={_t('settings.sqlEditor.showTableAliasesInCodeCompletion', {
defaultMessage: 'Show table aliases in code completion',
})}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.disableSplitByEmptyLine"
label={_t('settings.sqlEditor.disableSplitByEmptyLine', { defaultMessage: 'Disable split by empty line' })}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.disableExecuteCurrentLine"
label={_t('settings.sqlEditor.disableExecuteCurrentLine', {
defaultMessage: 'Disable current line execution (Execute current)',
})}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.hideColumnsPanel"
label={_t('settings.sqlEditor.hideColumnsPanel', { defaultMessage: 'Hide Columns/Filters panel by default' })}
defaultValue={false}
/>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
</style>
@@ -1,842 +0,0 @@
<script lang="ts">
import _ from 'lodash';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import Link from '../elements/Link.svelte';
import TabControl from '../elements/TabControl.svelte';
import CheckboxField from '../forms/CheckboxField.svelte';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import FormValues from '../forms/FormValues.svelte';
import SelectField from '../forms/SelectField.svelte';
import SettingsFormProvider from '../forms/SettingsFormProvider.svelte';
import TextField from '../forms/TextField.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import ModalBase from '../modals/ModalBase.svelte';
import { closeCurrentModal } from '../modals/modalTools';
import { EDITOR_KEYBINDINGS_MODES, EDITOR_THEMES, FONT_SIZES } from '../query/AceEditor.svelte';
import SqlEditor from '../query/SqlEditor.svelte';
import {
currentEditorFontSize,
currentEditorWrapEnabled,
currentEditorTheme,
currentEditorKeybindigMode,
extensions,
selectedWidget,
lockedDatabaseMode,
visibleWidgetSideBar,
currentTheme,
getSystemTheme,
} from '../stores';
import { isMac } from '../utility/common';
import getElectron from '../utility/getElectron';
import ThemeSkeleton from './ThemeSkeleton.svelte';
import { isProApp } from '../utility/proTools';
import FormTextAreaField from '../forms/FormTextAreaField.svelte';
import { apiCall } from '../utility/api';
import { useSettings } from '../utility/metadataLoaders';
import { derived } from 'svelte/store';
import { safeFormatDate } from 'dbgate-tools';
import FormDefaultActionField from './FormDefaultActionField.svelte';
import AiSettingsTab from './AiSettingsTab.svelte';
import { _t, setSelectedLanguage } from '../translations';
import hasPermission from '../utility/hasPermission';
import ConfirmModal from '../modals/ConfirmModal.svelte';
import { showModal } from '../modals/modalTools';
import { internalRedirectTo } from '../clientAuth';
import { getSelectedLanguage } from '../translations';
const electron = getElectron();
let restartWarning = false;
let licenseKeyCheckResult = null;
export let selectedTab = 'general';
const sqlPreview = `-- example query
SELECT
MAX(Album.AlbumId) AS max_album,
MAX(Album.Title) AS max_title,
Artist.ArtistId,
'album' AS test_string,
123 AS test_number
FROM
Album
INNER JOIN Artist ON Album.ArtistId = Artist.ArtistId
GROUP BY
Artist.ArtistId
ORDER BY
Artist.Name ASC
`;
function openThemePlugins() {
closeCurrentModal();
$selectedWidget = 'plugins';
$visibleWidgetSideBar = true;
}
const settings = useSettings();
const settingsValues = derived(settings, $settings => {
if (!$settings) {
return {};
}
return $settings;
});
$: licenseKey = $settingsValues['other.licenseKey'];
let checkedLicenseKey = false;
$: if (licenseKey && !checkedLicenseKey) {
checkedLicenseKey = true;
apiCall('config/check-license', { licenseKey }).then(result => {
licenseKeyCheckResult = result;
});
}
</script>
<SettingsFormProvider>
<ModalBase {...$$restProps} noPadding fixedHeight>
<div slot="header">{_t('settings.title', { defaultMessage: 'Settings' })}</div>
<FormValues let:values>
<TabControl
bind:value={selectedTab}
isInline
inlineTabs
scrollableContentContainer
containerMaxWidth="100%"
containerMaxHeight="calc(100% - 34px)"
maxHeight100
flex1
tabs={[
hasPermission('settings/change') && {
identifier: 'general',
label: _t('settings.general', { defaultMessage: 'General' }),
slot: 1,
},
isProApp() &&
electron && {
identifier: 'license',
label: _t('settings.license', { defaultMessage: 'License' }),
slot: 7,
},
hasPermission('settings/change') && {
identifier: 'connection',
label: _t('settings.connection', { defaultMessage: 'Connection' }),
slot: 2,
},
{ identifier: 'theme', label: _t('settings.theme', { defaultMessage: 'Themes' }), slot: 3 },
hasPermission('settings/change') && {
identifier: 'default-actions',
label: _t('settings.defaultActions', { defaultMessage: 'Default Actions' }),
slot: 4,
},
hasPermission('settings/change') && {
identifier: 'behaviour',
label: _t('settings.behaviour', { defaultMessage: 'Behaviour' }),
slot: 5,
},
hasPermission('settings/change') && {
identifier: 'external-tools',
label: _t('settings.externalTools', { defaultMessage: 'External tools' }),
slot: 8,
},
hasPermission('settings/change') && {
identifier: 'other',
label: _t('settings.other', { defaultMessage: 'Other' }),
slot: 6,
},
isProApp() && hasPermission('settings/change') && { identifier: 'ai', label: 'AI', slot: 9 },
]}
>
<svelte:fragment slot="1">
{#if electron}
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Appearance' })}</div>
<FormCheckboxField
name="app.useNativeMenu"
label={isMac()
? _t('settings.useNativeWindowTitle', { defaultMessage: 'Use native window title' })
: _t('settings.useSystemNativeMenu', { defaultMessage: 'Use system native menu' })}
on:change={() => {
restartWarning = true;
}}
/>
{#if restartWarning}
<div class="ml-5 mb-3">
<FontIcon icon="img warn" />
{_t('settings.nativeMenuRestartWarning', {
defaultMessage: 'Native menu settings will be applied after app restart',
})}
</div>
{/if}
{/if}
<FormCheckboxField
name="tabGroup.showServerName"
label={_t('settings.tabGroup.showServerName', {
defaultMessage: 'Show server name alongside database name in title of the tab group',
})}
defaultValue={false}
/>
<div class="heading">{_t('settings.localization', { defaultMessage: 'Localization' })}</div>
<FormFieldTemplateLarge
label={_t('settings.localization.language', { defaultMessage: 'Language' })}
type="combo"
>
<SelectField
isNative
data-testid="SettingsModal_languageSelect"
options={[
{ value: 'cs', label: 'Čeština' },
{ value: 'de', label: 'Deutsch' },
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'it', label: 'Italiano' },
{ value: 'pt', label: 'Português (Brasil)' },
{ value: 'sk', label: 'Slovenčina' },
{ value: 'zh', label: '中文' },
]}
defaultValue={getSelectedLanguage()}
value={getSelectedLanguage()}
on:change={e => {
setSelectedLanguage(e.detail);
showModal(ConfirmModal, {
message: _t('settings.localization.reloadWarning', {
defaultMessage: 'Application will be reloaded to apply new language settings',
}),
onConfirm: () => {
setTimeout(() => {
internalRedirectTo(electron ? '/index.html' : '/');
}, 100);
},
});
}}
/>
</FormFieldTemplateLarge>
<div class="heading">{_t('settings.dataGrid.title', { defaultMessage: 'Data grid' })}</div>
<FormTextField
name="dataGrid.pageSize"
label={_t('settings.dataGrid.pageSize', {
defaultMessage: 'Page size (number of rows for incremental loading, must be between 5 and 50000)',
})}
defaultValue="100"
/>
{#if isProApp()}
<FormCheckboxField
name="dataGrid.showHintColumns"
label={_t('settings.dataGrid.showHintColumns', { defaultMessage: 'Show foreign key hints' })}
defaultValue={true}
/>
{/if}
<!-- <FormCheckboxField name="dataGrid.showHintColumns" label="Show foreign key hints" defaultValue={true} /> -->
<FormCheckboxField
name="dataGrid.thousandsSeparator"
label={_t('settings.dataGrid.thousandsSeparator', {
defaultMessage: 'Use thousands separator for numbers',
})}
/>
<FormTextField
name="dataGrid.defaultAutoRefreshInterval"
label={_t('settings.dataGrid.defaultAutoRefreshInterval', {
defaultMessage: 'Default grid auto refresh interval in seconds',
})}
defaultValue="10"
/>
<FormCheckboxField
name="dataGrid.alignNumbersRight"
label={_t('settings.dataGrid.alignNumbersRight', { defaultMessage: 'Align numbers to right' })}
defaultValue={false}
/>
<FormTextField
name="dataGrid.collectionPageSize"
label={_t('settings.dataGrid.collectionPageSize', {
defaultMessage: 'Collection page size (for MongoDB JSON view, must be between 5 and 1000)',
})}
defaultValue="50"
/>
<FormSelectField
label={_t('settings.dataGrid.coloringMode', { defaultMessage: 'Row coloring mode' })}
name="dataGrid.coloringMode"
isNative
defaultValue="36"
options={[
{
value: '36',
label: _t('settings.dataGrid.coloringMode.36', { defaultMessage: 'Every 3rd and 6th row' }),
},
{
value: '2-primary',
label: _t('settings.dataGrid.coloringMode.2-primary', {
defaultMessage: 'Every 2-nd row, primary color',
}),
},
{
value: '2-secondary',
label: _t('settings.dataGrid.coloringMode.2-secondary', {
defaultMessage: 'Every 2-nd row, secondary color',
}),
},
{ value: 'none', label: _t('settings.dataGrid.coloringMode.none', { defaultMessage: 'None' }) },
]}
/>
<FormCheckboxField
name="dataGrid.showAllColumnsWhenSearch"
label={_t('settings.dataGrid.showAllColumnsWhenSearch', {
defaultMessage: 'Show all columns when searching',
})}
defaultValue={false}
/>
<div class="heading">{_t('settings.sqlEditor', { defaultMessage: 'SQL editor' })}</div>
<div class="flex">
<div class="col-3">
<FormSelectField
label={_t('settings.sqlEditor.sqlCommandsCase', { defaultMessage: 'SQL commands case' })}
name="sqlEditor.sqlCommandsCase"
isNative
defaultValue="upperCase"
options={[
{ value: 'upperCase', label: 'UPPER CASE' },
{ value: 'lowerCase', label: 'lower case' },
]}
/>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.editor.keybinds', { defaultMessage: 'Editor keybinds' })}
type="combo"
>
<SelectField
isNative
defaultValue="default"
options={EDITOR_KEYBINDINGS_MODES.map(mode => ({ label: mode.label, value: mode.value }))}
value={$currentEditorKeybindigMode}
on:change={e => ($currentEditorKeybindigMode = e.detail)}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.editor.wordWrap', { defaultMessage: 'Enable word wrap' })}
type="combo"
>
<CheckboxField
checked={$currentEditorWrapEnabled}
on:change={e => ($currentEditorWrapEnabled = e.target.checked)}
/>
</FormFieldTemplateLarge>
</div>
</div>
<FormTextField
name="sqlEditor.limitRows"
label={_t('settings.sqlEditor.limitRows', { defaultMessage: 'Return only N rows from query' })}
placeholder={_t('settings.sqlEditor.limitRowsPlaceholder', { defaultMessage: '(No rows limit)' })}
/>
<FormCheckboxField
name="sqlEditor.showTableAliasesInCodeCompletion"
label={_t('settings.sqlEditor.showTableAliasesInCodeCompletion', {
defaultMessage: 'Show table aliases in code completion',
})}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.disableSplitByEmptyLine"
label={_t('settings.sqlEditor.disableSplitByEmptyLine', { defaultMessage: 'Disable split by empty line' })}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.disableExecuteCurrentLine"
label={_t('settings.sqlEditor.disableExecuteCurrentLine', {
defaultMessage: 'Disable current line execution (Execute current)',
})}
defaultValue={false}
/>
</svelte:fragment>
<svelte:fragment slot="2">
<div class="heading">{_t('settings.connection', { defaultMessage: 'Connection' })}</div>
<FormFieldTemplateLarge
label={_t('settings.connection.showOnlyTabsFromSelectedDatabase', {
defaultMessage: 'Show only tabs from selected database',
})}
type="checkbox"
labelProps={{
onClick: () => {
$lockedDatabaseMode = !$lockedDatabaseMode;
},
}}
>
<CheckboxField checked={$lockedDatabaseMode} on:change={e => ($lockedDatabaseMode = e.target.checked)} />
</FormFieldTemplateLarge>
<FormCheckboxField
name="connection.autoRefresh"
label={_t('settings.connection.autoRefresh', {
defaultMessage: 'Automatic refresh of database model on background',
})}
defaultValue={false}
/>
<FormTextField
name="connection.autoRefreshInterval"
label={_t('settings.connection.autoRefreshInterval', {
defaultMessage: 'Interval between automatic DB structure reloads in seconds',
})}
defaultValue="30"
disabled={values['connection.autoRefresh'] === false}
/>
<FormSelectField
label={_t('settings.connection.sshBindHost', { defaultMessage: 'Local host address for SSH connections' })}
name="connection.sshBindHost"
isNative
defaultValue="127.0.0.1"
options={[
{ value: '127.0.0.1', label: '127.0.0.1 (IPv4)' },
{ value: '::1', label: '::1 (IPv6)' },
{ value: 'localhost', label: 'localhost (domain name)' },
]}
/>
<div class="heading">{_t('settings.session', { defaultMessage: 'Query sessions' })}</div>
<FormCheckboxField
name="session.autoClose"
label={_t('settings.session.autoClose', {
defaultMessage: 'Automatic close query sessions after period without any activity',
})}
defaultValue={true}
/>
<FormTextField
name="session.autoCloseTimeout"
label={_t('settings.session.autoCloseTimeout', {
defaultMessage: 'Interval, after which query session without activity is closed (in minutes)',
})}
defaultValue="15"
disabled={values['session.autoClose'] === false}
/>
</svelte:fragment>
<svelte:fragment slot="3">
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Application theme' })}</div>
<FormFieldTemplateLarge
label={_t('settings.appearance.useSystemTheme', { defaultMessage: 'Use system theme' })}
type="checkbox"
labelProps={{
onClick: () => {
if ($currentTheme) {
$currentTheme = null;
} else {
$currentTheme = getSystemTheme();
}
},
}}
>
<CheckboxField
checked={!$currentTheme}
on:change={e => {
if (e.target['checked']) {
$currentTheme = null;
} else {
$currentTheme = getSystemTheme();
}
}}
/>
</FormFieldTemplateLarge>
<div class="themes">
{#each $extensions.themes as theme}
<ThemeSkeleton {theme} />
{/each}
</div>
<div class="m-5">
{_t('settings.appearance.moreThemes', { defaultMessage: 'More themes are available as' })}
<Link onClick={openThemePlugins}>plugins</Link>
<br />
{_t('settings.appearance.afterInstalling', {
defaultMessage:
'After installing theme plugin (try search "theme" in available extensions) new themes will be available here.',
})}
</div>
<div class="heading">{_t('settings.appearance.editorTheme', { defaultMessage: 'Editor theme' })}</div>
<div class="flex">
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.appearance.editorTheme', { defaultMessage: 'Theme' })}
type="combo"
>
<SelectField
isNative
notSelected={_t('settings.appearance.editorTheme.default', { defaultMessage: '(use theme default)' })}
options={EDITOR_THEMES.map(theme => ({ label: theme, value: theme }))}
value={$currentEditorTheme}
on:change={e => ($currentEditorTheme = e.detail)}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.appearance.fontSize', { defaultMessage: 'Font size' })}
type="combo"
>
<SelectField
isNative
notSelected="(default)"
options={FONT_SIZES}
value={FONT_SIZES.find(x => x.value == $currentEditorFontSize) ? $currentEditorFontSize : 'custom'}
on:change={e => ($currentEditorFontSize = e.detail)}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.appearance.customSize', { defaultMessage: 'Custom size' })}
type="text"
>
<TextField
value={$currentEditorFontSize == 'custom' ? '' : $currentEditorFontSize}
on:change={e => ($currentEditorFontSize = e.target['value'])}
disabled={!!FONT_SIZES.find(x => x.value == $currentEditorFontSize) &&
$currentEditorFontSize != 'custom'}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormTextField
name="editor.fontFamily"
label={_t('settings.appearance.fontFamily', { defaultMessage: 'Editor font family' })}
/>
</div>
</div>
<div class="editor">
<SqlEditor value={sqlPreview} readOnly />
</div>
</svelte:fragment>
<svelte:fragment slot="4">
<div class="heading">{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}</div>
<FormSelectField
label={_t('settings.defaultActions.connectionClick', { defaultMessage: 'Connection click' })}
name="defaultAction.connectionClick"
isNative
defaultValue="connect"
options={[
{
value: 'openDetails',
label: _t('settings.defaultActions.connectionClick.openDetails', {
defaultMessage: 'Edit / open details',
}),
},
{
value: 'connect',
label: _t('settings.defaultActions.connectionClick.connect', { defaultMessage: 'Connect' }),
},
{
value: 'none',
label: _t('settings.defaultActions.connectionClick.none', { defaultMessage: 'Do nothing' }),
},
]}
/>
<FormSelectField
label={_t('settings.defaultActions.databaseClick', { defaultMessage: 'Database click' })}
name="defaultAction.databaseClick"
isNative
defaultValue="switch"
options={[
{
value: 'switch',
label: _t('settings.defaultActions.databaseClick.switch', { defaultMessage: 'Switch database' }),
},
{
value: 'none',
label: _t('settings.defaultActions.databaseClick.none', { defaultMessage: 'Do nothing' }),
},
]}
/>
<FormCheckboxField
name="defaultAction.useLastUsedAction"
label={_t('settings.defaultActions.useLastUsedAction', { defaultMessage: 'Use last used action' })}
defaultValue={true}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.tableClick', { defaultMessage: 'Table click' })}
objectTypeField="tables"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.viewClick', { defaultMessage: 'View click' })}
objectTypeField="views"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.materializedViewClick', { defaultMessage: 'Materialized view click' })}
objectTypeField="matviews"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.procedureClick', { defaultMessage: 'Procedure click' })}
objectTypeField="procedures"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.functionClick', { defaultMessage: 'Function click' })}
objectTypeField="functions"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label={_t('settings.defaultActions.collectionClick', { defaultMessage: 'NoSQL collection click' })}
objectTypeField="collections"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
</svelte:fragment>
<svelte:fragment slot="5">
<div class="heading">{_t('settings.behaviour', { defaultMessage: 'Behaviour' })}</div>
<FormCheckboxField
name="behaviour.useTabPreviewMode"
label={_t('settings.behaviour.useTabPreviewMode', { defaultMessage: 'Use tab preview mode' })}
defaultValue={true}
/>
<FormCheckboxField
name="behaviour.jsonPreviewWrap"
label={_t('settings.behaviour.jsonPreviewWrap', { defaultMessage: 'Wrap JSON in preview' })}
defaultValue={false}
/>
<div class="tip">
<FontIcon icon="img tip" />
{_t('settings.behaviour.singleClickPreview', {
defaultMessage:
'When you single-click or select a file in the "Tables, Views, Functions" view, it is shown in a preview mode and reuses an existing tab (preview tab). This is useful if you are quickly browsing tables and don\'t want every visited table to have its own tab. When you start editing the table or use double-click to open the table from the "Tables" view, a new tab is dedicated to that table.',
})}
</div>
<FormCheckboxField
name="behaviour.openDetailOnArrows"
label={_t('settings.behaviour.openDetailOnArrows', {
defaultMessage: 'Open detail on keyboard navigation',
})}
defaultValue={true}
disabled={values['behaviour.useTabPreviewMode'] === false}
/>
<div class="heading">{_t('settings.confirmations', { defaultMessage: 'Confirmations' })}</div>
<FormCheckboxField
name="skipConfirm.tableDataSave"
label={_t('settings.confirmations.skipConfirm.tableDataSave', {
defaultMessage: 'Skip confirmation when saving table data (SQL)',
})}
/>
<FormCheckboxField
name="skipConfirm.collectionDataSave"
label={_t('settings.confirmations.skipConfirm.collectionDataSave', {
defaultMessage: 'Skip confirmation when saving collection data (NoSQL)',
})}
/>
</svelte:fragment>
<svelte:fragment slot="6">
<div class="heading">{_t('settings.other', { defaultMessage: 'Other' })}</div>
<FormTextField
name="other.gistCreateToken"
label={_t('settings.other.gistCreateToken', { defaultMessage: 'API token for creating error gists' })}
defaultValue=""
/>
<FormSelectField
label={_t('settings.other.autoUpdateApplication', { defaultMessage: 'Auto update application' })}
name="app.autoUpdateMode"
isNative
defaultValue=""
options={[
{
value: 'skip',
label: _t('settings.other.autoUpdateApplication.skip', {
defaultMessage: 'Do not check for new versions',
}),
},
{
value: '',
label: _t('settings.other.autoUpdateApplication.check', { defaultMessage: 'Check for new versions' }),
},
{
value: 'download',
label: _t('settings.other.autoUpdateApplication.download', {
defaultMessage: 'Check and download new versions',
}),
},
]}
/>
{#if isProApp()}
<FormCheckboxField
name="ai.allowSendModels"
label={_t('settings.other.ai.allowSendModels', {
defaultMessage: 'Allow to send DB models and query snippets to AI service',
})}
defaultValue={false}
/>
{/if}
</svelte:fragment>
<svelte:fragment slot="7">
<div class="heading">{_t('settings.other.license', { defaultMessage: 'License' })}</div>
<FormTextAreaField
name="other.licenseKey"
label={_t('settings.other.licenseKey', { defaultMessage: 'License key' })}
rows={7}
onChange={async value => {
licenseKeyCheckResult = await apiCall('config/check-license', { licenseKey: value });
}}
/>
{#if licenseKeyCheckResult}
<div class="m-3 ml-5">
{#if licenseKeyCheckResult.status == 'ok'}
<div>
<FontIcon icon="img ok" />
{_t('settings.other.licenseKey.valid', { defaultMessage: 'License key is valid' })}
</div>
{#if licenseKeyCheckResult.validTo}
<div>
{_t('settings.other.licenseKey.validTo', { defaultMessage: 'License valid to:' })}
{licenseKeyCheckResult.validTo}
</div>
{/if}
{#if licenseKeyCheckResult.expiration}
<div>
{_t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' })}
<b>{safeFormatDate(licenseKeyCheckResult.expiration)}</b>
</div>
{/if}
{:else if licenseKeyCheckResult.status == 'error'}
<div>
<FontIcon icon="img error" />
{licenseKeyCheckResult.errorMessage ??
_t('settings.other.licenseKey.invalid', { defaultMessage: 'License key is invalid' })}
{#if licenseKeyCheckResult.expiration}
<div>
{_t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' })}
<b>{safeFormatDate(licenseKeyCheckResult.expiration)}</b>
</div>
{/if}
</div>
{#if licenseKeyCheckResult.isExpired}
<div class="mt-2">
<FormStyledButton
value={_t('settings.other.licenseKey.checkForNew', {
defaultMessage: 'Check for new license key',
})}
skipWidth
on:click={async () => {
licenseKeyCheckResult = await apiCall('config/get-new-license', { oldLicenseKey: licenseKey });
if (licenseKeyCheckResult.licenseKey) {
apiCall('config/update-settings', { 'other.licenseKey': licenseKeyCheckResult.licenseKey });
}
}}
/>
</div>
{/if}
{/if}
</div>
{/if}
</svelte:fragment>
<svelte:fragment slot="8">
<div class="heading">{_t('settings.externalTools', { defaultMessage: 'External tools' })}</div>
<FormTextField
name="externalTools.mysqldump"
label={_t('settings.other.externalTools.mysqldump', {
defaultMessage: 'mysqldump (backup MySQL database)',
})}
defaultValue="mysqldump"
/>
<FormTextField
name="externalTools.mysql"
label={_t('settings.other.externalTools.mysql', { defaultMessage: 'mysql (restore MySQL database)' })}
defaultValue="mysql"
/>
<FormTextField
name="externalTools.mysqlPlugins"
label={_t('settings.other.externalTools.mysqlPlugins', {
defaultMessage:
'Folder with mysql plugins (for example for authentication). Set only in case of problems',
})}
defaultValue=""
/>
<FormTextField
name="externalTools.pg_dump"
label={_t('settings.other.externalTools.pg_dump', {
defaultMessage: 'pg_dump (backup PostgreSQL database)',
})}
defaultValue="pg_dump"
/>
<FormTextField
name="externalTools.psql"
label={_t('settings.other.externalTools.psql', { defaultMessage: 'psql (restore PostgreSQL database)' })}
defaultValue="psql"
/>
</svelte:fragment>
<svelte:fragment slot="9">
<AiSettingsTab {values} />
</svelte:fragment>
</TabControl>
</FormValues>
<div slot="footer">
<!-- <FormSubmit value="OK" on:click={handleOk} /> -->
<FormStyledButton value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</div>
</ModalBase>
</SettingsFormProvider>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
.tip {
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
.themes {
overflow-x: scroll;
display: flex;
}
.editor {
position: relative;
height: 200px;
width: 400px;
margin-left: var(--dim-large-form-margin);
}
</style>
@@ -0,0 +1,164 @@
<script lang="ts">
import Link from "../elements/Link.svelte";
import CheckboxField from "../forms/CheckboxField.svelte";
import FormFieldTemplateLarge from "../forms/FormFieldTemplateLarge.svelte";
import SelectField from "../forms/SelectField.svelte";
import { currentEditorFontSize, currentEditorTheme, currentTheme, extensions, getSystemTheme, selectedWidget, visibleWidgetSideBar } from "../stores";
import { _t } from "../translations";
import ThemeSkeleton from "./ThemeSkeleton.svelte";
import { EDITOR_THEMES, FONT_SIZES } from '../query/AceEditor.svelte';
import { closeCurrentModal } from "../modals/modalTools";
import TextField from "../forms/TextField.svelte";
import FormTextField from "../forms/FormTextField.svelte";
import SqlEditor from "../query/SqlEditor.svelte";
function openThemePlugins() {
closeCurrentModal();
$selectedWidget = 'plugins';
$visibleWidgetSideBar = true;
}
const sqlPreview = `-- example query
SELECT
MAX(Album.AlbumId) AS max_album,
MAX(Album.Title) AS max_title,
Artist.ArtistId,
'album' AS test_string,
123 AS test_number
FROM
Album
INNER JOIN Artist ON Album.ArtistId = Artist.ArtistId
GROUP BY
Artist.ArtistId
ORDER BY
Artist.Name ASC
`;
</script>
<div class="wrapper">
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Application theme' })}</div>
<FormFieldTemplateLarge
label={_t('settings.appearance.useSystemTheme', { defaultMessage: 'Use system theme' })}
type="checkbox"
labelProps={{
onClick: () => {
if ($currentTheme) {
$currentTheme = null;
} else {
$currentTheme = getSystemTheme();
}
},
}}
>
<CheckboxField
checked={!$currentTheme}
on:change={e => {
if (e.target['checked']) {
$currentTheme = null;
} else {
$currentTheme = getSystemTheme();
}
}}
/>
</FormFieldTemplateLarge>
<div class="themes">
{#each $extensions.themes as theme}
<ThemeSkeleton {theme} />
{/each}
</div>
<div class="m-5">
{_t('settings.appearance.moreThemes', { defaultMessage: 'More themes are available as' })}
<Link onClick={openThemePlugins}>plugins</Link>
<br />
{_t('settings.appearance.afterInstalling', {
defaultMessage:
'After installing theme plugin (try search "theme" in available extensions) new themes will be available here.',
})}
</div>
<div class="heading">{_t('settings.appearance.editorTheme', { defaultMessage: 'Editor theme' })}</div>
<div class="flex">
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.appearance.editorTheme', { defaultMessage: 'Theme' })}
type="combo"
>
<SelectField
isNative
notSelected={_t('settings.appearance.editorTheme.default', { defaultMessage: '(use theme default)' })}
options={EDITOR_THEMES.map(theme => ({ label: theme, value: theme }))}
value={$currentEditorTheme}
on:change={e => ($currentEditorTheme = e.detail)}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.appearance.fontSize', { defaultMessage: 'Font size' })}
type="combo"
>
<SelectField
isNative
notSelected="(default)"
options={FONT_SIZES}
value={FONT_SIZES.find(x => x.value == $currentEditorFontSize) ? $currentEditorFontSize : 'custom'}
on:change={e => ($currentEditorFontSize = e.detail)}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge
label={_t('settings.appearance.customSize', { defaultMessage: 'Custom size' })}
type="text"
>
<TextField
value={$currentEditorFontSize == 'custom' ? '' : $currentEditorFontSize}
on:change={e => ($currentEditorFontSize = e.target['value'])}
disabled={!!FONT_SIZES.find(x => x.value == $currentEditorFontSize) &&
$currentEditorFontSize != 'custom'}
/>
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormTextField
name="editor.fontFamily"
label={_t('settings.appearance.fontFamily', { defaultMessage: 'Editor font family' })}
/>
</div>
</div>
<div class="editor">
<SqlEditor value={sqlPreview} readOnly />
</div>
</div>
<style>
.heading {
font-size: 20px;
margin: 5px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
}
.themes {
display: flex;
flex-wrap: wrap;
margin-left: var(--dim-large-form-margin);
}
.editor {
position: relative;
height: 250px;
width: 400px;
margin-left: var(--dim-large-form-margin);
margin-top: var(--dim-large-form-margin);
margin-bottom: var(--dim-large-form-margin);
}
</style>
@@ -60,7 +60,11 @@
<FormProvider>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">{constraintInfo ? _t('foreignKeyEditor.editForeignKey', { defaultMessage: 'Edit foreign key' }) : _t('foreignKeyEditor.addForeignKey', { defaultMessage: 'Add foreign key' })}</svelte:fragment>
<svelte:fragment slot="header"
>{constraintInfo
? _t('foreignKeyEditor.editForeignKey', { defaultMessage: 'Edit foreign key' })
: _t('foreignKeyEditor.addForeignKey', { defaultMessage: 'Add foreign key' })}</svelte:fragment
>
<div class="largeFormMarker">
<div class="row">
@@ -92,6 +96,19 @@
const name = fullNameFromString(e.detail);
refTableName = name.pureName;
refSchemaName = name.schemaName;
if (!columns?.find(x => x.columnName)) {
const refTable = dbInfo?.tables?.find(
x => x.pureName == refTableName && x.schemaName == refSchemaName
);
if (refTable?.primaryKey) {
columns = refTable.primaryKey.columns.map(col => ({
refColumnName: col.columnName,
}));
} else {
columns = [];
}
}
}
}}
/>
@@ -135,7 +152,8 @@
{_t('foreignKeyEditor.baseColumn', { defaultMessage: 'Base column - ' })}{tableInfo.pureName}
</div>
<div class="col-5 ml-1">
{_t('foreignKeyEditor.refColumn', { defaultMessage: 'Ref column - ' })}{refTableName || _t('foreignKeyEditor.tableNotSet', { defaultMessage: '(table not set)' })}
{_t('foreignKeyEditor.refColumn', { defaultMessage: 'Ref column - ' })}{refTableName ||
_t('foreignKeyEditor.tableNotSet', { defaultMessage: '(table not set)' })}
</div>
</div>
@@ -217,7 +235,11 @@
}}
/>
<FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
<FormStyledButton
type="button"
value={_t('common.close', { defaultMessage: 'Close' })}
on:click={closeCurrentModal}
/>
{#if constraintInfo}
<FormStyledButton
type="button"
+64 -25
View File
@@ -3,8 +3,8 @@
registerCommand({
id: 'tableEditor.addColumn',
category: __t('tableEditor', { defaultMessage: 'Table editor'}),
name: __t('tableEditor.addColumn', { defaultMessage: 'Add column'}),
category: __t('tableEditor', { defaultMessage: 'Table editor' }),
name: __t('tableEditor.addColumn', { defaultMessage: 'Add column' }),
icon: 'icon add-column',
toolbar: true,
isRelatedToTab: true,
@@ -14,8 +14,8 @@
registerCommand({
id: 'tableEditor.addPrimaryKey',
category: __t('tableEditor', { defaultMessage: 'Table editor'}),
name: __t('tableEditor.addPrimaryKey', { defaultMessage: 'Add primary key'}),
category: __t('tableEditor', { defaultMessage: 'Table editor' }),
name: __t('tableEditor.addPrimaryKey', { defaultMessage: 'Add primary key' }),
icon: 'icon add-key',
toolbar: true,
isRelatedToTab: true,
@@ -25,8 +25,8 @@
registerCommand({
id: 'tableEditor.addForeignKey',
category: __t('tableEditor', { defaultMessage: 'Table editor'}),
name: __t('tableEditor.addForeignKey', { defaultMessage: 'Add foreign key'}),
category: __t('tableEditor', { defaultMessage: 'Table editor' }),
name: __t('tableEditor.addForeignKey', { defaultMessage: 'Add foreign key' }),
icon: 'icon add-key',
toolbar: true,
isRelatedToTab: true,
@@ -36,8 +36,8 @@
registerCommand({
id: 'tableEditor.addIndex',
category: __t('tableEditor', { defaultMessage: 'Table editor'}),
name: __t('tableEditor.addIndex', { defaultMessage: 'Add index'}),
category: __t('tableEditor', { defaultMessage: 'Table editor' }),
name: __t('tableEditor.addIndex', { defaultMessage: 'Add index' }),
icon: 'icon add-key',
toolbar: true,
isRelatedToTab: true,
@@ -47,8 +47,8 @@
registerCommand({
id: 'tableEditor.addUnique',
category: __t('tableEditor', { defaultMessage: 'Table editor'}),
name: __t('tableEditor.addUnique', { defaultMessage: 'Add unique'}),
category: __t('tableEditor', { defaultMessage: 'Table editor' }),
name: __t('tableEditor.addUnique', { defaultMessage: 'Add unique' }),
icon: 'icon add-key',
toolbar: true,
isRelatedToTab: true,
@@ -188,7 +188,10 @@
<ObjectListControl
collection={columns?.map((x, index) => ({ ...x, ordinal: index + 1 }))}
title={_t('tableEditor.columns', { defaultMessage: 'Columns ({columnCount})', values: { columnCount: columns?.length || 0 } })}
title={_t('tableEditor.columns', {
defaultMessage: 'Columns ({columnCount})',
values: { columnCount: columns?.length || 0 },
})}
emptyMessage={_t('tableEditor.nocolumnsdefined', { defaultMessage: 'No columns defined' })}
clickable
on:clickrow={e => showModal(ColumnEditorModal, { columnInfo: e.detail, tableInfo, setTableInfo, driver })}
@@ -217,9 +220,7 @@
text: _t('tableEditor.copydefinitions', { defaultMessage: 'Copy definitions' }),
icon: 'icon copy',
onClick: selected => {
const names = selected
.map(x => `${x.columnName} ${x.dataType}${x.notNull ? ' NOT NULL' : ''}`)
.join(',\n');
const names = selected.map(x => `${x.columnName} ${x.dataType}${x.notNull ? ' NOT NULL' : ''}`).join(',\n');
navigator.clipboard.writeText(names);
},
},
@@ -288,9 +289,21 @@
: null,
]}
>
<svelte:fragment slot="0" let:row>{row?.notNull ? _t('tableEditor.notnull', { defaultMessage: 'NOT NULL' }) : _t('tableEditor.null', { defaultMessage: 'NULL' })}</svelte:fragment>
<svelte:fragment slot="1" let:row>{row?.isSparse ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment>
<svelte:fragment slot="2" let:row>{row?.isPersisted ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment>
<svelte:fragment slot="0" let:row
>{row?.notNull
? _t('tableEditor.notnull', { defaultMessage: 'NOT NULL' })
: _t('tableEditor.null', { defaultMessage: 'NULL' })}</svelte:fragment
>
<svelte:fragment slot="1" let:row
>{row?.isSparse
? _t('tableEditor.yes', { defaultMessage: 'YES' })
: _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment
>
<svelte:fragment slot="2" let:row
>{row?.isPersisted
? _t('tableEditor.yes', { defaultMessage: 'YES' })
: _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment
>
<svelte:fragment slot="3" let:row
><Link
onClick={e => {
@@ -299,8 +312,16 @@
}}>{_t('tableEditor.remove', { defaultMessage: 'Remove' })}</Link
></svelte:fragment
>
<svelte:fragment slot="4" let:row>{row?.isUnsigned ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment>
<svelte:fragment slot="5" let:row>{row?.isZerofill ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment>
<svelte:fragment slot="4" let:row
>{row?.isUnsigned
? _t('tableEditor.yes', { defaultMessage: 'YES' })
: _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment
>
<svelte:fragment slot="5" let:row
>{row?.isZerofill
? _t('tableEditor.yes', { defaultMessage: 'YES' })
: _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment
>
<svelte:fragment slot="name" let:row><ColumnLabel {...row} forceIcon /></svelte:fragment>
</ObjectListControl>
@@ -321,7 +342,10 @@
<ObjectListControl
collection={indexes}
onAddNew={isWritable && columns?.length > 0 ? addIndex : null}
title={_t('tableEditor.indexes', { defaultMessage: 'Indexes ({indexCount})', values: { indexCount: indexes?.length || 0 } })}
title={_t('tableEditor.indexes', {
defaultMessage: 'Indexes ({indexCount})',
values: { indexCount: indexes?.length || 0 },
})}
emptyMessage={isWritable ? _t('tableEditor.noindexdefined', { defaultMessage: 'No index defined' }) : null}
clickable
on:clickrow={e => showModal(IndexEditorModal, { constraintInfo: e.detail, tableInfo, setTableInfo, driver })}
@@ -348,7 +372,11 @@
>
<svelte:fragment slot="name" let:row><ConstraintLabel {...row} /></svelte:fragment>
<svelte:fragment slot="0" let:row>{row?.columns.map(x => x.columnName).join(', ')}</svelte:fragment>
<svelte:fragment slot="1" let:row>{row?.isUnique ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment>
<svelte:fragment slot="1" let:row
>{row?.isUnique
? _t('tableEditor.yes', { defaultMessage: 'YES' })
: _t('tableEditor.no', { defaultMessage: 'NO' })}</svelte:fragment
>
<svelte:fragment slot="2" let:row
><Link
onClick={e => {
@@ -364,7 +392,10 @@
<ObjectListControl
collection={uniques}
onAddNew={isWritable && columns?.length > 0 ? addUnique : null}
title={_t('tableEditor.uniqueConstraints', { defaultMessage: 'Unique constraints ({constraintCount})', values: { constraintCount: uniques?.length || 0 } })}
title={_t('tableEditor.uniqueConstraints', {
defaultMessage: 'Unique constraints ({constraintCount})',
values: { constraintCount: uniques?.length || 0 },
})}
emptyMessage={isWritable ? _t('tableEditor.nouniquedefined', { defaultMessage: 'No unique defined' }) : null}
clickable
on:clickrow={e => showModal(UniqueEditorModal, { constraintInfo: e.detail, tableInfo, setTableInfo })}
@@ -401,13 +432,21 @@
<ForeignKeyObjectListControl
collection={foreignKeys}
onAddNew={isWritable && columns?.length > 0 ? addForeignKey : null}
title={_t('tableEditor.foreignKeys', { defaultMessage: 'Foreign keys ({foreignKeyCount})', values: { foreignKeyCount: foreignKeys?.length || 0 } })}
emptyMessage={isWritable ? _t('tableEditor.noforeignkeydefined', { defaultMessage: 'No foreign key defined' }) : null}
title={_t('tableEditor.foreignKeys', {
defaultMessage: 'Foreign keys ({foreignKeyCount})',
values: { foreignKeyCount: foreignKeys?.length || 0 },
})}
emptyMessage={isWritable
? _t('tableEditor.noforeignkeydefined', { defaultMessage: 'No foreign key defined' })
: null}
clickable
onRemove={row => setTableInfo(tbl => editorDeleteConstraint(tbl, row))}
on:clickrow={e => showModal(ForeignKeyEditorModal, { constraintInfo: e.detail, tableInfo, setTableInfo, dbInfo })}
/>
<ForeignKeyObjectListControl collection={dependencies} title={_t('tableEditor.dependencies', { defaultMessage: 'Dependencies' })} />
<ForeignKeyObjectListControl
collection={dependencies}
title={_t('tableEditor.dependencies', { defaultMessage: 'Dependencies' })}
/>
{/if}
</div>
+5 -2
View File
@@ -758,7 +758,7 @@
title="Upgrade to Premium"
data-testid="TabsPanel_buttonUpgrade"
>
<FontIcon icon="icon premium" padRight /> Upgrade
<FontIcon icon="icon premium" /> Upgrade
</div>
{/if}
@@ -803,6 +803,9 @@
cursor: pointer;
font-size: 10pt;
padding: 5px;
margin-top: 3px;
margin-right: 3px;
font-size: 8pt;
}
.upgrade-button:hover {
background: linear-gradient(135deg, #0f5a85, #5c1870);
@@ -822,7 +825,7 @@
}
.tabs-upgrade-button {
right: 120px;
right: 110px;
}
.tabs.can-split {
right: 60px;
+32 -31
View File
@@ -24,6 +24,7 @@
createQuickExportHandlerRef,
registerQuickExportHandler,
} from '../buttons/ToolStripExportButton.svelte';
import { _t } from '../translations';
let loadedRows = [];
let loadedAll = false;
@@ -191,8 +192,8 @@
<SelectField
isNative
options={[
{ label: 'Recent logs', value: 'recent' },
{ label: 'Choose date', value: 'date' },
{ label: _t('logs.recentLogs', { defaultMessage: 'Recent logs' }), value: 'recent' },
{ label: _t('logs.chooseDate', { defaultMessage: 'Choose date' }), value: 'date' },
]}
value={mode}
on:change={e => {
@@ -202,7 +203,7 @@
/>
{#if mode === 'recent'}
<div class="filter-label ml-2">Auto-scroll</div>
<div class="filter-label ml-2">{_t('logs.autoScroll', { defaultMessage: 'Auto-scroll' })}</div>
<input
type="checkbox"
checked={autoScroll}
@@ -213,7 +214,7 @@
{/if}
{#if mode === 'date'}
<div class="filter-label">Date:</div>
<div class="filter-label">{_t('logs.date', { defaultMessage: 'Date:' })}</div>
<DateRangeSelector
onChange={value => {
dateFilter = value;
@@ -225,12 +226,12 @@
data-testid="AdminAuditLogTab_addFilter"
icon="icon filter"
menu={[
{ text: 'Connection ID', onClick: () => filterBy('conid') },
{ text: 'Database', onClick: () => filterBy('database') },
{ text: 'Engine', onClick: () => filterBy('engine') },
{ text: 'Message code', onClick: () => filterBy('msgcode') },
{ text: 'Caller', onClick: () => filterBy('caller') },
{ text: 'Name', onClick: () => filterBy('name') },
{ text: _t('logs.connectionId', { defaultMessage: 'Connection ID' }), onClick: () => filterBy('conid') },
{ text: _t('logs.database', { defaultMessage: 'Database' }), onClick: () => filterBy('database') },
{ text: _t('logs.engine', { defaultMessage: 'Engine' }), onClick: () => filterBy('engine') },
{ text: _t('logs.messageCode', { defaultMessage: 'Message code' }), onClick: () => filterBy('msgcode') },
{ text: _t('logs.caller', { defaultMessage: 'Caller' }), onClick: () => filterBy('caller') },
{ text: _t('logs.name', { defaultMessage: 'Name' }), onClick: () => filterBy('name') },
]}
/>
</div>
@@ -259,15 +260,15 @@
<table>
<thead>
<tr>
<th style="width:80px">Date</th>
<th>Time</th>
<th>Code</th>
<th>Message</th>
<th>Connection</th>
<th>Database</th>
<th>Engine</th>
<th>Caller</th>
<th>Name</th>
<th style="width:80px">{_t('logs.dateTab', { defaultMessage: 'Date' })}</th>
<th>{_t('logs.timeTab', { defaultMessage: 'Time' })}</th>
<th>{_t('logs.codeTab', { defaultMessage: 'Code' })}</th>
<th>{_t('logs.messageTab', { defaultMessage: 'Message' })}</th>
<th>{_t('logs.connectionTab', { defaultMessage: 'Connection' })}</th>
<th>{_t('logs.databaseTab', { defaultMessage: 'Database' })}</th>
<th>{_t('logs.engineTab', { defaultMessage: 'Engine' })}</th>
<th>{_t('logs.callerTab', { defaultMessage: 'Caller' })}</th>
<th>{_t('logs.nameTab', { defaultMessage: 'Name' })}</th>
</tr>
</thead>
<tbody>
@@ -299,14 +300,14 @@
<TabControl
isInline
tabs={_.compact([
{ label: 'Details', slot: 1 },
{ label: _t('logs.details', { defaultMessage: 'Details' }), slot: 1 },
{ label: 'JSON', slot: 2 },
])}
>
<svelte:fragment slot="1">
<div class="details-wrap">
<div class="row">
<div>Message code:</div>
<div>{_t('logs.messageCode', { defaultMessage: 'Message code:' })}</div>
{#if mode == 'date'}
<Link onClick={() => doSetFilter('msgcode', [row.msgcode])}>{row.msgcode || 'N/A'}</Link>
{:else}
@@ -314,15 +315,15 @@
{/if}
</div>
<div class="row">
<div>Message:</div>
<div>{_t('logs.message', { defaultMessage: 'Message:' })}</div>
{row.msg}
</div>
<div class="row">
<div>Time:</div>
<div>{_t('logs.time', { defaultMessage: 'Time:' })}</div>
<b>{row.time ? format(new Date(parseInt(row.time)), 'yyyy-MM-dd HH:mm:ss') : ''}</b>
</div>
<div class="row">
<div>Caller:</div>
<div>{_t('logs.caller', { defaultMessage: 'Caller:' })}</div>
{#if mode == 'date'}
<Link onClick={() => doSetFilter('caller', [row.caller])}>{row.caller || 'N/A'}</Link>
{:else}
@@ -330,7 +331,7 @@
{/if}
</div>
<div class="row">
<div>Name:</div>
<div>{_t('logs.name', { defaultMessage: 'Name:' })}</div>
{#if mode == 'date'}
<Link onClick={() => doSetFilter('name', [row.name])}>{row.name || 'N/A'}</Link>
{:else}
@@ -339,7 +340,7 @@
</div>
{#if row.conid}
<div class="row">
<div>Connection ID:</div>
<div>{_t('logs.connectionId', { defaultMessage: 'Connection ID:' })}</div>
{#if mode == 'date'}
<Link onClick={() => doSetFilter('conid', [row.conid])}
>{formatPossibleUuid(row.conid)}</Link
@@ -351,7 +352,7 @@
{/if}
{#if row.database}
<div class="row">
<div>Database:</div>
<div>{_t('logs.database', { defaultMessage: 'Database:' })}</div>
{#if mode == 'date'}
<Link onClick={() => doSetFilter('database', [row.database])}>{row.database}</Link>
{:else}
@@ -361,7 +362,7 @@
{/if}
{#if row.engine}
<div class="row">
<div>Engine:</div>
<div>{_t('logs.engine', { defaultMessage: 'Engine:' })}</div>
{#if mode == 'date'}
<Link onClick={() => doSetFilter('engine', [row.engine])}>{row.engine}</Link>
{:else}
@@ -381,13 +382,13 @@
{/each}
{#if !loadedRows?.length && mode === 'date'}
<tr>
<td colspan="6">No data for selected date</td>
<td colspan="6">{_t('logs.noDataForSelectedDate', { defaultMessage: "No data for selected date" })}</td>
</tr>
{/if}
{#if !loadedAll && mode === 'date'}
{#key loadedRows}
<tr>
<td colspan="6" bind:this={domLoadNext}>Loading next rows... </td>
<td colspan="6" bind:this={domLoadNext}>{_t('logs.loadingNextRows', { defaultMessage: "Loading next rows..." })}</td>
</tr>
{/key}
{/if}
@@ -402,7 +403,7 @@
data-testid="AdminAuditLogTab_refreshButton"
on:click={() => {
reloadData();
}}>Refresh</ToolStripButton
}}>{_t('logs.refresh', { defaultMessage: 'Refresh' })}</ToolStripButton
>
<ToolStripExportButton {quickExportHandlerRef} />
</svelte:fragment>
+4 -1
View File
@@ -13,6 +13,7 @@
import CommandModal from '../modals/CommandModal.svelte';
import { showModal } from '../modals/modalTools';
import { commandsCustomized } from '../stores';
import { _tval } from '../translations';
$: commandList = _.sortBy(_.values($commandsCustomized), ['category', 'name']);
let filter;
@@ -27,7 +28,9 @@
<div class="table-wrapper">
<TableControl
clickable
rows={commandList.filter(cmd => filterName(filter, cmd['category'], cmd['name'], cmd['keyText'], cmd['id']))}
rows={commandList.filter(cmd =>
filterName(filter, _tval(cmd['category']), _tval(cmd['name']), _tval(cmd['keyText']), cmd['id'])
)}
columns={[
{ header: 'Category', fieldName: 'category' },
{ header: 'Name', fieldName: 'name' },
+1
View File
@@ -8,6 +8,7 @@
folder: 'diagrams',
format: 'json',
fileExtension: 'diagram',
defaultTeamFolder: true,
undoRedo: true,
});
+12 -10
View File
@@ -10,6 +10,7 @@
fileExtension: 'impexp',
// undoRedo: true,
defaultTeamFolder: true,
});
</script>
@@ -53,6 +54,7 @@
import uuidv1 from 'uuid/v1';
import { tick } from 'svelte';
import { showSnackbarError } from '../utility/snackbar';
import { _t } from '../translations';
let busy = false;
let executeNumber = 0;
@@ -288,21 +290,21 @@
/>
{#if busy}
<LoadingInfo wrapper message="Processing import/export ..." />
<LoadingInfo wrapper message={_t('importExport.processingImportExport', { defaultMessage: "Processing import/export ..." })} />
{/if}
</div>
<svelte:fragment slot="2">
<WidgetColumnBar>
<WidgetColumnBarItem
title="Output files"
title={_t('importExport.outputFiles', { defaultMessage: "Output files" })}
name="output"
height="20%"
data-testid="ImportExportTab_outputFiles"
>
<RunnerOutputFiles {runnerId} {executeNumber} />
</WidgetColumnBarItem>
<WidgetColumnBarItem title="Messages" name="messages">
<WidgetColumnBarItem title={_t('importExport.messages', { defaultMessage: "Messages" })} name="messages">
<SocketMessageView
eventName={runnerId ? `runner-info-${runnerId}` : null}
{executeNumber}
@@ -311,16 +313,16 @@
/>
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="Preview"
title={_t('importExport.preview', { defaultMessage: "Preview" })}
name="preview"
skip={!$previewReaderStore}
data-testid="ImportExportTab_preview"
>
<PreviewDataGrid reader={$previewReaderStore} />
</WidgetColumnBarItem>
<WidgetColumnBarItem title="Advanced configuration" name="config" collapsed>
<FormTextField label="Schedule" name="schedule" />
<FormTextField label="Start variable index" name="startVariableIndex" />
<WidgetColumnBarItem title={_t('importExport.advancedConfiguration', { defaultMessage: "Advanced configuration" })} name="config" collapsed>
<FormTextField label={_t('importExport.schedule', { defaultMessage: "Schedule" })} name="schedule" />
<FormTextField label={_t('importExport.startVariableIndex', { defaultMessage: "Start variable index" })} name="startVariableIndex" />
</WidgetColumnBarItem>
</WidgetColumnBar>
</svelte:fragment>
@@ -329,15 +331,15 @@
<svelte:fragment slot="toolstrip">
{#if busy}
<ToolStripButton icon="icon stop" on:click={handleCancel} data-testid="ImportExportTab_stopButton"
>Stop</ToolStripButton
>{_t('importExport.stop', { defaultMessage: "Stop" })}</ToolStripButton
>
{:else}
<ToolStripButton on:click={handleExecute} icon="icon run" data-testid="ImportExportTab_executeButton"
>Run</ToolStripButton
>{_t('importExport.run', { defaultMessage: "Run" })}</ToolStripButton
>
{/if}
<ToolStripButton icon="img shell" on:click={handleGenerateScript} data-testid="ImportExportTab_generateScriptButton"
>Generate script</ToolStripButton
>{_t('importExport.generateScript', { defaultMessage: "Generate script" })}</ToolStripButton
>
<ToolStripSaveButton idPrefix="impexp" />
</svelte:fragment>
+7 -1
View File
@@ -52,6 +52,7 @@
findReplace: true,
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection() && hasPermission('dbops/query'),
copyPaste: true,
defaultTeamFolder: true,
});
registerCommand({
id: 'query.executeCurrent',
@@ -123,8 +124,9 @@
</script>
<script lang="ts">
import { getContext, onDestroy, onMount, tick } from 'svelte';
import { getContext, onDestroy, onMount, setContext, tick } from 'svelte';
import sqlFormatter from 'sql-formatter';
import { writable } from 'svelte/store';
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
import SqlEditor from '../query/SqlEditor.svelte';
@@ -166,6 +168,7 @@
import FontIcon from '../icons/FontIcon.svelte';
import hasPermission from '../utility/hasPermission';
import QueryAiAssistant from '../ai/QueryAiAssistant.svelte';
import { getCurrentSettings } from '../stores';
export let tabid;
export let conid;
@@ -175,6 +178,9 @@
export const activator = createActivator('QueryTab', false);
const collapsedLeftColumnStore = writable(getCurrentSettings()['sqlEditor.hideColumnsPanel'] ?? false);
setContext('collapsedLeftColumnStore', collapsedLeftColumnStore);
const QUERY_PARAMETER_STYLES = [
{
value: '',
+113
View File
@@ -0,0 +1,113 @@
<script lang="ts" context="module">
export const matchingProps = [];
</script>
<script lang="ts">
import SettingsMenuControl from "../elements/SettingsMenuControl.svelte";
import GeneralSettings from "../settings/GeneralSettings.svelte";
import SettingsFormProvider from "../forms/SettingsFormProvider.svelte";
import ConnectionSettings from "../settings/ConnectionSettings.svelte";
import ThemeSettings from "../settings/ThemeSettings.svelte";
import DefaultActionsSettings from "../settings/DefaultActionsSettings.svelte";
import BehaviourSettings from "../settings/BehaviourSettings.svelte";
import ExternalToolsSettings from "../settings/ExternalToolsSettings.svelte";
import LicenseSettings from "../settings/LicenseSettings.svelte";
import { isProApp } from "../utility/proTools";
import { _t } from "../translations";
import CommandListTab from "./CommandListTab.svelte";
import DataGridSettings from "../settings/DataGridSettings.svelte";
import SQLEditorSettings from "../settings/SQLEditorSettings.svelte";
import AiSettingsTab from "../settings/AiSettingsTab.svelte";
export let selectedItem = 'general';
const menuItems = [
{
label: _t('settings.general', { defaultMessage: 'General' }),
identifier: 'general',
component: GeneralSettings,
props: {},
testid: 'settings-general',
},
{
label: _t('settings.connection', { defaultMessage: 'Connection' }),
identifier: 'connection',
component: ConnectionSettings,
props: {},
testid: 'settings-connection',
},
{
label: _t('settings.dataGrid.title', { defaultMessage: 'Data grid' }),
identifier: 'data-grid',
component: DataGridSettings,
props: {},
testid: 'settings-data-grid',
},
{
label: _t('settings.sqlEditor.title', { defaultMessage: 'SQL Editor' }),
identifier: 'sql-editor',
component: SQLEditorSettings,
props: {},
testid: 'settings-sql-editor',
},
{
label: _t('settings.theme', { defaultMessage: 'Themes' }),
identifier: 'theme',
component: ThemeSettings,
props: {},
testid: 'settings-themes',
},
{
label: _t('settings.defaultActions', { defaultMessage: 'Default Actions' }),
identifier: 'default-actions',
component: DefaultActionsSettings,
props: {},
testid: 'settings-default-actions',
},
{
label: _t('settings.behaviour', { defaultMessage: 'Behaviour' }),
identifier: 'behaviour',
component: BehaviourSettings,
props: {},
testid: 'settings-behaviour',
},
{
label: _t('settings.externalTools', { defaultMessage: 'External Tools' }),
identifier: 'external-tools',
component: ExternalToolsSettings,
props: {},
testid: 'settings-external-tools',
},
{
label: _t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }),
identifier: 'shortcuts',
component: CommandListTab,
props: {},
testid: 'settings-shortcuts',
},
isProApp() && {
label: _t('settings.license', { defaultMessage: 'License' }),
identifier: 'license',
component: LicenseSettings,
props: {},
testid: 'settings-license',
},
isProApp() && {
label: _t('settings.AI', { defaultMessage: 'AI'}),
identifier: 'ai',
component: AiSettingsTab,
props: {},
testid: 'settings-ai',
},
];
</script>
<SettingsFormProvider>
<SettingsMenuControl
items={menuItems}
bind:value={selectedItem}
flex1={true}
flexColContainer={true}
scrollableContentContainer={true}
/>
</SettingsFormProvider>
+1
View File
@@ -12,6 +12,7 @@
execute: true,
toggleComment: true,
findReplace: true,
defaultTeamFolder: true,
executeAdditionalCondition: () => getCurrentConfig().allowShellScripting,
});
+2
View File
@@ -25,6 +25,7 @@ import * as ServerSummaryTab from './ServerSummaryTab.svelte';
import * as ImportExportTab from './ImportExportTab.svelte';
import * as SqlObjectTab from './SqlObjectTab.svelte';
import * as AppLogTab from './AppLogTab.svelte';
import * as SettingsTab from './SettingsTab.svelte';
import protabs from './index-pro';
@@ -56,5 +57,6 @@ export default {
ImportExportTab,
SqlObjectTab,
AppLogTab,
SettingsTab,
...protabs,
};
+11 -6
View File
@@ -6,6 +6,7 @@ import es from '../../../translations/es.json';
import zh from '../../../translations/zh.json';
import pt from '../../../translations/pt.json';
import it from '../../../translations/it.json';
import ja from '../../../translations/ja.json';
import MessageFormat, { MessageFunction } from '@messageformat/core';
import { getStringSettingsValue } from './settings/settingsTools';
@@ -22,6 +23,7 @@ const translations = {
es,
pt,
it,
ja,
};
const supportedLanguages = Object.keys(translations);
@@ -31,13 +33,16 @@ const defaultLanguage = 'en';
let selectedLanguageCache: string | null = null;
export function getSelectedLanguage(): string {
export function getSelectedLanguage(preferrendLanguage?: string): string {
if (selectedLanguageCache) return selectedLanguageCache;
// const browserLanguage = getBrowserLanguage();
if (preferrendLanguage == 'auto') {
preferrendLanguage = getBrowserLanguage();
}
const selectedLanguage = getElectron()
? getStringSettingsValue('localization.language', null)
: localStorage.getItem('selectedLanguage');
? getStringSettingsValue('localization.language', preferrendLanguage)
: localStorage.getItem('selectedLanguage') ?? preferrendLanguage;
if (!selectedLanguage || !supportedLanguages.includes(selectedLanguage)) return defaultLanguage;
return selectedLanguage;
@@ -51,8 +56,8 @@ export async function setSelectedLanguage(language: string) {
}
}
export function saveSelectedLanguageToCache() {
selectedLanguageCache = getSelectedLanguage();
export function saveSelectedLanguageToCache(preferrendLanguage?: string) {
selectedLanguageCache = getSelectedLanguage(preferrendLanguage);
}
export function getBrowserLanguage(): string {
+41 -1
View File
@@ -4,6 +4,8 @@ import _ from 'lodash';
import { getSchemaList } from './metadataLoaders';
import { showSnackbarError } from './snackbar';
import { _t } from '../translations';
import { apiCall } from './api';
import getElectron from './getElectron';
export class LoadingToken {
isCanceled = false;
@@ -63,7 +65,8 @@ export function getObjectTypeFieldLabel(objectTypeField, driver?) {
if (objectTypeField == 'procedures') return _t('dbObject.procedures', { defaultMessage: 'Procedures' });
if (objectTypeField == 'functions') return _t('dbObject.functions', { defaultMessage: 'Functions' });
if (objectTypeField == 'triggers') return _t('dbObject.triggers', { defaultMessage: 'Triggers' });
if (objectTypeField == 'schedulerEvents') return _t('dbObject.schedulerEvents', { defaultMessage: 'Scheduler Events' });
if (objectTypeField == 'schedulerEvents')
return _t('dbObject.schedulerEvents', { defaultMessage: 'Scheduler Events' });
if (objectTypeField == 'matviews') return _t('dbObject.matviews', { defaultMessage: 'Materialized Views' });
if (objectTypeField == 'collections') return _t('dbObject.collections', { defaultMessage: 'Collections/Containers' });
return _.startCase(objectTypeField);
@@ -151,3 +154,40 @@ export function getKeyTextFromEvent(e) {
keyText += e.key;
return keyText;
}
export function getDatabasStatusMenu(dbid) {
function callSchemalListChanged() {
apiCall('database-connections/dispatch-database-changed-event', { event: 'schema-list-changed', ...dbid });
}
return [
{
text: _t('command.database.refreshIncremental', { defaultMessage: 'Refresh DB structure (incremental)' }),
onClick: () => {
apiCall('database-connections/sync-model', dbid);
callSchemalListChanged();
},
},
{
text: _t('command.database.refreshFull', { defaultMessage: 'Refresh DB structure (full)' }),
onClick: () => {
apiCall('database-connections/sync-model', { ...dbid, isFullRefresh: true });
callSchemalListChanged();
},
},
{
text: _t('command.database.reopenConnection', { defaultMessage: 'Reopen connection' }),
onClick: () => {
apiCall('database-connections/refresh', dbid);
callSchemalListChanged();
},
},
{
text: _t('command.database.disconnect', { defaultMessage: 'Disconnect' }),
onClick: () => {
const electron = getElectron();
if (electron) apiCall('database-connections/disconnect', dbid);
switchCurrentDatabase(null);
},
},
];
}
+2 -1
View File
@@ -11,7 +11,7 @@ import getElectron from './getElectron';
// return derived(editorStore, editor => editor != null);
// }
export default async function saveTabFile(editor, saveMode, folder, format, fileExtension) {
export default async function saveTabFile(editor, saveMode, folder, format, fileExtension, defaultTeamFolder) {
const tabs = get(openedTabs);
const tabid = editor.activator.tabid;
const data = editor.getData();
@@ -94,6 +94,7 @@ export default async function saveTabFile(editor, saveMode, folder, format, file
filePath: savedFilePath,
onSave,
folid: savedCloudFolderId,
defaultTeamFolder,
// cntid: savedCloudContentId,
});
}
@@ -0,0 +1,132 @@
import _ from 'lodash';
import { Condition, dumpSqlInsert, dumpSqlUpdate, Insert, Update, Delete, dumpSqlDelete } from 'dbgate-sqltree';
import { TableInfo, SqlDumper } from 'dbgate-types';
export function createTableRestoreScript(backupTable: TableInfo, originalTable: TableInfo, dmp: SqlDumper) {
const bothColumns = _.intersection(
backupTable.columns.map(x => x.columnName),
originalTable.columns.map(x => x.columnName)
);
const keyColumns = _.intersection(
originalTable.primaryKey?.columns?.map(x => x.columnName) || [],
backupTable.columns.map(x => x.columnName)
);
const valueColumns = _.difference(bothColumns, keyColumns);
function makeColumnCond(colName: string, operator: '=' | '<>' | '<' | '>' | '<=' | '>=' = '='): Condition {
return {
conditionType: 'binary',
operator,
left: {
exprType: 'column',
columnName: colName,
source: { name: originalTable },
},
right: {
exprType: 'column',
columnName: colName,
source: { alias: 'bak' },
},
};
}
function putTitle(title: string) {
dmp.putRaw('\n\n');
dmp.comment(`******************** ${title} ********************`);
dmp.putRaw('\n');
}
dmp.comment(`Restoring data into table ${originalTable.pureName} from backup table ${backupTable.pureName}`);
dmp.putRaw('\n');
dmp.comment(`Key columns: ${keyColumns.join(', ')}`);
dmp.putRaw('\n');
dmp.comment(`Value columns: ${valueColumns.join(', ')}`);
dmp.putRaw('\n');
dmp.comment(`Follows UPDATE, DELETE, INSERT statements to restore data`);
dmp.putRaw('\n');
const update: Update = {
commandType: 'update',
from: { name: originalTable },
fields: valueColumns.map(colName => ({
exprType: 'select',
select: {
commandType: 'select',
from: { name: backupTable, alias: 'bak' },
columns: [
{
exprType: 'column',
columnName: colName,
source: { alias: 'bak' },
},
],
where: {
conditionType: 'and',
conditions: keyColumns.map(colName => makeColumnCond(colName)),
},
},
targetColumn: colName,
})),
where: {
conditionType: 'exists',
subQuery: {
commandType: 'select',
from: { name: backupTable, alias: 'bak' },
selectAll: true,
where: {
conditionType: 'and',
conditions: [
...keyColumns.map(keyColName => makeColumnCond(keyColName)),
{
conditionType: 'or',
conditions: valueColumns.map(colName => makeColumnCond(colName, '<>')),
},
],
},
},
},
};
putTitle('UPDATE');
dumpSqlUpdate(dmp, update);
dmp.endCommand();
const delcmd: Delete = {
commandType: 'delete',
from: { name: originalTable },
where: {
conditionType: 'notExists',
subQuery: {
commandType: 'select',
from: { name: backupTable, alias: 'bak' },
selectAll: true,
where: {
conditionType: 'and',
conditions: keyColumns.map(colName => makeColumnCond(colName)),
},
},
},
};
putTitle('DELETE');
dumpSqlDelete(dmp, delcmd);
dmp.endCommand();
const insert: Insert = {
commandType: 'insert',
targetTable: originalTable,
fields: bothColumns.map(colName => ({
targetColumn: colName,
exprType: 'column',
columnName: colName,
source: { alias: 'bak' },
})),
whereNotExistsSource: { name: backupTable, alias: 'bak' },
insertWhereNotExistsCondition: {
conditionType: 'and',
conditions: keyColumns.map(colName => makeColumnCond(colName)),
},
};
putTitle('INSERT');
dumpSqlInsert(dmp, insert);
dmp.endCommand();
}
@@ -101,6 +101,7 @@
import WidgetTitle from './WidgetTitle.svelte';
import JsonExpandedCellView from '../celldata/JsonExpandedCellView.svelte';
import XmlCellView from '../celldata/XmlCellView.svelte';
import { _t } from '../translations';
let selectedFormatType = 'autodetect';
@@ -116,7 +117,7 @@
</script>
<div class="wrapper">
<WidgetTitle>Cell data view</WidgetTitle>
<WidgetTitle>{_t('cellDataWidget.title', { defaultMessage: "Cell data view" })}</WidgetTitle>
<div class="main">
<div class="toolbar">
Format:<span>&nbsp;</span>
@@ -126,18 +127,18 @@
on:change={e => (selectedFormatType = e.detail)}
data-testid="CellDataWidget_selectFormat"
options={[
{ value: 'autodetect', label: `Autodetect - ${autodetectFormat.title}` },
{ value: 'autodetect', label: _t('cellDataWidget.autodetect', { defaultMessage: "Autodetect - {autoDetectTitle}", values : { autoDetectTitle: autodetectFormat.title } }) },
...formats.map(fmt => ({ label: fmt.title, value: fmt.type })),
]}
/>
</div>
<div class="data">
{#if usedFormat.single && selection?.length != 1}
<ErrorInfo message="Must be selected one cell" alignTop />
<ErrorInfo message={_t('cellDataWidget.mustSelectOneCell', { defaultMessage: "Must be selected one cell" })} alignTop />
{:else if usedFormat == null}
<ErrorInfo message="Format not selected" alignTop />
<ErrorInfo message={_t('cellDataWidget.formatNotSelected', { defaultMessage: "Format not selected" })} alignTop />
{:else if !selection || selection.length == 0}
<ErrorInfo message="No data selected" alignTop />
<ErrorInfo message={_t('cellDataWidget.noDataSelected', { defaultMessage: "No data selected" })} alignTop />
{:else}
<svelte:component this={usedFormat?.component} {selection} />
{/if}
+2 -2
View File
@@ -19,12 +19,12 @@
</script>
<WidgetColumnBar>
<WidgetColumnBarItem title="Saved files" name="files" height="70%" storageName="savedFilesWidget">
<WidgetColumnBarItem title={_t('files.savedFiles', { defaultMessage: "Saved files" })} name="files" height="70%" storageName="savedFilesWidget">
<SavedFilesList />
</WidgetColumnBarItem>
{#if hasPermission('files/favorites/read')}
<WidgetColumnBarItem title="Favorites" name="favorites" storageName="favoritesWidget">
<WidgetColumnBarItem title={_t('files.favorites', { defaultMessage: "Favorites" })} name="favorites" storageName="favoritesWidget">
<WidgetsInnerContainer>
<AppObjectList list={$favorites || []} module={favoriteFileAppObject} />
</WidgetsInnerContainer>
@@ -13,13 +13,14 @@
import WidgetColumnBar from './WidgetColumnBar.svelte';
import WidgetColumnBarItem from './WidgetColumnBarItem.svelte';
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
import { _t } from '../translations';
$: favorites = useFavorites();
</script>
<WidgetColumnBar>
<WidgetColumnBarItem title="Recently closed tabs" name="closedTabs" storageName='closedTabsWidget'>
<WidgetColumnBarItem title={_t('history.recentlyClosedTabs', { defaultMessage: "Recently closed tabs" })} name="closedTabs" storageName='closedTabsWidget'>
<WidgetsInnerContainer>
<AppObjectList
list={_.sortBy(
@@ -30,7 +31,7 @@
/>
</WidgetsInnerContainer>
</WidgetColumnBarItem>
<WidgetColumnBarItem title="Query history" name="queryHistory" storageName='queryHistoryWidget'>
<WidgetColumnBarItem title={_t('history.queryHistory', { defaultMessage: "Query history" })} name="queryHistory" storageName='queryHistoryWidget'>
<QueryHistoryList />
</WidgetColumnBarItem>
</WidgetColumnBar>
@@ -4,13 +4,15 @@
import WidgetColumnBar from './WidgetColumnBar.svelte';
import WidgetColumnBarItem from './WidgetColumnBarItem.svelte';
import { _t } from '../translations';
</script>
<WidgetColumnBar>
<WidgetColumnBarItem title="Installed extensions" name="installed" height="50%" storageName='installedPluginsWidget'>
<WidgetColumnBarItem title={_t('widgets.installedExtensions', { defaultMessage: 'Installed extensions' })} name="installed" height="50%" storageName='installedPluginsWidget'>
<InstalledPluginsList />
</WidgetColumnBarItem>
<WidgetColumnBarItem title="Available extensions" name="all" storageName='allPluginsWidget'>
<WidgetColumnBarItem title={_t('widgets.availableExtensions', { defaultMessage: 'Available extensions' })} name="all" storageName='allPluginsWidget'>
<AvailablePluginsList />
</WidgetColumnBarItem>
</WidgetColumnBar>
@@ -30,11 +30,11 @@
<WidgetColumnBarItem title="Public Knowledge Base" name="publicCloud" storageName="publicCloudItems">
<WidgetsInnerContainer>
<SearchBoxWrapper>
<SearchInput placeholder="Search public files" bind:value={filter} />
<SearchInput placeholder={_t('publicCloudWidget.searchPublicFiles', { defaultMessage: "Search public files" })} bind:value={filter} />
<CloseSearchButton bind:filter />
<InlineButton
on:click={handleRefreshPublic}
title="Refresh files"
title={_t('publicCloudWidget.refreshFiles', { defaultMessage: "Refresh files" })}
data-testid="CloudItemsWidget_buttonRefreshPublic"
>
<FontIcon icon="icon refresh" />
@@ -52,9 +52,9 @@
<ErrorInfo message="No files found for your configuration" />
<div class="error-info">
<div class="m-1">
Only files relevant for your connections, platform and DbGate edition are listed. Please define connections at first.
{_t('publicCloudWidget.onlyRelevantFilesListed', { defaultMessage: "Only files relevant for your connections, platform and DbGate edition are listed. Please define connections at first." })}
</div>
<FormStyledButton value={`Refresh list`} skipWidth on:click={handleRefreshPublic} />
<FormStyledButton value={_t('publicCloudWidget.refreshList', { defaultMessage: "Refresh list" })} skipWidth on:click={handleRefreshPublic} />
</div>
{/if}
</WidgetsInnerContainer>
@@ -9,6 +9,7 @@
import openNewTab from '../utility/openNewTab';
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
import { apiCall, apiOff, apiOn } from '../utility/api';
import { _t } from '../translations';
let filter = '';
let search = '';
@@ -38,7 +39,7 @@
</script>
<SearchBoxWrapper>
<SearchInput placeholder="Search query history" {filter} bind:value={filter} />
<SearchInput placeholder={_t('history.searchQueryHistory', { defaultMessage: "Search query history" })} {filter} bind:value={filter} />
<CloseSearchButton
bind:filter
on:click={() => {
@@ -54,7 +55,7 @@
on:click={() => {
openNewTab(
{
title: 'Query #',
title: _t('database.queryDesigner', { defaultMessage: "Query #" }),
icon: 'icon sql-file',
tabComponent: 'QueryTab',
focused: true,
@@ -13,6 +13,7 @@
import { isProApp } from '../utility/proTools';
import InlineUploadButton from '../buttons/InlineUploadButton.svelte';
import { DATA_FOLDER_NAMES } from 'dbgate-tools';
import { _t } from '../translations';
let filter = '';
@@ -65,19 +66,19 @@
</script>
<SearchBoxWrapper>
<SearchInput placeholder="Search saved files" bind:value={filter} />
<SearchInput placeholder={_t('files.searchSavedFiles', { defaultMessage: "Search saved files" })} bind:value={filter} />
<CloseSearchButton bind:filter />
<InlineUploadButton
filters={[
{
name: `All supported files`,
name: _t('files.allSupportedFiles', { defaultMessage: "All supported files" }),
extensions: ['sql'],
},
{ name: `SQL files`, extensions: ['sql'] },
{ name: _t('files.sqlFiles', { defaultMessage: "SQL files" }), extensions: ['sql'] },
]}
onProcessFile={handleUploadedFile}
/>
<InlineButton on:click={handleRefreshFiles} title="Refresh files" data-testid="SavedFileList_buttonRefresh">
<InlineButton on:click={handleRefreshFiles} title={_t('files.refreshFiles', { defaultMessage: "Refresh files" })} data-testid="SavedFileList_buttonRefresh">
<FontIcon icon="icon refresh" />
</InlineButton>
</SearchBoxWrapper>
@@ -86,7 +87,7 @@
<AppObjectList
list={files}
module={savedFileAppObject}
groupFunc={data => (data.teamFileId ? 'Team files' : dataFolderTitle(data.folder))}
groupFunc={data => (data.teamFileId ? _t('files.teamFiles', { defaultMessage: "Team files" }) : dataFolderTitle(data.folder))}
{filter}
/>
</WidgetsInnerContainer>
+38 -14
View File
@@ -31,7 +31,7 @@
import { chevronExpandIcon } from '../icons/expandIcons';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import { getObjectTypeFieldLabel } from '../utility/common';
import { getDatabasStatusMenu, getObjectTypeFieldLabel } from '../utility/common';
import DropDownButton from '../buttons/DropDownButton.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
@@ -120,11 +120,6 @@
// setInterval(() => (generateIndex += 1), 2000);
// $: objectList = generateObjectList(generateIndex);
const handleRefreshDatabase = () => {
apiCall('database-connections/refresh', { conid, database });
apiCall('database-connections/dispatch-database-changed-event', { event: 'schema-list-changed', conid, database });
};
function createAddMenu() {
const res = [];
if (driver?.databaseEngineTypes?.includes('document')) {
@@ -147,6 +142,15 @@
return res;
}
function createRefreshDatabaseMenu() {
return getDatabasStatusMenu({ conid, database });
}
function handleFullRefreshDatabase() {
apiCall('database-connections/sync-model', { conid, database, isFullRefresh: true });
apiCall('database-connections/dispatch-database-changed-event', { event: 'schema-list-changed', conid, database });
}
function createSearchMenu() {
const res = [];
res.push({ label: _t('sqlObject.searchBy', { defaultMessage: 'Search by:' }), isBold: true, disabled: true });
@@ -228,6 +232,15 @@
$focusedConnectionOrDatabase?.database != extractDbNameFromComposite(database)));
// $: console.log('STATUS', $status);
function getAppObjectGroup(data) {
if (data.objectTypeField == 'tables') {
if (data.pureName.match(databaseObjectAppObject.TABLE_BACKUP_REGEX)) {
return _t('dbObject.tableBackups', { defaultMessage: 'Table Backups' });
}
}
return getObjectTypeFieldLabel(data.objectTypeField, driver);
}
</script>
{#if $status && $status.name == 'error'}
@@ -237,7 +250,18 @@
<WidgetsInnerContainer hideContent={differentFocusedDb}>
<ErrorInfo message={$status.message} icon="img error" />
<InlineButton on:click={handleRefreshDatabase}>{_t('common.refresh', { defaultMessage: 'Refresh' })}</InlineButton>
<InlineButton on:click={handleFullRefreshDatabase}
>{_t('common.refresh', { defaultMessage: 'Refresh' })}</InlineButton
>
<DropDownButton
menu={createRefreshDatabaseMenu}
title={_t('sqlObjectList.refreshDatabase', { defaultMessage: 'Refresh database connection and object list' })}
square
narrow={false}
data-testid="SqlObjectList_refreshButton"
icon="icon dots-vertical"
/>
</WidgetsInnerContainer>
{:else if objectList.length == 0 && $status && $status.name != 'pending' && $status.name != 'checkStructure' && $status.name != 'loadStructure' && $objects}
<SchemaSelector
@@ -262,7 +286,7 @@
icon="img alert"
/>
<div class="m-1" />
<InlineButton on:click={handleRefreshDatabase}>{_t('common.refresh', { defaultMessage: 'Refresh' })}</InlineButton>
<InlineButton on:click={handleFullRefreshDatabase}>{_t('common.refresh', { defaultMessage: 'Refresh' })}</InlineButton>
{#if driver?.databaseEngineTypes?.includes('sql')}
<div class="m-1" />
<InlineButton on:click={() => runCommand('new.table')}
@@ -298,14 +322,14 @@
{#if !filter}
<DropDownButton icon="icon plus-thick" menu={createAddMenu} />
{/if}
<InlineButton
on:click={handleRefreshDatabase}
<DropDownButton
menu={createRefreshDatabaseMenu}
title={_t('sqlObjectList.refreshDatabase', { defaultMessage: 'Refresh database connection and object list' })}
square
narrow={false}
data-testid="SqlObjectList_refreshButton"
>
<FontIcon icon="icon refresh" />
</InlineButton>
icon="icon dots-vertical"
/>
</SearchBoxWrapper>
<SchemaSelector
schemaList={_.isArray($schemaList) ? $schemaList : null}
@@ -356,7 +380,7 @@
.filter(x => x.schemaName == null || ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true))
.map(x => ({ ...x, conid, database }))}
module={databaseObjectAppObject}
groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)}
groupFunc={getAppObjectGroup}
subItemsComponent={(data, { isExpandedBySearch }) =>
data.objectTypeField == 'procedures' || data.objectTypeField == 'functions'
? isExpandedBySearch
+16 -36
View File
@@ -35,16 +35,16 @@
getCurrentConfig().storageDatabase && {
icon: 'icon admin',
name: 'admin',
title: 'Administration',
title: _t('widgets.administration', { defaultMessage: 'Administration' }),
},
{
icon: 'icon database',
name: 'database',
title: 'Database connections',
title: _t('widgets.databaseConnections', { defaultMessage: 'Database connections' }),
},
getCurrentConfig().allowPrivateCloud && {
name: 'cloud-private',
title: 'DbGate Cloud',
title: _t('widgets.dbgateCloud', { defaultMessage: 'DbGate Cloud' }),
icon: 'icon cloud-private',
},
@@ -55,17 +55,17 @@
{
icon: 'icon file',
name: 'file',
title: 'Favorites & Saved files',
title: _t('widgets.favoritesAndSavedFiles', { defaultMessage: 'Favorites & Saved files' }),
},
{
icon: 'icon history',
name: 'history',
title: 'Query history & Closed tabs',
title: _t('widgets.queryHistoryAndClosedTabs', { defaultMessage: 'Query history & Closed tabs' }),
},
isProApp() && {
icon: 'icon archive',
name: 'archive',
title: 'Archive (saved tabular data)',
title: _t('widgets.archive', { defaultMessage: 'Archive (saved tabular data)' }),
},
// {
// icon: 'icon plugin',
@@ -75,17 +75,17 @@
{
icon: 'icon cell-data',
name: 'cell-data',
title: 'Selected cell data detail view',
title: _t('widgets.selectedCellDataDetailView', { defaultMessage: 'Selected cell data detail view' }),
},
{
name: 'cloud-public',
title: 'DbGate Cloud',
title: _t('widgets.dbgateCloud', { defaultMessage: 'DbGate Cloud' }),
icon: 'icon cloud-public',
},
{
icon: 'icon premium',
name: 'premium',
title: 'Premium promo',
title: _t('widgets.premiumPromo', { defaultMessage: 'Premium promo' }),
isPremiumPromo: true,
},
// {
@@ -113,32 +113,12 @@
//const handleChangeWidget= e => (selectedWidget.set(item.name))
function handleSettingsMenu() {
const rect = domSettings.getBoundingClientRect();
const left = rect.right;
const top = rect.bottom;
const items = [
hasPermission('settings/change') && { command: 'settings.show' },
{ command: 'theme.changeTheme' },
hasPermission('settings/change') && { command: 'settings.commands' },
hasPermission('widgets/plugins') && {
text: _t('widgets.managePlugins', { defaultMessage: 'Manage plugins' }),
onClick: () => {
$selectedWidget = 'plugins';
$visibleWidgetSideBar = true;
},
},
hasPermission('application-log') && {
text: _t('widgets.viewApplicationLogs', { defaultMessage: 'View application logs' }),
onClick: () => {
openNewTab({
title: 'Application log',
icon: 'img applog',
tabComponent: 'AppLogTab',
});
},
},
];
currentDropDownMenu.set({ left, top, items });
openNewTab({
title: 'Settings',
icon: 'icon settings',
tabComponent: 'SettingsTab',
props: {},
});
}
function handleCloudAccountMenu() {
@@ -213,7 +193,7 @@
class="wrapper"
on:click={() => showModal(NewObjectModal)}
data-testid="WidgetIconPanel_addButton"
title="Add New"
title={_t('widgets.addNew', { defaultMessage: 'Add New' })}
>
<FontIcon icon="icon add" />
</div>
@@ -84,9 +84,7 @@ class Analyser extends DatabaseAnalyser {
async _runAnalysis() {
this.feedback({ analysingMessage: 'DBGM-00241 Loading tables' });
const tables = await this.analyserQuery(this.driver.dialect.stringAgg ? 'tableModifications' : 'tableList', [
'tables',
]);
const tables = await this.analyserQuery('tableList', ['tables']);
this.feedback({ analysingMessage: 'DBGM-00242 Loading columns' });
const columns = await this.analyserQuery('columns', ['tables', 'views']);
@@ -396,9 +394,6 @@ class Analyser extends DatabaseAnalyser {
}
async _getFastSnapshot() {
const tableModificationsQueryData = this.driver.dialect.stringAgg
? await this.analyserQuery('tableModifications')
: null;
const viewModificationsQueryData = await this.analyserQuery('viewModifications');
const matviewModificationsQueryData = this.driver.dialect.materializedViews
? await this.analyserQuery('matviewModifications')
@@ -406,15 +401,7 @@ class Analyser extends DatabaseAnalyser {
const routineModificationsQueryData = await this.analyserQuery('routineModifications');
return {
tables: tableModificationsQueryData
? tableModificationsQueryData.rows.map(x => ({
objectId: `tables:${x.schema_name}.${x.pure_name}`,
pureName: x.pure_name,
schemaName: x.schema_name,
sizeBytes: x.size_bytes,
contentHash: `${x.hash_code_columns}-${x.hash_code_constraints}`,
}))
: null,
tables: null,
views: viewModificationsQueryData.rows.map(x => ({
objectId: `views:${x.schema_name}.${x.pure_name}`,
pureName: x.pure_name,
@@ -1,5 +1,4 @@
const columns = require('./columns');
const tableModifications = require('./tableModifications');
const tableList = require('./tableList');
const viewModifications = require('./viewModifications');
const matviewModifications = require('./matviewModifications');
@@ -25,7 +24,6 @@ const fk_keyColumnUsage = require('./fk_key_column_usage');
module.exports = {
columns,
tableModifications,
tableList,
viewModifications,
primaryKeys,
@@ -1,17 +1,24 @@
module.exports = `
select
table_constraints.constraint_schema as "constraint_schema",
table_constraints.constraint_name as "constraint_name",
table_constraints.table_schema as "schema_name",
table_constraints.table_name as "pure_name",
key_column_usage.column_name as "column_name"
from information_schema.table_constraints
inner join information_schema.key_column_usage on table_constraints.table_name = key_column_usage.table_name and table_constraints.constraint_name = key_column_usage.constraint_name
and table_constraints.table_schema = key_column_usage.table_schema
where
table_constraints.table_schema !~ '^_timescaledb_'
and table_constraints.constraint_type = 'PRIMARY KEY'
and ('tables:' || table_constraints.table_schema || '.' || table_constraints.table_name) =OBJECT_ID_CONDITION
and table_constraints.table_schema =SCHEMA_NAME_CONDITION
order by key_column_usage.ordinal_position
SELECT
n.nspname AS "constraint_schema",
c.conname AS "constraint_name",
n.nspname AS "schema_name",
t.relname AS "pure_name",
a.attname AS "column_name"
FROM pg_catalog.pg_constraint AS c
JOIN pg_catalog.pg_class AS t
ON t.oid = c.conrelid
JOIN pg_catalog.pg_namespace AS n
ON n.oid = t.relnamespace
JOIN LATERAL unnest(c.conkey) WITH ORDINALITY AS cols(attnum, ordinal_position)
ON TRUE
JOIN pg_catalog.pg_attribute AS a
ON a.attrelid = t.oid
AND a.attnum = cols.attnum
WHERE
c.contype = 'p' -- PRIMARY KEY
AND n.nspname !~ '^_timescaledb_'
AND ('tables:' || n.nspname || '.' || t.relname) =OBJECT_ID_CONDITION
AND n.nspname =SCHEMA_NAME_CONDITION
ORDER BY cols.ordinal_position
`;
@@ -5,6 +5,6 @@ from information_schema.tables infoTables
where infoTables.table_type not like '%VIEW%'
and ('tables:' || infoTables.table_schema || '.' || infoTables.table_name) =OBJECT_ID_CONDITION
and infoTables.table_schema <> 'pg_internal'
and infoTables.table_schema !~ '^_timescaledb_'
and infoTables.table_schema !~ '^_timescaledb_'
and infoTables.table_schema =SCHEMA_NAME_CONDITION
`;
@@ -1,28 +0,0 @@
module.exports = `
select infoTables.table_schema as "schema_name", infoTables.table_name as "pure_name",
(
select $md5Function(string_agg(
infoColumns.column_name || '|' || infoColumns.data_type || '|' || infoColumns.is_nullable::varchar(255) || '|' || coalesce(infoColumns.character_maximum_length, -1)::varchar(255)
|| '|' || coalesce(infoColumns.numeric_precision, -1)::varchar(255) ,
',' order by infoColumns.ordinal_position
)) as "hash_code_columns"
from information_schema.columns infoColumns
where infoColumns.table_schema = infoTables.table_schema and infoColumns.table_name = infoTables.table_name
),
(
select $md5Function(string_agg(
infoConstraints.constraint_name || '|' || infoConstraints.constraint_type ,
',' order by infoConstraints.constraint_name
)) as "hash_code_constraints"
from information_schema.table_constraints infoConstraints
where infoConstraints.table_schema = infoTables.table_schema and infoConstraints.table_name = infoTables.table_name
),
pg_relation_size('"'||infoTables.table_schema||'"."'||infoTables.table_name||'"') as "size_bytes"
from information_schema.tables infoTables
where infoTables.table_type not like '%VIEW%'
and ('tables:' || infoTables.table_schema || '.' || infoTables.table_name) =OBJECT_ID_CONDITION
and infoTables.table_schema <> 'pg_internal'
and infoTables.table_schema !~ '^_timescaledb_'
and infoTables.table_schema =SCHEMA_NAME_CONDITION
`;
+102 -1
View File
@@ -3,6 +3,11 @@
"app.loading_plugin": "Načítám plugin {plugin} ...",
"app.preparingPlugins": "Příprava pluginů...",
"app.starting": "Spouštění DbGate",
"cellDataWidget.autodetect": "Autodetekce - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Formát není vybrán",
"cellDataWidget.mustSelectOneCell": "Musí být vybrána jedna buňka",
"cellDataWidget.noDataSelected": "Nejsou vybrána žádná data",
"cellDataWidget.title": "Zobrazení dat buňky",
"chart.detect": "Rozpoznat graf",
"chart.open": "Otevřít graf",
"clipboard.SQLInsert": "SQL INSERT příkazy",
@@ -40,6 +45,10 @@
"columnEditor.isSparse": "Řídký",
"columnEditor.isUnsigned": "Bez znaménka",
"columnEditor.isZerofill": "Doplňování nul",
"columnLine.addReference": "Přidat referenci",
"columnLine.sortAscending": "Seřadit vzestupně",
"columnLine.sortDescending": "Seřadit sestupně",
"columnLine.unsort": "Zrušit řazení",
"columnsConstraintEditor.addNewColumn": "Přidat nový sloupec",
"columnsConstraintEditor.chooseColumn": "Vybrat sloupec",
"columnsConstraintEditor.selectColumn": "Vybrat sloupec",
@@ -289,6 +298,7 @@
"commandModal.showKeyCombination": "Zadejte požadovanou kombinaci kláves a stiskněte ENTER",
"common.addNew": "Přidat nový",
"common.advanced": "Pokročilé",
"common.allFields": "Všechny {field}",
"common.archive": "Archiv (JSONL)",
"common.cancel": "Zrušit",
"common.close": "Zavřít",
@@ -315,6 +325,7 @@
"common.kill": "Ukončit",
"common.loadingData": "Načítání dat",
"common.name": "Název",
"common.newConnection": "Nové připojení",
"common.notSelectedOptional": "(nezvoleno - volitelné)",
"common.parameters": "Parametry",
"common.passwordEncrypted": "Heslo je zašifrované",
@@ -324,6 +335,7 @@
"common.queryEditor": "Editor SQL dotazů",
"common.refresh": "Obnovit",
"common.remove": "Odstranit",
"common.removeAll": "Odstranit vše",
"common.reset": "Resetovat",
"common.save": "Uložit",
"common.saveAndNext": "Uložit a další",
@@ -331,6 +343,7 @@
"common.schema": "Schéma",
"common.search": "Hledat",
"common.searchBy": "Hledat podle:",
"common.server": "Server",
"common.sqlGenerator": "SQL Generátor",
"common.table": "Tabulka",
"common.testingConnection": "Testování připojení",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Triggery",
"dbObject.truncateTable": "Vyprázdnit tabulku",
"dbObject.views": "Pohledy",
"designerTable.addReferences": "Přidat reference",
"designerTable.changeColor": "Změnit barvu",
"designerTable.defineVirtualForeignKey": "Definovat virtuální cizí klíč",
"designerTable.newAlias": "Nový alias",
"designerTable.removeTableAlias": "Odstranit alias tabulky",
"designerTable.setTableAlias": "Nastavit alias tabulky",
"error.driverNotFound": "Neplatné připojení k databázi, ovladač nebyl nalezen",
"error.selectedCloudConnection": "Vybrané připojení je z DbGate cloudu",
"error.selectedNotCloudConnection": "Vybrané připojení není z DbGate cloudu",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Soubory návrháře dotazů",
"file.sqlFiles": "Soubory SQL",
"file.sqliteDatabase": "Databáze SQLite",
"files.allSupportedFiles": "Všechny podporované soubory",
"files.favorites": "Oblíbené",
"files.openFile": "Otevřít soubor",
"files.refreshFiles": "Obnovit soubory",
"files.savedFiles": "Uložené soubory",
"files.searchSavedFiles": "Hledat v uložených souborech",
"files.sqlFiles": "Soubory SQL",
"files.teamFiles": "Týmové soubory",
"files.uploadFile": "Nahrát soubor",
"filter.after": "Po...",
"filter.and": "A",
"filter.arrayIsEmpty": "Pole je prázdné",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Referenční sloupec - ",
"foreignKeyEditor.referencedTable": "Odkazovaná tabulka",
"foreignKeyEditor.tableNotSet": "(tabulka není nastavena)",
"history.queryHistory": "Historie dotazů",
"history.recentlyClosedTabs": "Nedávno zavřené karty",
"history.searchQueryHistory": "Hledat v historii dotazů",
"importExport.action": "Akce",
"importExport.addWebUrl": "Přidat webovou URL",
"importExport.advancedConfiguration": "Pokročilá konfigurace",
"importExport.archiveFolder": "Složka archivu",
"importExport.columns": "Sloupce",
"importExport.createZipFileInArchive": "Vytvořit ZIP soubor v archivu",
"importExport.currentArchive": "Aktuální archiv",
"importExport.currentDatabase": "Aktuální DB",
"importExport.dragDropImportedFilesHere": "Přetáhněte sem importované soubory",
"importExport.exportToZipArchive": "Exportovat do ZIP archivu",
"importExport.exportToZipFile": "Exportovat do ZIP souboru",
"importExport.generateScript": "Vygenerovat skript",
"importExport.importFromZipArchive": "Importovat z ZIP archivu",
"importExport.importFromZipFile": "Importovat z ZIP souboru (v archivní složce)",
"importExport.mapSourceTablesFiles": "Mapovat zdrojové tabulky/soubory",
"importExport.messages": "Zprávy",
"importExport.newArchive": "Nový archiv",
"importExport.outputFiles": "Výstupní soubory",
"importExport.preview": "Náhled",
"importExport.processingImportExport": "Zpracovávání importu/exportu ...",
"importExport.run": "Spustit",
"importExport.schedule": "Plán",
"importExport.source": "Zdroj",
"importExport.sourceConfiguration": "Konfigurace zdroje",
"importExport.sourceFiles": "Zdrojové soubory",
"importExport.startVariableIndex": "Počáteční index proměnné",
"importExport.status": "Stav",
"importExport.stop": "Zastavit",
"importExport.storageType": "Typ úložiště",
"importExport.tablesViewsCollections": "Tabulky / pohledy / kolekce",
"importExport.target": "Cíl",
"importExport.targetConfiguration": "Konfigurace cíle",
"indexEditor.filteredIndexCondition": "Podmínka filtrovaného indexu",
"indexEditor.indexName": "Název indexu",
"indexEditor.isUnique": "Je jedinečný index",
"logs.autoScroll": "Automatické posouvání",
"logs.caller": "Volající:",
"logs.callerTab": "Volající",
"logs.chooseDate": "Vyberte datum",
"logs.codeTab": "Kód",
"logs.connectionId": "ID připojení:",
"logs.connectionTab": "Připojení",
"logs.database": "Databáze:",
"logs.databaseTab": "Databáze",
"logs.date": "Datum:",
"logs.dateTab": "Datum",
"logs.details": "Detaily",
"logs.engine": "Engine:",
"logs.engineTab": "Engine",
"logs.loadingNextRows": "Načítání dalších řádků...",
"logs.message": "Zpráva:",
"logs.messageCode": "Kód zprávy:",
"logs.messageTab": "Zpráva",
"logs.name": "Název:",
"logs.nameTab": "Název",
"logs.noDataForSelectedDate": "Pro vybrané datum nejsou k dispozici žádná data",
"logs.recentLogs": "Nedávné logy",
"logs.refresh": "Obnovit",
"logs.time": "Čas:",
"logs.timeTab": "Čas",
"menu.edit": "Upravit",
"menu.file": "Soubor",
"menu.help": "Nápověda",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "SQL generátor není pro aktuální databázi k dispozici",
"newObject.tableDescription": "Vytvořit tabulku v aktuální databázi",
"newObject.tableDisabled": "Vytvoření tabulky není pro aktuální databázi k dispozici",
"plugins.searchExtensionsOnWeb": "Hledat rozšíření na webu",
"publicCloudWidget.onlyRelevantFilesListed": "Jsou zobrazeny pouze soubory relevantní pro vaše připojení, platformu a edici DbGate. Nejprve prosím definujte připojení.",
"publicCloudWidget.refreshFiles": "Obnovit soubory",
"publicCloudWidget.refreshList": "Obnovit seznam",
"publicCloudWidget.searchPublicFiles": "Hledat veřejné soubory",
"query.limitRows": "Omezit na {queryRowsLimit} řádků",
"query.named": ":proměnná",
"query.noParameters": "(žádné parametry)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Název sloupce",
"sqlObject.databaseEmpty": "Databáze {database} je prázdná nebo struktura není načtena, stiskněte tlačítko Obnovit pro znovunačtení struktury",
"sqlObject.loadingStructure": "Načítání struktury databáze",
"sqlObject.name": "Název",
"sqlObject.newCollection": "Nová kolekce/kontejner",
"sqlObject.rowCount": "Počet řádků",
"sqlObject.schemaName": "Schéma",
"sqlObject.search.placeholder": "Hledat v tabulkách, pohledech, procedurách",
"sqlObject.searchBy": "Hledat podle:",
"sqlObject.sizeBytes": "Velikost (bajty)",
"sqlObject.sortBy": "Seřadit podle:",
"sqlObject.tableComment": "Komentář tabulky",
"sqlObject.tableEngine": "Engine tabulky",
"sqlObject.tableViewProcedureName": "Název tabulky/pohledu/procedury",
@@ -902,6 +992,17 @@
"widget.keys": "Klíče",
"widget.pinned": "Připnuté",
"widget.tablesViewsFunctions": "Tabulky, pohledy, funkce",
"widgets.addNew": "Přidat nový",
"widgets.administration": "Administrace",
"widgets.archive": "Archiv (uložená tabulková data)",
"widgets.availableExtensions": "Dostupná rozšíření",
"widgets.databaseConnections": "Databázová připojení",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Oblíbené a uložené soubory",
"widgets.installedExtensions": "Nainstalovaná rozšíření",
"widgets.managePlugins": "Spravovat pluginy",
"widgets.premiumPromo": "Premium promo",
"widgets.queryHistoryAndClosedTabs": "Historie dotazů a zavřené karty",
"widgets.selectedCellDataDetailView": "Detailní zobrazení dat vybrané buňky",
"widgets.viewApplicationLogs": "Zobrazit aplikační logy"
}
}
+101
View File
@@ -3,6 +3,11 @@
"app.loading_plugin": "Lade Plugin {plugin} ...",
"app.preparingPlugins": "Plugins werden vorbereitet...",
"app.starting": "Starte DbGate",
"cellDataWidget.autodetect": "Automatisch erkennen - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Format nicht ausgewählt",
"cellDataWidget.mustSelectOneCell": "Es muss eine Zelle ausgewählt sein",
"cellDataWidget.noDataSelected": "Keine Daten ausgewählt",
"cellDataWidget.title": "Zell-Datenansicht",
"chart.detect": "Diagramm erkennen",
"chart.open": "Diagramm öffnen",
"clipboard.SQLInsert": "SQL INSERTs",
@@ -40,6 +45,10 @@
"columnEditor.isSparse": "Sparse",
"columnEditor.isUnsigned": "Vorzeichenlos",
"columnEditor.isZerofill": "Mit Nullen auffüllen",
"columnLine.addReference": "Referenz hinzufügen",
"columnLine.sortAscending": "Aufsteigend sortieren",
"columnLine.sortDescending": "Absteigend sortieren",
"columnLine.unsort": "Sortierung aufheben",
"columnsConstraintEditor.addNewColumn": "Neue Spalte hinzufügen",
"columnsConstraintEditor.chooseColumn": "Spalte auswählen",
"columnsConstraintEditor.selectColumn": "Spalte auswählen",
@@ -289,6 +298,7 @@
"commandModal.showKeyCombination": "Gewünschte Tastenkombination eingeben und ENTER drücken",
"common.addNew": "Neu hinzufügen",
"common.advanced": "Erweitert",
"common.allFields": "Alle {field}",
"common.archive": "Archiv (JSONL)",
"common.cancel": "Abbrechen",
"common.close": "Schließen",
@@ -315,6 +325,7 @@
"common.kill": "Beenden",
"common.loadingData": "Lade Daten",
"common.name": "Name",
"common.newConnection": "Neue Verbindung",
"common.notSelectedOptional": "(nicht ausgewählt - optional)",
"common.parameters": "Parameter",
"common.passwordEncrypted": "Passwort ist verschlüsselt",
@@ -324,6 +335,7 @@
"common.queryEditor": "SQL-Abfrage-Editor",
"common.refresh": "Aktualisieren",
"common.remove": "Entfernen",
"common.removeAll": "Alle entfernen",
"common.reset": "Zurücksetzen",
"common.save": "Speichern",
"common.saveAndNext": "Speichern und weiter",
@@ -331,6 +343,7 @@
"common.schema": "Schema",
"common.search": "Suchen",
"common.searchBy": "Suchen nach:",
"common.server": "Server",
"common.sqlGenerator": "SQL-Generator",
"common.table": "Tabelle",
"common.testingConnection": "Verbindung wird getestet",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Trigger",
"dbObject.truncateTable": "Tabelle leeren",
"dbObject.views": "Sichten",
"designerTable.addReferences": "Referenzen hinzufügen",
"designerTable.changeColor": "Farbe ändern",
"designerTable.defineVirtualForeignKey": "Virtuellen Fremdschlüssel definieren",
"designerTable.newAlias": "Neuer Alias",
"designerTable.removeTableAlias": "Tabellenalias entfernen",
"designerTable.setTableAlias": "Tabellenalias setzen",
"error.driverNotFound": "Ungültige Datenbankverbindung, Treiber nicht gefunden",
"error.selectedCloudConnection": "Ausgewählte Verbindung ist von DbGate Cloud",
"error.selectedNotCloudConnection": "Ausgewählte Verbindung ist nicht von DbGate Cloud",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Abfrage-Designer-Dateien",
"file.sqlFiles": "SQL-Dateien",
"file.sqliteDatabase": "SQLite-Datenbank",
"files.allSupportedFiles": "Alle unterstützten Dateien",
"files.favorites": "Favoriten",
"files.openFile": "Datei öffnen",
"files.refreshFiles": "Dateien aktualisieren",
"files.savedFiles": "Gespeicherte Dateien",
"files.searchSavedFiles": "Gespeicherte Dateien suchen",
"files.sqlFiles": "SQL-Dateien",
"files.teamFiles": "Team-Dateien",
"files.uploadFile": "Datei hochladen",
"filter.after": "Nach...",
"filter.and": "Und",
"filter.arrayIsEmpty": "Array ist leer",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Ref-Spalte - ",
"foreignKeyEditor.referencedTable": "Referenzierte Tabelle",
"foreignKeyEditor.tableNotSet": "(Tabelle nicht festgelegt)",
"history.queryHistory": "Abfrageverlauf",
"history.recentlyClosedTabs": "Kürzlich geschlossene Tabs",
"history.searchQueryHistory": "Abfrageverlauf durchsuchen",
"importExport.action": "Aktion",
"importExport.addWebUrl": "Web-URL hinzufügen",
"importExport.advancedConfiguration": "Erweiterte Konfiguration",
"importExport.archiveFolder": "Archivordner",
"importExport.columns": "Spalten",
"importExport.createZipFileInArchive": "ZIP-Datei im Archiv erstellen",
"importExport.currentArchive": "Aktuelles Archiv",
"importExport.currentDatabase": "Aktuelle DB",
"importExport.dragDropImportedFilesHere": "Importierte Dateien hierher ziehen und ablegen",
"importExport.exportToZipArchive": "In ZIP-Archiv exportieren",
"importExport.exportToZipFile": "In ZIP-Datei exportieren",
"importExport.generateScript": "Skript generieren",
"importExport.importFromZipArchive": "Aus ZIP-Archiv importieren",
"importExport.importFromZipFile": "Aus ZIP-Datei importieren (im Archivordner)",
"importExport.mapSourceTablesFiles": "Quelltabellen/-dateien zuordnen",
"importExport.messages": "Meldungen",
"importExport.newArchive": "Neues Archiv",
"importExport.outputFiles": "Ausgabedateien",
"importExport.preview": "Vorschau",
"importExport.processingImportExport": "Import/Export wird verarbeitet ...",
"importExport.run": "Ausführen",
"importExport.schedule": "Zeitplan",
"importExport.source": "Quelle",
"importExport.sourceConfiguration": "Quellenkonfiguration",
"importExport.sourceFiles": "Quelldateien",
"importExport.startVariableIndex": "Startvariablenindex",
"importExport.status": "Status",
"importExport.stop": "Stopp",
"importExport.storageType": "Speichertyp",
"importExport.tablesViewsCollections": "Tabellen / Sichten / Sammlungen",
"importExport.target": "Ziel",
"importExport.targetConfiguration": "Zielkonfiguration",
"indexEditor.filteredIndexCondition": "Gefilterte Index-Bedingung",
"indexEditor.indexName": "Index-Name",
"indexEditor.isUnique": "Ist eindeutiger Index",
"logs.autoScroll": "Automatisches Scrollen",
"logs.caller": "Aufrufer:",
"logs.callerTab": "Aufrufer",
"logs.chooseDate": "Datum auswählen",
"logs.codeTab": "Code",
"logs.connectionId": "Verbindungs-ID:",
"logs.connectionTab": "Verbindung",
"logs.database": "Datenbank:",
"logs.databaseTab": "Datenbank",
"logs.date": "Datum:",
"logs.dateTab": "Datum",
"logs.details": "Details",
"logs.engine": "Engine:",
"logs.engineTab": "Engine",
"logs.loadingNextRows": "Lade nächste Zeilen...",
"logs.message": "Nachricht:",
"logs.messageCode": "Nachrichtencode:",
"logs.messageTab": "Nachricht",
"logs.name": "Name:",
"logs.nameTab": "Name",
"logs.noDataForSelectedDate": "Keine Daten für ausgewähltes Datum",
"logs.recentLogs": "Letzte Protokolle",
"logs.refresh": "Aktualisieren",
"logs.time": "Zeit:",
"logs.timeTab": "Zeit",
"menu.edit": "Bearbeiten",
"menu.file": "Datei",
"menu.help": "Hilfe",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "SQL-Generator ist für aktuelle Datenbank nicht verfügbar",
"newObject.tableDescription": "Tabelle in der aktuellen Datenbank erstellen",
"newObject.tableDisabled": "Tabellenerstellung ist für aktuelle Datenbank nicht verfügbar",
"plugins.searchExtensionsOnWeb": "Erweiterungen im Web suchen",
"publicCloudWidget.onlyRelevantFilesListed": "Es werden nur Dateien aufgelistet, die für Ihre Verbindungen, Plattform und DbGate-Edition relevant sind. Bitte definieren Sie zuerst Verbindungen.",
"publicCloudWidget.refreshFiles": "Dateien aktualisieren",
"publicCloudWidget.refreshList": "Liste aktualisieren",
"publicCloudWidget.searchPublicFiles": "Öffentliche Dateien suchen",
"query.limitRows": "Auf {queryRowsLimit} Zeilen begrenzen",
"query.named": ":Variable",
"query.noParameters": "(keine Parameter)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Spaltenname",
"sqlObject.databaseEmpty": "Datenbank {database} ist leer oder Struktur ist nicht geladen, drücken Sie die Schaltfläche Aktualisieren, um die Struktur neu zu laden",
"sqlObject.loadingStructure": "Lade Datenbankstruktur",
"sqlObject.name": "Name",
"sqlObject.newCollection": "Neue Sammlung/Container",
"sqlObject.rowCount": "Zeilenanzahl",
"sqlObject.schemaName": "Schema",
"sqlObject.search.placeholder": "In Tabellen, Ansichten, Prozeduren suchen",
"sqlObject.searchBy": "Suchen nach:",
"sqlObject.sizeBytes": "Größe (Bytes)",
"sqlObject.sortBy": "Sortieren nach:",
"sqlObject.tableComment": "Tabellenkommentar",
"sqlObject.tableEngine": "Tabellen-Engine",
"sqlObject.tableViewProcedureName": "Name von Tabelle/Ansicht/Prozedur",
@@ -902,6 +992,17 @@
"widget.keys": "Schlüssel",
"widget.pinned": "Angeheftet",
"widget.tablesViewsFunctions": "Tabellen, Ansichten, Funktionen",
"widgets.addNew": "Neu hinzufügen",
"widgets.administration": "Administration",
"widgets.archive": "Archiv (gespeicherte tabellarische Daten)",
"widgets.availableExtensions": "Verfügbare Erweiterungen",
"widgets.databaseConnections": "Datenbankverbindungen",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Favoriten & gespeicherte Dateien",
"widgets.installedExtensions": "Installierte Erweiterungen",
"widgets.managePlugins": "Plugins verwalten",
"widgets.premiumPromo": "Premium-Werbung",
"widgets.queryHistoryAndClosedTabs": "Abfrageverlauf & geschlossene Tabs",
"widgets.selectedCellDataDetailView": "Detailansicht der ausgewählten Zelldaten",
"widgets.viewApplicationLogs": "Anwendungsprotokolle anzeigen"
}
+102 -1
View File
@@ -3,7 +3,11 @@
"app.loading_plugin": "Loading plugin {plugin} ...",
"app.preparingPlugins": "Preparing plugins ...",
"app.starting": "Starting DbGate",
"connection.authToken": "Auth token",
"cellDataWidget.autodetect": "Autodetect - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Format not selected",
"cellDataWidget.mustSelectOneCell": "Must be selected one cell",
"cellDataWidget.noDataSelected": "No data selected",
"cellDataWidget.title": "Cell data view",
"chart.detect": "Detect chart",
"chart.open": "Open chart",
"clipboard.SQLInsert": "SQL INSERTs",
@@ -41,6 +45,10 @@
"columnEditor.isSparse": "Sparse",
"columnEditor.isUnsigned": "Unsigned",
"columnEditor.isZerofill": "Zero fill",
"columnLine.addReference": "Add reference",
"columnLine.sortAscending": "Sort ascending",
"columnLine.sortDescending": "Sort descending",
"columnLine.unsort": "Unsort",
"columnsConstraintEditor.addNewColumn": "Add new column",
"columnsConstraintEditor.chooseColumn": "Choose column",
"columnsConstraintEditor.selectColumn": "Select column",
@@ -290,6 +298,7 @@
"commandModal.showKeyCombination": "Show desired key combination and press ENTER",
"common.addNew": "Add new",
"common.advanced": "Advanced",
"common.allFields": "All {field}",
"common.archive": "Archive (JSONL)",
"common.cancel": "Cancel",
"common.close": "Close",
@@ -316,6 +325,7 @@
"common.kill": "Kill",
"common.loadingData": "Loading data",
"common.name": "Name",
"common.newConnection": "New Connection",
"common.notSelectedOptional": "(not selected - optional)",
"common.parameters": "Parameters",
"common.passwordEncrypted": "Password is encrypted",
@@ -325,6 +335,7 @@
"common.queryEditor": "SQL query editor",
"common.refresh": "Refresh",
"common.remove": "Remove",
"common.removeAll": "Remove all",
"common.reset": "Reset",
"common.save": "Save",
"common.saveAndNext": "Save and next",
@@ -332,6 +343,7 @@
"common.schema": "Schema",
"common.search": "Search",
"common.searchBy": "Search by:",
"common.server": "Server",
"common.sqlGenerator": "SQL Generator",
"common.table": "Table",
"common.testingConnection": "Testing connection",
@@ -340,6 +352,7 @@
"connection.allowedDatabasesRegex": "Allowed databases regular expression",
"connection.askPassword": "Don't save, ask for password",
"connection.askUser": "Don't save, ask for login and password",
"connection.authToken": "Auth token",
"connection.authentication": "Authentication",
"connection.autoDetectNatMap": "Auto detect NAT map (use for Redis Cluster in Docker network)",
"connection.chooseType": "Choose type",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Triggers",
"dbObject.truncateTable": "Truncate table",
"dbObject.views": "Views",
"designerTable.addReferences": "Add references",
"designerTable.changeColor": "Change color",
"designerTable.defineVirtualForeignKey": "Define virtual foreign key",
"designerTable.newAlias": "New alias",
"designerTable.removeTableAlias": "Remove table alias",
"designerTable.setTableAlias": "Set table alias",
"error.driverNotFound": "Invalid database connection, driver not found",
"error.selectedCloudConnection": "Selected connection is from DbGate cloud",
"error.selectedNotCloudConnection": "Selected connection is not from DbGate cloud",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Query designer files",
"file.sqlFiles": "SQL files",
"file.sqliteDatabase": "SQLite database",
"files.allSupportedFiles": "All supported files",
"files.favorites": "Favorites",
"files.openFile": "Open file",
"files.refreshFiles": "Refresh files",
"files.savedFiles": "Saved files",
"files.searchSavedFiles": "Search saved files",
"files.sqlFiles": "SQL files",
"files.teamFiles": "Team files",
"files.uploadFile": "Upload file",
"filter.after": "After...",
"filter.and": "And",
"filter.arrayIsEmpty": "Array is empty",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Ref column - ",
"foreignKeyEditor.referencedTable": "Referenced table",
"foreignKeyEditor.tableNotSet": "(table not set)",
"history.queryHistory": "Query history",
"history.recentlyClosedTabs": "Recently closed tabs",
"history.searchQueryHistory": "Search query history",
"importExport.action": "Action",
"importExport.addWebUrl": "Add web URL",
"importExport.advancedConfiguration": "Advanced configuration",
"importExport.archiveFolder": "Archive folder",
"importExport.columns": "Columns",
"importExport.createZipFileInArchive": "Create ZIP file in archive",
"importExport.currentArchive": "Current archive",
"importExport.currentDatabase": "Current DB",
"importExport.dragDropImportedFilesHere": "Drag & drop imported files here",
"importExport.exportToZipArchive": "Output ZIP archive",
"importExport.exportToZipFile": "Export to ZIP file",
"importExport.generateScript": "Generate script",
"importExport.importFromZipArchive": "Input ZIP archive",
"importExport.importFromZipFile": "Import from ZIP file (in archive folder)",
"importExport.mapSourceTablesFiles": "Map source tables/files",
"importExport.messages": "Messages",
"importExport.newArchive": "New archive",
"importExport.outputFiles": "Output files",
"importExport.preview": "Preview",
"importExport.processingImportExport": "Processing import/export ...",
"importExport.run": "Run",
"importExport.schedule": "Schedule",
"importExport.source": "Source",
"importExport.sourceConfiguration": "Source configuration",
"importExport.sourceFiles": "Source files",
"importExport.startVariableIndex": "Start variable index",
"importExport.status": "Status",
"importExport.stop": "Stop",
"importExport.storageType": "Storage type",
"importExport.tablesViewsCollections": "Tables / views / collections",
"importExport.target": "Target",
"importExport.targetConfiguration": "Target configuration",
"indexEditor.filteredIndexCondition": "Filtered index condition",
"indexEditor.indexName": "Index name",
"indexEditor.isUnique": "Is unique index",
"logs.autoScroll": "Auto-scroll",
"logs.caller": "Caller:",
"logs.callerTab": "Caller",
"logs.chooseDate": "Choose date",
"logs.codeTab": "Code",
"logs.connectionId": "Connection ID:",
"logs.connectionTab": "Connection",
"logs.database": "Database:",
"logs.databaseTab": "Database",
"logs.date": "Date:",
"logs.dateTab": "Date",
"logs.details": "Details",
"logs.engine": "Engine:",
"logs.engineTab": "Engine",
"logs.loadingNextRows": "Loading next rows...",
"logs.message": "Message:",
"logs.messageCode": "Message code:",
"logs.messageTab": "Message",
"logs.name": "Name:",
"logs.nameTab": "Name",
"logs.noDataForSelectedDate": "No data for selected date",
"logs.recentLogs": "Recent logs",
"logs.refresh": "Refresh",
"logs.time": "Time:",
"logs.timeTab": "Time",
"menu.edit": "Edit",
"menu.file": "File",
"menu.help": "Help",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "SQL Generator is not available for current database",
"newObject.tableDescription": "Create table in the current database",
"newObject.tableDisabled": "Table creation is not available for current database",
"plugins.searchExtensionsOnWeb": "Search extensions on web",
"publicCloudWidget.onlyRelevantFilesListed": "Only files relevant for your connections, platform and DbGate edition are listed. Please define connections at first.",
"publicCloudWidget.refreshFiles": "Refresh files",
"publicCloudWidget.refreshList": "Refresh list",
"publicCloudWidget.searchPublicFiles": "Search public files",
"query.limitRows": "Limit {queryRowsLimit} rows",
"query.named": ":variable",
"query.noParameters": "(no parameters)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Column name",
"sqlObject.databaseEmpty": "Database {database} is empty or structure is not loaded, press Refresh button to reload structure",
"sqlObject.loadingStructure": "Loading database structure",
"sqlObject.name": "Name",
"sqlObject.newCollection": "New collection/container",
"sqlObject.rowCount": "Row count",
"sqlObject.schemaName": "Schema",
"sqlObject.search.placeholder": "Search in tables, views, procedures",
"sqlObject.searchBy": "Search by:",
"sqlObject.sizeBytes": "Size (bytes)",
"sqlObject.sortBy": "Sort by:",
"sqlObject.tableComment": "Table comment",
"sqlObject.tableEngine": "Table engine",
"sqlObject.tableViewProcedureName": "Table/view/procedure name",
@@ -902,6 +992,17 @@
"widget.keys": "Keys",
"widget.pinned": "Pinned",
"widget.tablesViewsFunctions": "Tables, views, functions",
"widgets.addNew": "Add New",
"widgets.administration": "Administration",
"widgets.archive": "Archive (saved tabular data)",
"widgets.availableExtensions": "Available extensions",
"widgets.databaseConnections": "Database connections",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Favorites & Saved files",
"widgets.installedExtensions": "Installed extensions",
"widgets.managePlugins": "Manage plugins",
"widgets.premiumPromo": "Premium promo",
"widgets.queryHistoryAndClosedTabs": "Query history & Closed tabs",
"widgets.selectedCellDataDetailView": "Selected cell data detail view",
"widgets.viewApplicationLogs": "View application logs"
}
+101
View File
@@ -3,6 +3,11 @@
"app.loading_plugin": "Cargando plugin {plugin} ...",
"app.preparingPlugins": "Preparando plugins ...",
"app.starting": "Iniciando DbGate",
"cellDataWidget.autodetect": "Detección automática - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Formato no seleccionado",
"cellDataWidget.mustSelectOneCell": "Debe seleccionarse una celda",
"cellDataWidget.noDataSelected": "No hay datos seleccionados",
"cellDataWidget.title": "Vista de datos de celda",
"chart.detect": "Detectar gráfico",
"chart.open": "Abrir gráfico",
"clipboard.SQLInsert": "SQL INSERTs",
@@ -40,6 +45,10 @@
"columnEditor.isSparse": "Dispersa",
"columnEditor.isUnsigned": "Sin signo",
"columnEditor.isZerofill": "Relleno con ceros",
"columnLine.addReference": "Agregar referencia",
"columnLine.sortAscending": "Ordenar ascendente",
"columnLine.sortDescending": "Ordenar descendente",
"columnLine.unsort": "Quitar orden",
"columnsConstraintEditor.addNewColumn": "Agregar nueva columna",
"columnsConstraintEditor.chooseColumn": "Elegir columna",
"columnsConstraintEditor.selectColumn": "Seleccionar columna",
@@ -289,6 +298,7 @@
"commandModal.showKeyCombination": "Muestre la combinación de teclas deseada y presione ENTER",
"common.addNew": "Agregar nuevo",
"common.advanced": "Avanzado",
"common.allFields": "Todos {field}",
"common.archive": "Archivo (JSONL)",
"common.cancel": "Cancelar",
"common.close": "Cerrar",
@@ -315,6 +325,7 @@
"common.kill": "Terminar",
"common.loadingData": "Cargando datos",
"common.name": "Nombre",
"common.newConnection": "Nueva conexión",
"common.notSelectedOptional": "(no seleccionado - opcional)",
"common.parameters": "Parámetros",
"common.passwordEncrypted": "La contraseña está encriptada",
@@ -324,6 +335,7 @@
"common.queryEditor": "Editor de consultas SQL",
"common.refresh": "Refrescar",
"common.remove": "Eliminar",
"common.removeAll": "Eliminar todo",
"common.reset": "Restablecer",
"common.save": "Guardar",
"common.saveAndNext": "Guardar y siguiente",
@@ -331,6 +343,7 @@
"common.schema": "Esquema",
"common.search": "Buscar",
"common.searchBy": "Buscar por:",
"common.server": "Servidor",
"common.sqlGenerator": "Generador SQL",
"common.table": "Tabla",
"common.testingConnection": "Probando conexión",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Disparadores",
"dbObject.truncateTable": "Truncar tabla",
"dbObject.views": "Vistas",
"designerTable.addReferences": "Agregar referencias",
"designerTable.changeColor": "Cambiar color",
"designerTable.defineVirtualForeignKey": "Definir clave foránea virtual",
"designerTable.newAlias": "Nuevo alias",
"designerTable.removeTableAlias": "Eliminar alias de tabla",
"designerTable.setTableAlias": "Establecer alias de tabla",
"error.driverNotFound": "Conexión de base de datos inválida, controlador no encontrado",
"error.selectedCloudConnection": "La conexión seleccionada es de la nube de DbGate",
"error.selectedNotCloudConnection": "La conexión seleccionada no es de la nube de DbGate",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Archivos de diseñador de consultas",
"file.sqlFiles": "Archivos SQL",
"file.sqliteDatabase": "Base de datos SQLite",
"files.allSupportedFiles": "Todos los archivos soportados",
"files.favorites": "Favoritos",
"files.openFile": "Abrir archivo",
"files.refreshFiles": "Refrescar archivos",
"files.savedFiles": "Archivos guardados",
"files.searchSavedFiles": "Buscar archivos guardados",
"files.sqlFiles": "Archivos SQL",
"files.teamFiles": "Archivos de equipo",
"files.uploadFile": "Subir archivo",
"filter.after": "Después de...",
"filter.and": "Y",
"filter.arrayIsEmpty": "El arreglo está vacío",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Columna ref - ",
"foreignKeyEditor.referencedTable": "Tabla referenciada",
"foreignKeyEditor.tableNotSet": "(tabla no establecida)",
"history.queryHistory": "Historial de consultas",
"history.recentlyClosedTabs": "Pestañas cerradas recientemente",
"history.searchQueryHistory": "Buscar en historial de consultas",
"importExport.action": "Acción",
"importExport.addWebUrl": "Agregar URL web",
"importExport.advancedConfiguration": "Configuración avanzada",
"importExport.archiveFolder": "Carpeta de archivo",
"importExport.columns": "Columnas",
"importExport.createZipFileInArchive": "Crear archivo ZIP en el archivo",
"importExport.currentArchive": "Archivo actual",
"importExport.currentDatabase": "BD actual",
"importExport.dragDropImportedFilesHere": "Arrastre y suelte aquí los archivos importados",
"importExport.exportToZipArchive": "Archivo ZIP de salida",
"importExport.exportToZipFile": "Exportar a archivo ZIP",
"importExport.generateScript": "Generar script",
"importExport.importFromZipArchive": "Archivo ZIP de entrada",
"importExport.importFromZipFile": "Importar desde archivo ZIP (en carpeta de archivo)",
"importExport.mapSourceTablesFiles": "Mapear tablas/archivos de origen",
"importExport.messages": "Mensajes",
"importExport.newArchive": "Nuevo archivo",
"importExport.outputFiles": "Archivos de salida",
"importExport.preview": "Vista previa",
"importExport.processingImportExport": "Procesando importación/exportación ...",
"importExport.run": "Ejecutar",
"importExport.schedule": "Programar",
"importExport.source": "Origen",
"importExport.sourceConfiguration": "Configuración de origen",
"importExport.sourceFiles": "Archivos de origen",
"importExport.startVariableIndex": "Índice inicial de variable",
"importExport.status": "Estado",
"importExport.stop": "Detener",
"importExport.storageType": "Tipo de almacenamiento",
"importExport.tablesViewsCollections": "Tablas / vistas / colecciones",
"importExport.target": "Destino",
"importExport.targetConfiguration": "Configuración de destino",
"indexEditor.filteredIndexCondition": "Condición de índice filtrado",
"indexEditor.indexName": "Nombre de índice",
"indexEditor.isUnique": "Es índice único",
"logs.autoScroll": "Desplazamiento automático",
"logs.caller": "Llamador:",
"logs.callerTab": "Llamador",
"logs.chooseDate": "Elegir fecha",
"logs.codeTab": "Código",
"logs.connectionId": "ID de conexión:",
"logs.connectionTab": "Conexión",
"logs.database": "Base de datos:",
"logs.databaseTab": "Base de datos",
"logs.date": "Fecha:",
"logs.dateTab": "Fecha",
"logs.details": "Detalles",
"logs.engine": "Motor:",
"logs.engineTab": "Motor",
"logs.loadingNextRows": "Cargando siguientes filas...",
"logs.message": "Mensaje:",
"logs.messageCode": "Código de mensaje:",
"logs.messageTab": "Mensaje",
"logs.name": "Nombre:",
"logs.nameTab": "Nombre",
"logs.noDataForSelectedDate": "No hay datos para la fecha seleccionada",
"logs.recentLogs": "Registros recientes",
"logs.refresh": "Refrescar",
"logs.time": "Hora:",
"logs.timeTab": "Hora",
"menu.edit": "Editar",
"menu.file": "Archivo",
"menu.help": "Ayuda",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "El generador SQL no está disponible para la base de datos actual",
"newObject.tableDescription": "Crear tabla en la base de datos actual",
"newObject.tableDisabled": "La creación de tablas no está disponible para la base de datos actual",
"plugins.searchExtensionsOnWeb": "Buscar extensiones en la web",
"publicCloudWidget.onlyRelevantFilesListed": "Solo se listan archivos relevantes para sus conexiones, plataforma y edición de DbGate. Defina primero las conexiones.",
"publicCloudWidget.refreshFiles": "Refrescar archivos",
"publicCloudWidget.refreshList": "Refrescar lista",
"publicCloudWidget.searchPublicFiles": "Buscar archivos públicos",
"query.limitRows": "Limitar {queryRowsLimit} filas",
"query.named": ":variable",
"query.noParameters": "(sin parámetros)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Nombre de columna",
"sqlObject.databaseEmpty": "La base de datos {database} está vacía o la estructura no está cargada, presione el botón Refrescar para recargar la estructura",
"sqlObject.loadingStructure": "Cargando estructura de base de datos",
"sqlObject.name": "Nombre",
"sqlObject.newCollection": "Nueva colección/contenedor",
"sqlObject.rowCount": "Recuento de filas",
"sqlObject.schemaName": "Esquema",
"sqlObject.search.placeholder": "Buscar en tablas, vistas, procedimientos",
"sqlObject.searchBy": "Buscar por:",
"sqlObject.sizeBytes": "Tamaño (bytes)",
"sqlObject.sortBy": "Ordenar por:",
"sqlObject.tableComment": "Comentario de tabla",
"sqlObject.tableEngine": "Motor de tabla",
"sqlObject.tableViewProcedureName": "Nombre de tabla/vista/procedimiento",
@@ -902,6 +992,17 @@
"widget.keys": "Claves",
"widget.pinned": "Anclado",
"widget.tablesViewsFunctions": "Tablas, vistas, funciones",
"widgets.addNew": "Agregar nuevo",
"widgets.administration": "Administración",
"widgets.archive": "Archivo (datos tabulares guardados)",
"widgets.availableExtensions": "Extensiones disponibles",
"widgets.databaseConnections": "Conexiones de base de datos",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Favoritos y archivos guardados",
"widgets.installedExtensions": "Extensiones instaladas",
"widgets.managePlugins": "Administrar plugins",
"widgets.premiumPromo": "Promoción Premium",
"widgets.queryHistoryAndClosedTabs": "Historial de consultas y pestañas cerradas",
"widgets.selectedCellDataDetailView": "Vista detallada de datos de celda seleccionada",
"widgets.viewApplicationLogs": "Ver registros de la aplicación"
}
+101
View File
@@ -3,6 +3,11 @@
"app.loading_plugin": "Chargement du plugin {plugin}...",
"app.preparingPlugins": "Préparation des plugins...",
"app.starting": "Démarrage de DbGate",
"cellDataWidget.autodetect": "Détection automatique - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Format non sélectionné",
"cellDataWidget.mustSelectOneCell": "Une seule cellule doit être sélectionnée",
"cellDataWidget.noDataSelected": "Aucune donnée sélectionnée",
"cellDataWidget.title": "Vue des données de cellule",
"chart.detect": "Détecter le graphique",
"chart.open": "Ouvrir le graphique",
"clipboard.SQLInsert": "INSERT SQL",
@@ -40,6 +45,10 @@
"columnEditor.isSparse": "Sparse",
"columnEditor.isUnsigned": "Non signé",
"columnEditor.isZerofill": "Remplissage de zéros",
"columnLine.addReference": "Ajouter une référence",
"columnLine.sortAscending": "Trier par ordre croissant",
"columnLine.sortDescending": "Trier par ordre décroissant",
"columnLine.unsort": "Annuler le tri",
"columnsConstraintEditor.addNewColumn": "Ajouter une nouvelle colonne",
"columnsConstraintEditor.chooseColumn": "Choisir une colonne",
"columnsConstraintEditor.selectColumn": "Sélectionner une colonne",
@@ -289,6 +298,7 @@
"commandModal.showKeyCombination": "Afficher la combinaison de touches souhaitée et appuyez sur ENTRÉE",
"common.addNew": "Ajouter un nouvel élément",
"common.advanced": "Avancé",
"common.allFields": "Tous les {field}",
"common.archive": "Archive (JSONL)",
"common.cancel": "Annuler",
"common.close": "Fermer",
@@ -315,6 +325,7 @@
"common.kill": "Tuer",
"common.loadingData": "Chargement des données",
"common.name": "Nom",
"common.newConnection": "Nouvelle connexion",
"common.notSelectedOptional": "(non sélectionné - optionnel)",
"common.parameters": "Paramètres",
"common.passwordEncrypted": "Le mot de passe est chiffré",
@@ -324,6 +335,7 @@
"common.queryEditor": "Éditeur de requêtes SQL",
"common.refresh": "Rafraîchir",
"common.remove": "Supprimer",
"common.removeAll": "Tout supprimer",
"common.reset": "Réinitialiser",
"common.save": "Enregistrer",
"common.saveAndNext": "Enregistrer et passer au suivant",
@@ -331,6 +343,7 @@
"common.schema": "Schéma",
"common.search": "Rechercher",
"common.searchBy": "Rechercher par :",
"common.server": "Serveur",
"common.sqlGenerator": "Générateur SQL",
"common.table": "Table",
"common.testingConnection": "Test de connexion",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Déclencheurs",
"dbObject.truncateTable": "Tronquer la table",
"dbObject.views": "Vues",
"designerTable.addReferences": "Ajouter des références",
"designerTable.changeColor": "Changer la couleur",
"designerTable.defineVirtualForeignKey": "Définir une clé étrangère virtuelle",
"designerTable.newAlias": "Nouvel alias",
"designerTable.removeTableAlias": "Supprimer l'alias de table",
"designerTable.setTableAlias": "Définir l'alias de table",
"error.driverNotFound": "Connexion de base de données non valide, pilote introuvable",
"error.selectedCloudConnection": "La connexion sélectionnée provient du cloud DbGate",
"error.selectedNotCloudConnection": "La connexion sélectionnée ne provient pas du cloud DbGate",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Fichiers du concepteur de requêtes",
"file.sqlFiles": "Fichiers SQL",
"file.sqliteDatabase": "Base de données SQLite",
"files.allSupportedFiles": "Tous les fichiers pris en charge",
"files.favorites": "Favoris",
"files.openFile": "Ouvrir le fichier",
"files.refreshFiles": "Rafraîchir les fichiers",
"files.savedFiles": "Fichiers enregistrés",
"files.searchSavedFiles": "Rechercher dans les fichiers enregistrés",
"files.sqlFiles": "Fichiers SQL",
"files.teamFiles": "Fichiers d'équipe",
"files.uploadFile": "Téléverser un fichier",
"filter.after": "Après...",
"filter.and": "Et",
"filter.arrayIsEmpty": "Le tableau est vide",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Colonne réf. - ",
"foreignKeyEditor.referencedTable": "Table référencée",
"foreignKeyEditor.tableNotSet": "(table non définie)",
"history.queryHistory": "Historique des requêtes",
"history.recentlyClosedTabs": "Onglets récemment fermés",
"history.searchQueryHistory": "Rechercher dans l'historique des requêtes",
"importExport.action": "Action",
"importExport.addWebUrl": "Ajouter une URL web",
"importExport.advancedConfiguration": "Configuration avancée",
"importExport.archiveFolder": "Dossier d'archive",
"importExport.columns": "Colonnes",
"importExport.createZipFileInArchive": "Créer un fichier ZIP dans l'archive",
"importExport.currentArchive": "Archive actuelle",
"importExport.currentDatabase": "BD actuelle",
"importExport.dragDropImportedFilesHere": "Glissez-déposez les fichiers importés ici",
"importExport.exportToZipArchive": "Archive ZIP de sortie",
"importExport.exportToZipFile": "Exporter vers un fichier ZIP",
"importExport.generateScript": "Générer un script",
"importExport.importFromZipArchive": "Archive ZIP d'entrée",
"importExport.importFromZipFile": "Importer depuis un fichier ZIP (dans le dossier d'archive)",
"importExport.mapSourceTablesFiles": "Mapper les tables/fichiers source",
"importExport.messages": "Messages",
"importExport.newArchive": "Nouvelle archive",
"importExport.outputFiles": "Fichiers de sortie",
"importExport.preview": "Aperçu",
"importExport.processingImportExport": "Traitement de l'import/export...",
"importExport.run": "Exécuter",
"importExport.schedule": "Planifier",
"importExport.source": "Source",
"importExport.sourceConfiguration": "Configuration de la source",
"importExport.sourceFiles": "Fichiers source",
"importExport.startVariableIndex": "Index de variable de départ",
"importExport.status": "Statut",
"importExport.stop": "Arrêter",
"importExport.storageType": "Type de stockage",
"importExport.tablesViewsCollections": "Tables / vues / collections",
"importExport.target": "Cible",
"importExport.targetConfiguration": "Configuration de la cible",
"indexEditor.filteredIndexCondition": "Condition d'index filtré",
"indexEditor.indexName": "Nom de l'index",
"indexEditor.isUnique": "Est un index unique",
"logs.autoScroll": "Défilement automatique",
"logs.caller": "Appelant :",
"logs.callerTab": "Appelant",
"logs.chooseDate": "Choisir la date",
"logs.codeTab": "Code",
"logs.connectionId": "ID de connexion :",
"logs.connectionTab": "Connexion",
"logs.database": "Base de données :",
"logs.databaseTab": "Base de données",
"logs.date": "Date :",
"logs.dateTab": "Date",
"logs.details": "Détails",
"logs.engine": "Moteur :",
"logs.engineTab": "Moteur",
"logs.loadingNextRows": "Chargement des lignes suivantes...",
"logs.message": "Message :",
"logs.messageCode": "Code du message :",
"logs.messageTab": "Message",
"logs.name": "Nom :",
"logs.nameTab": "Nom",
"logs.noDataForSelectedDate": "Aucune donnée pour la date sélectionnée",
"logs.recentLogs": "Journaux récents",
"logs.refresh": "Rafraîchir",
"logs.time": "Heure :",
"logs.timeTab": "Heure",
"menu.edit": "Modifier",
"menu.file": "Fichier",
"menu.help": "Aide",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "Le générateur SQL n'est pas disponible pour la base de données actuelle",
"newObject.tableDescription": "Créer une table dans la base de données actuelle",
"newObject.tableDisabled": "La création de table n'est pas disponible pour la base de données actuelle",
"plugins.searchExtensionsOnWeb": "Rechercher des extensions sur le web",
"publicCloudWidget.onlyRelevantFilesListed": "Seuls les fichiers pertinents pour vos connexions, votre plateforme et votre édition de DbGate sont listés. Veuillez d'abord définir des connexions.",
"publicCloudWidget.refreshFiles": "Rafraîchir les fichiers",
"publicCloudWidget.refreshList": "Rafraîchir la liste",
"publicCloudWidget.searchPublicFiles": "Rechercher des fichiers publics",
"query.limitRows": "Limiter à {queryRowsLimit} lignes",
"query.named": ":variable",
"query.noParameters": "(aucun paramètre)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Nom de colonne",
"sqlObject.databaseEmpty": "La base de données {database} est vide ou la structure n'est pas chargée, appuyez sur le bouton Rafraîchir pour recharger la structure",
"sqlObject.loadingStructure": "Chargement de la structure de la base de données",
"sqlObject.name": "Nom",
"sqlObject.newCollection": "Nouvelle collection/conteneur",
"sqlObject.rowCount": "Nombre de lignes",
"sqlObject.schemaName": "Schéma",
"sqlObject.search.placeholder": "Rechercher dans les tables, vues, procédures",
"sqlObject.searchBy": "Rechercher par :",
"sqlObject.sizeBytes": "Taille (octets)",
"sqlObject.sortBy": "Trier par :",
"sqlObject.tableComment": "Commentaire de table",
"sqlObject.tableEngine": "Moteur de table",
"sqlObject.tableViewProcedureName": "Nom de table/vue/procédure",
@@ -902,6 +992,17 @@
"widget.keys": "Clés",
"widget.pinned": "Épinglé",
"widget.tablesViewsFunctions": "Tables, vues, fonctions",
"widgets.addNew": "Ajouter un nouvel élément",
"widgets.administration": "Administration",
"widgets.archive": "Archive (données tabulaires enregistrées)",
"widgets.availableExtensions": "Extensions disponibles",
"widgets.databaseConnections": "Connexions de base de données",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Favoris et fichiers enregistrés",
"widgets.installedExtensions": "Extensions installées",
"widgets.managePlugins": "Gérer les plugins",
"widgets.premiumPromo": "Promotion Premium",
"widgets.queryHistoryAndClosedTabs": "Historique des requêtes et onglets fermés",
"widgets.selectedCellDataDetailView": "Vue détaillée des données de la cellule sélectionnée",
"widgets.viewApplicationLogs": "Afficher les journaux de l'application"
}
+103 -2
View File
@@ -3,7 +3,11 @@
"app.loading_plugin": "Caricamento plugin {plugin} ...",
"app.preparingPlugins": "Preparazione plugin ...",
"app.starting": "Avvio DbGate",
"connection.authToken": "Token di autenticazione",
"cellDataWidget.autodetect": "Rilevamento automatico - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Formato non selezionato",
"cellDataWidget.mustSelectOneCell": "Deve essere selezionata una cella",
"cellDataWidget.noDataSelected": "Nessun dato selezionato",
"cellDataWidget.title": "Vista dati cella",
"chart.detect": "Rileva grafico",
"chart.open": "Apri grafico",
"clipboard.SQLInsert": "SQL INSERTs",
@@ -41,6 +45,10 @@
"columnEditor.isSparse": "Sparse",
"columnEditor.isUnsigned": "Unsigned",
"columnEditor.isZerofill": "Zero fill",
"columnLine.addReference": "Aggiungi riferimento",
"columnLine.sortAscending": "Ordina crescente",
"columnLine.sortDescending": "Ordina decrescente",
"columnLine.unsort": "Rimuovi ordinamento",
"columnsConstraintEditor.addNewColumn": "Aggiungi nuova colonna",
"columnsConstraintEditor.chooseColumn": "Scegli colonna",
"columnsConstraintEditor.selectColumn": "Seleziona colonna",
@@ -290,6 +298,7 @@
"commandModal.showKeyCombination": "Mostra la combinazione di tasti desiderata e premi INVIO",
"common.addNew": "Aggiungi nuovo",
"common.advanced": "Avanzate",
"common.allFields": "Tutti {field}",
"common.archive": "Archivio (JSONL)",
"common.cancel": "Annulla",
"common.close": "Chiudi",
@@ -316,6 +325,7 @@
"common.kill": "Termina",
"common.loadingData": "Caricamento dati",
"common.name": "Nome",
"common.newConnection": "Nuova connessione",
"common.notSelectedOptional": "(non selezionato - opzionale)",
"common.parameters": "Parametri",
"common.passwordEncrypted": "La password è crittografata",
@@ -325,6 +335,7 @@
"common.queryEditor": "Editor query SQL",
"common.refresh": "Aggiorna",
"common.remove": "Rimuovi",
"common.removeAll": "Rimuovi tutto",
"common.reset": "Ripristina",
"common.save": "Salva",
"common.saveAndNext": "Salva e avanti",
@@ -332,6 +343,7 @@
"common.schema": "Schema",
"common.search": "Cerca",
"common.searchBy": "Cerca per:",
"common.server": "Server",
"common.sqlGenerator": "Generatore SQL",
"common.table": "Tabella",
"common.testingConnection": "Test connessione",
@@ -340,6 +352,7 @@
"connection.allowedDatabasesRegex": "Espressione regolare database consentiti",
"connection.askPassword": "Non salvare, richiedi password",
"connection.askUser": "Non salvare, richiedi login e password",
"connection.authToken": "Token di autenticazione",
"connection.authentication": "Autenticazione",
"connection.autoDetectNatMap": "Rileva automaticamente mappa NAT (usa per Redis Cluster in rete Docker)",
"connection.chooseType": "Scegli tipo",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Trigger",
"dbObject.truncateTable": "Truncate tabella",
"dbObject.views": "Viste",
"designerTable.addReferences": "Aggiungi riferimenti",
"designerTable.changeColor": "Cambia colore",
"designerTable.defineVirtualForeignKey": "Definisci chiave esterna virtuale",
"designerTable.newAlias": "Nuovo alias",
"designerTable.removeTableAlias": "Rimuovi alias tabella",
"designerTable.setTableAlias": "Imposta alias tabella",
"error.driverNotFound": "Connessione database non valida, driver non trovato",
"error.selectedCloudConnection": "La connessione selezionata è da DbGate cloud",
"error.selectedNotCloudConnection": "La connessione selezionata non è da DbGate cloud",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "File designer query",
"file.sqlFiles": "File SQL",
"file.sqliteDatabase": "Database SQLite",
"files.allSupportedFiles": "Tutti i file supportati",
"files.favorites": "Preferiti",
"files.openFile": "Apri file",
"files.refreshFiles": "Aggiorna file",
"files.savedFiles": "File salvati",
"files.searchSavedFiles": "Cerca file salvati",
"files.sqlFiles": "File SQL",
"files.teamFiles": "File team",
"files.uploadFile": "Carica file",
"filter.after": "Dopo...",
"filter.and": "E",
"filter.arrayIsEmpty": "Array è vuoto",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Colonna rif - ",
"foreignKeyEditor.referencedTable": "Tabella referenziata",
"foreignKeyEditor.tableNotSet": "(tabella non impostata)",
"history.queryHistory": "Cronologia query",
"history.recentlyClosedTabs": "Schede chiuse di recente",
"history.searchQueryHistory": "Cerca nella cronologia query",
"importExport.action": "Azione",
"importExport.addWebUrl": "Aggiungi URL web",
"importExport.advancedConfiguration": "Configurazione avanzata",
"importExport.archiveFolder": "Cartella archivio",
"importExport.columns": "Colonne",
"importExport.createZipFileInArchive": "Crea file ZIP nell'archivio",
"importExport.currentArchive": "Archivio corrente",
"importExport.currentDatabase": "DB corrente",
"importExport.dragDropImportedFilesHere": "Trascina e rilascia qui i file da importare",
"importExport.exportToZipArchive": "Archivio ZIP di output",
"importExport.exportToZipFile": "Esporta in file ZIP",
"importExport.generateScript": "Genera script",
"importExport.importFromZipArchive": "Archivio ZIP di input",
"importExport.importFromZipFile": "Importa da file ZIP (nella cartella archivio)",
"importExport.mapSourceTablesFiles": "Mappa tabelle/file sorgente",
"importExport.messages": "Messaggi",
"importExport.newArchive": "Nuovo archivio",
"importExport.outputFiles": "File di output",
"importExport.preview": "Anteprima",
"importExport.processingImportExport": "Elaborazione import/export ...",
"importExport.run": "Esegui",
"importExport.schedule": "Pianifica",
"importExport.source": "Sorgente",
"importExport.sourceConfiguration": "Configurazione sorgente",
"importExport.sourceFiles": "File sorgente",
"importExport.startVariableIndex": "Indice variabile iniziale",
"importExport.status": "Stato",
"importExport.stop": "Ferma",
"importExport.storageType": "Tipo archiviazione",
"importExport.tablesViewsCollections": "Tabelle / viste / collezioni",
"importExport.target": "Destinazione",
"importExport.targetConfiguration": "Configurazione destinazione",
"indexEditor.filteredIndexCondition": "Condizione indice filtrato",
"indexEditor.indexName": "Nome indice",
"indexEditor.isUnique": "È indice univoco",
"logs.autoScroll": "Scorrimento automatico",
"logs.caller": "Chiamante:",
"logs.callerTab": "Chiamante",
"logs.chooseDate": "Scegli data",
"logs.codeTab": "Codice",
"logs.connectionId": "ID connessione:",
"logs.connectionTab": "Connessione",
"logs.database": "Database:",
"logs.databaseTab": "Database",
"logs.date": "Data:",
"logs.dateTab": "Data",
"logs.details": "Dettagli",
"logs.engine": "Motore:",
"logs.engineTab": "Motore",
"logs.loadingNextRows": "Caricamento righe successive...",
"logs.message": "Messaggio:",
"logs.messageCode": "Codice messaggio:",
"logs.messageTab": "Messaggio",
"logs.name": "Nome:",
"logs.nameTab": "Nome",
"logs.noDataForSelectedDate": "Nessun dato per la data selezionata",
"logs.recentLogs": "Log recenti",
"logs.refresh": "Aggiorna",
"logs.time": "Ora:",
"logs.timeTab": "Ora",
"menu.edit": "Modifica",
"menu.file": "File",
"menu.help": "Aiuto",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "Il generatore SQL non è disponibile per il database corrente",
"newObject.tableDescription": "Crea tabella nel database corrente",
"newObject.tableDisabled": "La creazione tabella non è disponibile per il database corrente",
"plugins.searchExtensionsOnWeb": "Cerca estensioni sul web",
"publicCloudWidget.onlyRelevantFilesListed": "Sono elencati solo i file rilevanti per le tue connessioni, piattaforma ed edizione DbGate. Definisci prima le connessioni.",
"publicCloudWidget.refreshFiles": "Aggiorna file",
"publicCloudWidget.refreshList": "Aggiorna elenco",
"publicCloudWidget.searchPublicFiles": "Cerca file pubblici",
"query.limitRows": "Limita a {queryRowsLimit} righe",
"query.named": ":variabile",
"query.noParameters": "(nessun parametro)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Nome colonna",
"sqlObject.databaseEmpty": "Il database {database} è vuoto o la struttura non è caricata, premi il pulsante Aggiorna per ricaricare la struttura",
"sqlObject.loadingStructure": "Caricamento struttura database",
"sqlObject.name": "Nome",
"sqlObject.newCollection": "Nuova collezione/container",
"sqlObject.rowCount": "Conteggio righe",
"sqlObject.schemaName": "Schema",
"sqlObject.search.placeholder": "Cerca in tabelle, viste, procedure",
"sqlObject.searchBy": "Cerca per:",
"sqlObject.sizeBytes": "Dimensione (byte)",
"sqlObject.sortBy": "Ordina per:",
"sqlObject.tableComment": "Commento tabella",
"sqlObject.tableEngine": "Motore tabella",
"sqlObject.tableViewProcedureName": "Nome tabella/vista/procedura",
@@ -902,6 +992,17 @@
"widget.keys": "Chiavi",
"widget.pinned": "Fissate",
"widget.tablesViewsFunctions": "Tabelle, viste, funzioni",
"widgets.addNew": "Aggiungi nuovo",
"widgets.administration": "Amministrazione",
"widgets.archive": "Archivio (dati tabellari salvati)",
"widgets.availableExtensions": "Estensioni disponibili",
"widgets.databaseConnections": "Connessioni database",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Preferiti e file salvati",
"widgets.installedExtensions": "Estensioni installate",
"widgets.managePlugins": "Gestisci plugin",
"widgets.premiumPromo": "Promo Premium",
"widgets.queryHistoryAndClosedTabs": "Cronologia query e schede chiuse",
"widgets.selectedCellDataDetailView": "Vista dettagliata dati cella selezionata",
"widgets.viewApplicationLogs": "Visualizza log applicazione"
}
}
+1008
View File
File diff suppressed because it is too large Load Diff
+103 -2
View File
@@ -3,7 +3,11 @@
"app.loading_plugin": "Carregando plugin {plugin} ...",
"app.preparingPlugins": "Preparando plugins ...",
"app.starting": "Iniciando DbGate",
"connection.authToken": "Token de autenticação",
"cellDataWidget.autodetect": "Auto detectar - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Formato não selecionado",
"cellDataWidget.mustSelectOneCell": "Deve ser selecionada uma célula",
"cellDataWidget.noDataSelected": "Nenhum dado selecionado",
"cellDataWidget.title": "Visualização de dados da célula",
"chart.detect": "Detectar gráfico",
"chart.open": "Abrir gráfico",
"clipboard.SQLInsert": "SQL INSERTs",
@@ -41,6 +45,10 @@
"columnEditor.isSparse": "Esparso",
"columnEditor.isUnsigned": "Sem sinal",
"columnEditor.isZerofill": "Preenchimento com zero",
"columnLine.addReference": "Adicionar referência",
"columnLine.sortAscending": "Ordenar crescente",
"columnLine.sortDescending": "Ordenar decrescente",
"columnLine.unsort": "Remover ordenação",
"columnsConstraintEditor.addNewColumn": "Adicionar nova coluna",
"columnsConstraintEditor.chooseColumn": "Escolher coluna",
"columnsConstraintEditor.selectColumn": "Selecionar coluna",
@@ -290,6 +298,7 @@
"commandModal.showKeyCombination": "Mostre a combinação de teclas desejada e pressione ENTER",
"common.addNew": "Adicionar novo",
"common.advanced": "Avançado",
"common.allFields": "Todos {field}",
"common.archive": "Arquivo (JSONL)",
"common.cancel": "Cancelar",
"common.close": "Fechar",
@@ -316,6 +325,7 @@
"common.kill": "Encerrar",
"common.loadingData": "Carregando dados",
"common.name": "Nome",
"common.newConnection": "Nova conexão",
"common.notSelectedOptional": "(não selecionado - opcional)",
"common.parameters": "Parâmetros",
"common.passwordEncrypted": "Senha está criptografada",
@@ -325,6 +335,7 @@
"common.queryEditor": "Editor de consulta SQL",
"common.refresh": "Atualizar",
"common.remove": "Remover",
"common.removeAll": "Remover tudo",
"common.reset": "Resetar",
"common.save": "Salvar",
"common.saveAndNext": "Salvar e próximo",
@@ -332,6 +343,7 @@
"common.schema": "Schema",
"common.search": "Pesquisar",
"common.searchBy": "Pesquisar por:",
"common.server": "Servidor",
"common.sqlGenerator": "Gerador SQL",
"common.table": "Tabela",
"common.testingConnection": "Testando conexão",
@@ -340,6 +352,7 @@
"connection.allowedDatabasesRegex": "Expressão regular de bancos de dados permitidos",
"connection.askPassword": "Não salvar, perguntar senha",
"connection.askUser": "Não salvar, perguntar login e senha",
"connection.authToken": "Token de autenticação",
"connection.authentication": "Autenticação",
"connection.autoDetectNatMap": "Auto detectar mapa NAT (use para Redis Cluster em rede Docker)",
"connection.chooseType": "Escolher tipo",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Gatilhos",
"dbObject.truncateTable": "Truncar tabela",
"dbObject.views": "Visões",
"designerTable.addReferences": "Adicionar referências",
"designerTable.changeColor": "Alterar cor",
"designerTable.defineVirtualForeignKey": "Definir chave estrangeira virtual",
"designerTable.newAlias": "Novo alias",
"designerTable.removeTableAlias": "Remover alias da tabela",
"designerTable.setTableAlias": "Definir alias da tabela",
"error.driverNotFound": "Conexão de banco de dados inválida, driver não encontrado",
"error.selectedCloudConnection": "Conexão selecionada é da nuvem DbGate",
"error.selectedNotCloudConnection": "Conexão selecionada não é da nuvem DbGate",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Arquivos de designer de consulta",
"file.sqlFiles": "Arquivos SQL",
"file.sqliteDatabase": "Banco de dados SQLite",
"files.allSupportedFiles": "Todos os arquivos suportados",
"files.favorites": "Favoritos",
"files.openFile": "Abrir arquivo",
"files.refreshFiles": "Atualizar arquivos",
"files.savedFiles": "Arquivos salvos",
"files.searchSavedFiles": "Pesquisar arquivos salvos",
"files.sqlFiles": "Arquivos SQL",
"files.teamFiles": "Arquivos de equipe",
"files.uploadFile": "Enviar arquivo",
"filter.after": "Depois de...",
"filter.and": "E",
"filter.arrayIsEmpty": "Array está vazio",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Coluna ref - ",
"foreignKeyEditor.referencedTable": "Tabela referenciada",
"foreignKeyEditor.tableNotSet": "(tabela não definida)",
"history.queryHistory": "Histórico de consultas",
"history.recentlyClosedTabs": "Abas fechadas recentemente",
"history.searchQueryHistory": "Pesquisar histórico de consultas",
"importExport.action": "Ação",
"importExport.addWebUrl": "Adicionar URL da web",
"importExport.advancedConfiguration": "Configuração avançada",
"importExport.archiveFolder": "Pasta de arquivo",
"importExport.columns": "Colunas",
"importExport.createZipFileInArchive": "Criar arquivo ZIP no arquivo",
"importExport.currentArchive": "Arquivo atual",
"importExport.currentDatabase": "BD atual",
"importExport.dragDropImportedFilesHere": "Arraste e solte arquivos importados aqui",
"importExport.exportToZipArchive": "Arquivo ZIP de saída",
"importExport.exportToZipFile": "Exportar para arquivo ZIP",
"importExport.generateScript": "Gerar script",
"importExport.importFromZipArchive": "Arquivo ZIP de entrada",
"importExport.importFromZipFile": "Importar de arquivo ZIP (na pasta de arquivo)",
"importExport.mapSourceTablesFiles": "Mapear tabelas/arquivos de origem",
"importExport.messages": "Mensagens",
"importExport.newArchive": "Novo arquivo",
"importExport.outputFiles": "Arquivos de saída",
"importExport.preview": "Visualizar",
"importExport.processingImportExport": "Processando importação/exportação ...",
"importExport.run": "Executar",
"importExport.schedule": "Agendar",
"importExport.source": "Origem",
"importExport.sourceConfiguration": "Configuração de origem",
"importExport.sourceFiles": "Arquivos de origem",
"importExport.startVariableIndex": "Índice inicial da variável",
"importExport.status": "Status",
"importExport.stop": "Parar",
"importExport.storageType": "Tipo de armazenamento",
"importExport.tablesViewsCollections": "Tabelas / visões / coleções",
"importExport.target": "Destino",
"importExport.targetConfiguration": "Configuração de destino",
"indexEditor.filteredIndexCondition": "Condição de índice filtrado",
"indexEditor.indexName": "Nome do índice",
"indexEditor.isUnique": "É índice único",
"logs.autoScroll": "Rolagem automática",
"logs.caller": "Chamador:",
"logs.callerTab": "Chamador",
"logs.chooseDate": "Escolher data",
"logs.codeTab": "Código",
"logs.connectionId": "ID da conexão:",
"logs.connectionTab": "Conexão",
"logs.database": "Banco de dados:",
"logs.databaseTab": "Banco de dados",
"logs.date": "Data:",
"logs.dateTab": "Data",
"logs.details": "Detalhes",
"logs.engine": "Motor:",
"logs.engineTab": "Motor",
"logs.loadingNextRows": "Carregando próximas linhas...",
"logs.message": "Mensagem:",
"logs.messageCode": "Código da mensagem:",
"logs.messageTab": "Mensagem",
"logs.name": "Nome:",
"logs.nameTab": "Nome",
"logs.noDataForSelectedDate": "Nenhum dado para a data selecionada",
"logs.recentLogs": "Logs recentes",
"logs.refresh": "Atualizar",
"logs.time": "Hora:",
"logs.timeTab": "Hora",
"menu.edit": "Editar",
"menu.file": "Arquivo",
"menu.help": "Ajuda",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "Gerador SQL não está disponível para o banco de dados atual",
"newObject.tableDescription": "Criar tabela no banco de dados atual",
"newObject.tableDisabled": "Criação de tabela não está disponível para o banco de dados atual",
"plugins.searchExtensionsOnWeb": "Pesquisar extensões na web",
"publicCloudWidget.onlyRelevantFilesListed": "Apenas arquivos relevantes para suas conexões, plataforma e edição do DbGate são listados. Defina conexões primeiro.",
"publicCloudWidget.refreshFiles": "Atualizar arquivos",
"publicCloudWidget.refreshList": "Atualizar lista",
"publicCloudWidget.searchPublicFiles": "Pesquisar arquivos públicos",
"query.limitRows": "Limitar a {queryRowsLimit} linhas",
"query.named": ":variável",
"query.noParameters": "(sem parâmetros)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Nome da coluna",
"sqlObject.databaseEmpty": "Banco de dados {database} está vazio ou estrutura não foi carregada, pressione o botão Atualizar para recarregar a estrutura",
"sqlObject.loadingStructure": "Carregando estrutura do banco de dados",
"sqlObject.name": "Nome",
"sqlObject.newCollection": "Nova coleção/contêiner",
"sqlObject.rowCount": "Contagem de linhas",
"sqlObject.schemaName": "Schema",
"sqlObject.search.placeholder": "Pesquisar em tabelas, visões, procedimentos",
"sqlObject.searchBy": "Pesquisar por:",
"sqlObject.sizeBytes": "Tamanho (bytes)",
"sqlObject.sortBy": "Ordenar por:",
"sqlObject.tableComment": "Comentário da tabela",
"sqlObject.tableEngine": "Motor da tabela",
"sqlObject.tableViewProcedureName": "Nome da tabela/visão/procedimento",
@@ -902,6 +992,17 @@
"widget.keys": "Chaves",
"widget.pinned": "Fixados",
"widget.tablesViewsFunctions": "Tabelas, visões, funções",
"widgets.addNew": "Adicionar novo",
"widgets.administration": "Administração",
"widgets.archive": "Arquivo (dados tabulares salvos)",
"widgets.availableExtensions": "Extensões disponíveis",
"widgets.databaseConnections": "Conexões de banco de dados",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Favoritos e arquivos salvos",
"widgets.installedExtensions": "Extensões instaladas",
"widgets.managePlugins": "Gerenciar plugins",
"widgets.premiumPromo": "Promoção Premium",
"widgets.queryHistoryAndClosedTabs": "Histórico de consultas e abas fechadas",
"widgets.selectedCellDataDetailView": "Visualização detalhada de dados da célula selecionada",
"widgets.viewApplicationLogs": "Ver logs da aplicação"
}
}
+102 -1
View File
@@ -3,6 +3,11 @@
"app.loading_plugin": "Načítavam plugin {plugin} ...",
"app.preparingPlugins": "Príprava pluginov...",
"app.starting": "Spúšťam DbGate",
"cellDataWidget.autodetect": "Autodetekcia - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "Formát nie je zvolený",
"cellDataWidget.mustSelectOneCell": "Musí byť vybraná jedna bunka",
"cellDataWidget.noDataSelected": "Nie sú vybrané žiadne dáta",
"cellDataWidget.title": "Zobrazenie dát bunky",
"chart.detect": "Rozpoznať graf",
"chart.open": "Otvoriť graf",
"clipboard.SQLInsert": "SQL INSERT príkazy",
@@ -40,6 +45,10 @@
"columnEditor.isSparse": "Riedky",
"columnEditor.isUnsigned": "Bez znamienka",
"columnEditor.isZerofill": "Výplň nulami",
"columnLine.addReference": "Pridať referenciu",
"columnLine.sortAscending": "Zoradiť vzostupne",
"columnLine.sortDescending": "Zoradiť zostupne",
"columnLine.unsort": "Zrušiť zoradenie",
"columnsConstraintEditor.addNewColumn": "Pridať nový stĺpec",
"columnsConstraintEditor.chooseColumn": "Vybrať stĺpec",
"columnsConstraintEditor.selectColumn": "Vybrať stĺpec",
@@ -289,6 +298,7 @@
"commandModal.showKeyCombination": "Zobraziť požadovanú klávesovú kombináciu a stlačiť ENTER",
"common.addNew": "Pridať nový",
"common.advanced": "Pokročilé",
"common.allFields": "Všetky {field}",
"common.archive": "Archivovať (JSONL)",
"common.cancel": "Zrušiť",
"common.close": "Zavrieť",
@@ -315,6 +325,7 @@
"common.kill": "Ukončiť",
"common.loadingData": "Načítavanie dát",
"common.name": "Názov",
"common.newConnection": "Nové pripojenie",
"common.notSelectedOptional": "(nezvolené - voliteľné)",
"common.parameters": "Parametre",
"common.passwordEncrypted": "Heslo je zašifrované",
@@ -324,6 +335,7 @@
"common.queryEditor": "Editor SQL dotazov",
"common.refresh": "Obnoviť",
"common.remove": "Odstrániť",
"common.removeAll": "Odstrániť všetko",
"common.reset": "Resetovať",
"common.save": "Uložiť",
"common.saveAndNext": "Uložiť a pokračovať",
@@ -331,6 +343,7 @@
"common.schema": "Schéma",
"common.search": "Hledat",
"common.searchBy": "Hľadať podľa:",
"common.server": "Server",
"common.sqlGenerator": "SQL Generátor",
"common.table": "Tabuľka",
"common.testingConnection": "Testovanie pripojenia",
@@ -574,6 +587,12 @@
"dbObject.triggers": "Triggery",
"dbObject.truncateTable": "Orezanie tabuľky",
"dbObject.views": "Pohľady",
"designerTable.addReferences": "Pridať referencie",
"designerTable.changeColor": "Zmeniť farbu",
"designerTable.defineVirtualForeignKey": "Definovať virtuálny cudzí kľúč",
"designerTable.newAlias": "Nový alias",
"designerTable.removeTableAlias": "Odstrániť alias tabuľky",
"designerTable.setTableAlias": "Nastaviť alias tabuľky",
"error.driverNotFound": "Neplatné pripojenie k databáze, ovládač nenájdený",
"error.selectedCloudConnection": "Vybrané pripojenie je z DbGate cloudu",
"error.selectedNotCloudConnection": "Vybrané pripojenie nie je z DbGate cloudu",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "Súbory návrhu dotazu",
"file.sqlFiles": "SQL súbory",
"file.sqliteDatabase": "SQLite databáza",
"files.allSupportedFiles": "Všetky podporované súbory",
"files.favorites": "Obľúbené",
"files.openFile": "Otvoriť súbor",
"files.refreshFiles": "Obnoviť súbory",
"files.savedFiles": "Uložené súbory",
"files.searchSavedFiles": "Hľadať v uložených súboroch",
"files.sqlFiles": "SQL súbory",
"files.teamFiles": "Tímové súbory",
"files.uploadFile": "Nahrať súbor",
"filter.after": "Po...",
"filter.and": "A",
"filter.arrayIsEmpty": "Pole je prázdne",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "Referencovaný stĺpec - ",
"foreignKeyEditor.referencedTable": "Referencovaná tabuľka - ",
"foreignKeyEditor.tableNotSet": "(tabuľka nie je nastavená)",
"history.queryHistory": "História dotazov",
"history.recentlyClosedTabs": "Nedávno zatvorené karty",
"history.searchQueryHistory": "Hľadať v histórii dotazov",
"importExport.action": "Akcia",
"importExport.addWebUrl": "Pridať web URL",
"importExport.advancedConfiguration": "Pokročilá konfigurácia",
"importExport.archiveFolder": "Archívny priečinok",
"importExport.columns": "Stĺpce",
"importExport.createZipFileInArchive": "Vytvoriť ZIP súbor v archíve",
"importExport.currentArchive": "Aktuálny archív",
"importExport.currentDatabase": "Aktuálna DB",
"importExport.dragDropImportedFilesHere": "Pretiahnite importované súbory sem",
"importExport.exportToZipArchive": "Exportovať do ZIP archívu",
"importExport.exportToZipFile": "Exportovať do ZIP súboru",
"importExport.generateScript": "Generovať skript",
"importExport.importFromZipArchive": "Importovať zo ZIP archívu",
"importExport.importFromZipFile": "Importovať zo ZIP súboru (v archívnej zložke)",
"importExport.mapSourceTablesFiles": "Mapovať zdrojové tabuľky/súbory",
"importExport.messages": "Správy",
"importExport.newArchive": "Nový archív",
"importExport.outputFiles": "Výstupné súbory",
"importExport.preview": "Náhľad",
"importExport.processingImportExport": "Spracovanie importu/exportu ...",
"importExport.run": "Spustiť",
"importExport.schedule": "Plánovanie",
"importExport.source": "Zdroj",
"importExport.sourceConfiguration": "Konfigurácia zdroja",
"importExport.sourceFiles": "Zdrojové súbory",
"importExport.startVariableIndex": "Počiatočný index premennej",
"importExport.status": "Stav",
"importExport.stop": "Zastaviť",
"importExport.storageType": "Typ úložiska",
"importExport.tablesViewsCollections": "Tabuľky / pohľady / kolekcie",
"importExport.target": "Cieľ",
"importExport.targetConfiguration": "Konfigurácia cieľa",
"indexEditor.filteredIndexCondition": "Podmienka filtrovaného indexu",
"indexEditor.indexName": "Názov indexu",
"indexEditor.isUnique": "Je jedinečný index",
"logs.autoScroll": "Automatické rolovanie",
"logs.caller": "Volajúci:",
"logs.callerTab": "Volajúci",
"logs.chooseDate": "Vybrať dátum",
"logs.codeTab": "Kód",
"logs.connectionId": "ID pripojenia:",
"logs.connectionTab": "Pripojenie",
"logs.database": "Databáza:",
"logs.databaseTab": "Databáza",
"logs.date": "Dátum:",
"logs.dateTab": "Dátum",
"logs.details": "Detaily",
"logs.engine": "Engine:",
"logs.engineTab": "Engine",
"logs.loadingNextRows": "Načítavanie ďalších riadkov...",
"logs.message": "Správa:",
"logs.messageCode": "Kód správy:",
"logs.messageTab": "Správa",
"logs.name": "Názov:",
"logs.nameTab": "Názov",
"logs.noDataForSelectedDate": "Pre zvolený dátum nie sú k dispozícii žiadne dáta",
"logs.recentLogs": "Nedávne logy",
"logs.refresh": "Obnoviť",
"logs.time": "Čas:",
"logs.timeTab": "Čas",
"menu.edit": "Upraviť",
"menu.file": "Súbor",
"menu.help": "Pomoc",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "SQL Generátor nie je k dispozícii pre aktuálnu databázu",
"newObject.tableDescription": "Vytvoriť tabuľku v aktuálnej databáze",
"newObject.tableDisabled": "Vytvorenie tabuľky nie je k dispozícii pre aktuálnu databázu",
"plugins.searchExtensionsOnWeb": "Hľadať rozšírenia na webe",
"publicCloudWidget.onlyRelevantFilesListed": "Sú zobrazené iba súbory relevantné pre vaše pripojenia, platformu a edíciu DbGate. Najprv definujte pripojenia.",
"publicCloudWidget.refreshFiles": "Obnoviť súbory",
"publicCloudWidget.refreshList": "Obnoviť zoznam",
"publicCloudWidget.searchPublicFiles": "Hľadať verejné súbory",
"query.limitRows": "Obmedziť na {queryRowsLimit} riadkov",
"query.named": ":premenná",
"query.noParameters": "(žiadne parametre)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "Názov stĺpca",
"sqlObject.databaseEmpty": "Databáza {database} je prázdna alebo štruktúra nie je načítaná, stlačte tlačidlo Obnoviť pre opätovné načítanie štruktúry",
"sqlObject.loadingStructure": "Načítavanie štruktúry databázy",
"sqlObject.name": "Názov",
"sqlObject.newCollection": "Nová kolekcia/kontajner",
"sqlObject.rowCount": "Počet riadkov",
"sqlObject.schemaName": "Schéma",
"sqlObject.search.placeholder": "Hľadať v tabuľkách, pohľadoch, procedúrach",
"sqlObject.searchBy": "Hľadať podľa:",
"sqlObject.sizeBytes": "Veľkosť (bajty)",
"sqlObject.sortBy": "Zoradiť podľa:",
"sqlObject.tableComment": "Komentár tabuľky",
"sqlObject.tableEngine": "Engine tabuľky",
"sqlObject.tableViewProcedureName": "Názov tabuľky/pohľadu/procedúry",
@@ -902,6 +992,17 @@
"widget.keys": "Kľúče",
"widget.pinned": "Pripnuté",
"widget.tablesViewsFunctions": "Tabuľky, pohľady, funkcie",
"widgets.addNew": "Pridať nový",
"widgets.administration": "Administrácia",
"widgets.archive": "Archív (uložené tabuľkové dáta)",
"widgets.availableExtensions": "Dostupné rozšírenia",
"widgets.databaseConnections": "Databázové pripojenia",
"widgets.dbgateCloud": "DbGate Cloud",
"widgets.favoritesAndSavedFiles": "Obľúbené a uložené súbory",
"widgets.installedExtensions": "Nainštalované rozšírenia",
"widgets.managePlugins": "Spravovať pluginy",
"widgets.premiumPromo": "Premium promo",
"widgets.queryHistoryAndClosedTabs": "História dotazov a zatvorené karty",
"widgets.selectedCellDataDetailView": "Detailné zobrazenie dát vybranej bunky",
"widgets.viewApplicationLogs": "Zobraziť aplikačné logy"
}
}
+102 -1
View File
@@ -3,6 +3,11 @@
"app.loading_plugin": "正在加载插件 {plugin} ...",
"app.preparingPlugins": "正在准备插件 ...",
"app.starting": "正在启动 DbGate",
"cellDataWidget.autodetect": "自动检测 - {autoDetectTitle}",
"cellDataWidget.formatNotSelected": "未选择格式",
"cellDataWidget.mustSelectOneCell": "必须选择一个单元格",
"cellDataWidget.noDataSelected": "未选择数据",
"cellDataWidget.title": "单元格数据视图",
"chart.detect": "检测图表",
"chart.open": "打开图表",
"clipboard.SQLInsert": "SQL INSERT 语句",
@@ -40,6 +45,10 @@
"columnEditor.isSparse": "稀疏",
"columnEditor.isUnsigned": "无符号",
"columnEditor.isZerofill": "零填充",
"columnLine.addReference": "添加引用",
"columnLine.sortAscending": "升序排序",
"columnLine.sortDescending": "降序排序",
"columnLine.unsort": "取消排序",
"columnsConstraintEditor.addNewColumn": "添加新列",
"columnsConstraintEditor.chooseColumn": "选择列",
"columnsConstraintEditor.selectColumn": "选择列",
@@ -289,6 +298,7 @@
"commandModal.showKeyCombination": "显示所需的键盘组合并按回车键",
"common.addNew": "添加新项",
"common.advanced": "高级",
"common.allFields": "所有 {field}",
"common.archive": "归档 (JSONL)",
"common.cancel": "取消",
"common.close": "关闭",
@@ -315,6 +325,7 @@
"common.kill": "终止",
"common.loadingData": "正在加载数据",
"common.name": "名称",
"common.newConnection": "新建连接",
"common.notSelectedOptional": "(未选择 - 可选)",
"common.parameters": "参数",
"common.passwordEncrypted": "密码已加密",
@@ -324,6 +335,7 @@
"common.queryEditor": "SQL 查询编辑器",
"common.refresh": "刷新",
"common.remove": "移除",
"common.removeAll": "全部移除",
"common.reset": "重置",
"common.save": "保存",
"common.saveAndNext": "保存并下一个",
@@ -331,6 +343,7 @@
"common.schema": "模式",
"common.search": "搜索",
"common.searchBy": "搜索方式:",
"common.server": "服务器",
"common.sqlGenerator": "SQL 生成器",
"common.table": "表",
"common.testingConnection": "正在测试连接",
@@ -574,6 +587,12 @@
"dbObject.triggers": "触发器",
"dbObject.truncateTable": "截断表",
"dbObject.views": "视图",
"designerTable.addReferences": "添加引用",
"designerTable.changeColor": "更改颜色",
"designerTable.defineVirtualForeignKey": "定义虚拟外键",
"designerTable.newAlias": "新建别名",
"designerTable.removeTableAlias": "移除表别名",
"designerTable.setTableAlias": "设置表别名",
"error.driverNotFound": "无效的数据库连接,未找到驱动程序",
"error.selectedCloudConnection": "选定的连接来自DbGate云",
"error.selectedNotCloudConnection": "选定的连接不来自DbGate云",
@@ -588,6 +607,15 @@
"file.queryDesignerFiles": "查询设计器文件",
"file.sqlFiles": "SQL文件",
"file.sqliteDatabase": "SQLite数据库",
"files.allSupportedFiles": "所有支持的文件",
"files.favorites": "收藏",
"files.openFile": "打开文件",
"files.refreshFiles": "刷新文件",
"files.savedFiles": "已保存文件",
"files.searchSavedFiles": "搜索已保存文件",
"files.sqlFiles": "SQL 文件",
"files.teamFiles": "团队文件",
"files.uploadFile": "上传文件",
"filter.after": "之后...",
"filter.and": "且",
"filter.arrayIsEmpty": "数组为空",
@@ -669,16 +697,69 @@
"foreignKeyEditor.refColumn": "引用列 - ",
"foreignKeyEditor.referencedTable": "引用表",
"foreignKeyEditor.tableNotSet": "(未设置表)",
"history.queryHistory": "查询历史",
"history.recentlyClosedTabs": "最近关闭的标签页",
"history.searchQueryHistory": "搜索查询历史",
"importExport.action": "操作",
"importExport.addWebUrl": "添加 Web URL",
"importExport.advancedConfiguration": "高级配置",
"importExport.archiveFolder": "归档文件夹",
"importExport.columns": "列",
"importExport.createZipFileInArchive": "在存档中创建ZIP文件",
"importExport.currentArchive": "当前归档",
"importExport.currentDatabase": "当前数据库",
"importExport.dragDropImportedFilesHere": "将导入的文件拖放到此处",
"importExport.exportToZipArchive": "输出ZIP存档",
"importExport.exportToZipFile": "导出到ZIP文件",
"importExport.generateScript": "生成脚本",
"importExport.importFromZipArchive": "输入ZIP存档",
"importExport.importFromZipFile": "从ZIP文件导入(在存档文件夹中)",
"importExport.mapSourceTablesFiles": "映射源表/文件",
"importExport.messages": "消息",
"importExport.newArchive": "新建归档",
"importExport.outputFiles": "输出文件",
"importExport.preview": "预览",
"importExport.processingImportExport": "正在处理导入/导出 ...",
"importExport.run": "运行",
"importExport.schedule": "计划",
"importExport.source": "源",
"importExport.sourceConfiguration": "源配置",
"importExport.sourceFiles": "源文件",
"importExport.startVariableIndex": "起始变量索引",
"importExport.status": "状态",
"importExport.stop": "停止",
"importExport.storageType": "存储类型",
"importExport.tablesViewsCollections": "表 / 视图 / 集合",
"importExport.target": "目标",
"importExport.targetConfiguration": "目标配置",
"indexEditor.filteredIndexCondition": "过滤索引条件",
"indexEditor.indexName": "索引名称",
"indexEditor.isUnique": "是唯一索引",
"logs.autoScroll": "自动滚动",
"logs.caller": "调用方:",
"logs.callerTab": "调用方",
"logs.chooseDate": "选择日期",
"logs.codeTab": "代码",
"logs.connectionId": "连接 ID",
"logs.connectionTab": "连接",
"logs.database": "数据库:",
"logs.databaseTab": "数据库",
"logs.date": "日期:",
"logs.dateTab": "日期",
"logs.details": "详情",
"logs.engine": "引擎:",
"logs.engineTab": "引擎",
"logs.loadingNextRows": "正在加载下一批行...",
"logs.message": "消息:",
"logs.messageCode": "消息代码:",
"logs.messageTab": "消息",
"logs.name": "名称:",
"logs.nameTab": "名称",
"logs.noDataForSelectedDate": "所选日期无数据",
"logs.recentLogs": "最近日志",
"logs.refresh": "刷新",
"logs.time": "时间:",
"logs.timeTab": "时间",
"menu.edit": "编辑",
"menu.file": "文件",
"menu.help": "帮助",
@@ -703,6 +784,11 @@
"newObject.sqlGeneratorDisabled": "当前数据库不支持SQL生成器",
"newObject.tableDescription": "在当前数据库中创建表",
"newObject.tableDisabled": "当前数据库不支持创建表",
"plugins.searchExtensionsOnWeb": "在网页上搜索扩展",
"publicCloudWidget.onlyRelevantFilesListed": "仅列出与您的连接、平台和 DbGate 版本相关的文件。请先定义连接。",
"publicCloudWidget.refreshFiles": "刷新文件",
"publicCloudWidget.refreshList": "刷新列表",
"publicCloudWidget.searchPublicFiles": "搜索公共文件",
"query.limitRows": "限制 {queryRowsLimit} 行",
"query.named": ":variable",
"query.noParameters": "(无参数)",
@@ -819,10 +905,14 @@
"sqlObject.columnName": "列名称",
"sqlObject.databaseEmpty": "数据库 {database} 为空或结构未加载,请按刷新按钮重新加载结构",
"sqlObject.loadingStructure": "加载数据库结构",
"sqlObject.name": "名称",
"sqlObject.newCollection": "新集合/容器",
"sqlObject.rowCount": "行数",
"sqlObject.schemaName": "模式",
"sqlObject.search.placeholder": "在表、视图、存储过程中搜索",
"sqlObject.searchBy": "搜索条件:",
"sqlObject.sizeBytes": "大小(字节)",
"sqlObject.sortBy": "排序方式:",
"sqlObject.tableComment": "表注释",
"sqlObject.tableEngine": "表引擎",
"sqlObject.tableViewProcedureName": "表/视图/存储过程名称",
@@ -902,6 +992,17 @@
"widget.keys": "键",
"widget.pinned": "已固定",
"widget.tablesViewsFunctions": "表、视图、函数",
"widgets.addNew": "添加新项",
"widgets.administration": "管理",
"widgets.archive": "归档(已保存的表格数据)",
"widgets.availableExtensions": "可用扩展",
"widgets.databaseConnections": "数据库连接",
"widgets.dbgateCloud": "DbGate 云",
"widgets.favoritesAndSavedFiles": "收藏和已保存文件",
"widgets.installedExtensions": "已安装扩展",
"widgets.managePlugins": "管理插件",
"widgets.premiumPromo": "高级版推广",
"widgets.queryHistoryAndClosedTabs": "查询历史和已关闭标签页",
"widgets.selectedCellDataDetailView": "选定单元格数据详细视图",
"widgets.viewApplicationLogs": "查看应用程序日志"
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ checkout-and-merge-pro:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: f27a03d4aff5b00a009643df146a9c17bdbf7801
ref: 8df782559b84d6b59342c9488f3ca340074f35d6
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+18 -18
View File
@@ -49,26 +49,26 @@ jobs:
cd packages/tools
yarn test:ci
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: integration-tests/result.json
action-name: Integration tests
# - uses: tanmen/jest-reporter@v1
# if: always()
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# result-file: integration-tests/result.json
# action-name: Integration tests
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/filterparser/result.json
action-name: Filter parser test results
# - uses: tanmen/jest-reporter@v1
# if: always()
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# result-file: packages/filterparser/result.json
# action-name: Filter parser test results
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/datalib/result.json
action-name: Datalib (perspectives) test results
# - uses: tanmen/jest-reporter@v1
# if: always()
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# result-file: packages/datalib/result.json
# action-name: Datalib (perspectives) test results
services:
postgres-integr: