Merge branch 'master' into feature/postgresql-export-bytea

This commit is contained in:
Stela Augustinova
2025-11-13 13:44:11 +01:00
161 changed files with 5638 additions and 1627 deletions

View File

@@ -27,7 +27,7 @@
import SettingsListener from './utility/SettingsListener.svelte';
import { handleAuthOnStartup } from './clientAuth';
import { initializeAppUpdates } from './utility/appUpdate';
import { _t } from './translations';
import { _t, saveSelectedLanguageToCache } from './translations';
import { installCloudListeners } from './utility/cloudListeners';
export let isAdminPage = false;
@@ -61,6 +61,7 @@
initializeAppUpdates();
installCloudListeners();
refreshPublicCloudFiles();
saveSelectedLanguageToCache();
}
loadedApi = loadedApiValue;

View File

@@ -14,6 +14,7 @@
import ErrorInfo from './elements/ErrorInfo.svelte';
import { isOneOfPage } from './utility/pageDefs';
import { openWebLink } from './utility/simpleTools';
import FontIcon from './icons/FontIcon.svelte';
const config = useConfig();
const values = writable({ amoid: null, databaseServer: null });
@@ -22,17 +23,15 @@
$: trialDaysLeft = $config?.trialDaysLeft;
let errorMessage = '';
let expiredMessageSet = false;
$: if (isExpired && !expiredMessageSet) {
errorMessage = 'Your license is expired';
expiredMessageSet = true;
}
let isInsertingLicense = false;
$: trialButtonAvailable = !isExpired && trialDaysLeft == null;
// $: console.log('CONFIG', $config);
$: {
if ($config?.isLicenseValid) {
if ($config?.isLicenseValid && trialDaysLeft == null) {
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
}
}
@@ -41,83 +40,124 @@
<FormProviderCore {values}>
<SpecialPageLayout>
{#if getElectron() || ($config?.storageDatabase && hasPermission('admin/license'))}
<div class="heading">License</div>
<FormTextAreaField label="Enter your license key" name="licenseKey" rows={5} />
<div class="heading">Thank you for using DbGate!</div>
<div class="submit">
<FormSubmit
value="Save license"
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
const { licenseKey } = e.detail;
const resp = await apiCall('config/save-license-key', { licenseKey, tryToRenew: true });
if (resp?.status == 'ok') {
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = resp?.errorMessage || 'Error saving license key';
}
}}
/>
</div>
{#if isExpired}
<div class="infotext"><FontIcon icon="img warn" /> Your license has expired. Please insert new license.</div>
{:else if trialDaysLeft > 0}
<div class="infotext">
<FontIcon icon="img warn" /> Your trial period will expire in {trialDaysLeft} day{trialDaysLeft != 1
? 's'
: ''}.
</div>
{:else}
<div class="infotext">
<FontIcon icon="img info" /> Proceed by selecting a licensing option or providing your license key.
</div>
{/if}
{#if !isExpired && trialDaysLeft == null}
{#if isInsertingLicense}
<FormTextAreaField label="Enter your license key" name="licenseKey" rows={5} />
<div class="submit">
<div class="flex flex1">
<div class="col-6 flex">
<FormSubmit
value="Save license"
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
const { licenseKey } = e.detail;
const resp = await apiCall('config/save-license-key', { licenseKey, tryToRenew: true });
if (resp?.status == 'ok') {
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = resp?.errorMessage || 'Error saving license key';
}
}}
/>
</div>
<div class="col-6 flex">
<FormStyledButton
value="Cancel"
on:click={() => {
isInsertingLicense = false;
errorMessage = '';
}}
/>
</div>
</div>
</div>
{/if}
{#if !isInsertingLicense}
<div class="submit">
<FormStyledButton
value="Start 30-day trial"
on:click={async e => {
errorMessage = '';
const license = await apiCall('config/start-trial');
if (license?.status == 'ok') {
value="Insert license key"
on:click={() => {
isInsertingLicense = true;
}}
/>
</div>
{#if trialButtonAvailable}
<div class="submit">
<FormStyledButton
value="Start 30-day trial"
on:click={async e => {
errorMessage = '';
const license = await apiCall('config/start-trial');
if (license?.status == 'ok') {
sessionStorage.setItem('continueTrialConfirmed', '1');
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = license?.errorMessage || 'Error starting trial';
}
}}
/>
</div>
{/if}
{#if trialDaysLeft > 0}
<div class="submit">
<FormStyledButton
value={`Continue trial (${trialDaysLeft} days left)`}
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = license?.errorMessage || 'Error starting trial';
}
}}
/>
</div>
{/if}
}}
/>
</div>
{/if}
{#if trialDaysLeft > 0}
<div class="submit">
<FormStyledButton
value={`Continue trial (${trialDaysLeft} days left)`}
value="Purchase DbGate Premium"
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
// openWebLink(
// `https://auth.dbgate.eu/create-checkout-session-simple?source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
// openWebLink(
// `https://auth-proxy.dbgate.udolni.net/redirect-to-purchase?product=${getElectron() ? 'premium' : 'teram-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
openWebLink(
`https://auth.dbgate.eu/redirect-to-purchase?product=${getElectron() ? 'premium' : 'team-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
);
}}
/>
</div>
{/if}
<div class="submit">
<FormStyledButton
value="Purchase DbGate Premium"
on:click={async e => {
// openWebLink(
// `https://auth.dbgate.eu/create-checkout-session-simple?source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
// openWebLink(
// `https://auth-proxy.dbgate.udolni.net/redirect-to-purchase?product=${getElectron() ? 'premium' : 'teram-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
openWebLink(
`https://auth.dbgate.eu/redirect-to-purchase?product=${getElectron() ? 'premium' : 'team-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
);
}}
/>
</div>
{#if getElectron()}
<div class="submit">
<FormStyledButton
value="Exit"
on:click={e => {
getElectron().send('quit-app');
}}
/>
</div>
{#if getElectron()}
<div class="submit">
<FormStyledButton
value="Exit"
on:click={e => {
getElectron().send('quit-app');
}}
/>
</div>
{/if}
{/if}
{#if errorMessage}
@@ -125,8 +165,8 @@
{/if}
<div class="purchase-info">
For more info about DbGate licensing, you could visit <Link href="https://dbgate.eu/">dbgate.eu</Link> web or contact
us at <Link href="mailto:sales@dbgate.eu">sales@dbgate.eu</Link>
For more info about DbGate licensing, you could visit <Link href="https://dbgate.io/">dbgate.io</Link> web or contact
us at <Link href="mailto:sales@dbgate.io">sales@dbgate.io</Link>
</div>
{:else}
<ErrorInfo message="License for DbGate is not valid. Please contact administrator." />
@@ -141,6 +181,10 @@
font-size: xx-large;
}
.infotext {
margin: 1em;
}
.submit {
margin: var(--dim-large-form-margin);
display: flex;

View File

@@ -16,7 +16,7 @@
<div class="heading">Configuration error</div>
{#if $config?.checkedLicense?.status == 'error'}
<ErrorInfo
message={`Invalid license. Please contact sales@dbgate.eu for more details. ${$config?.checkedLicense?.error}`}
message={`Invalid license. Please contact sales@dbgate.io for more details. ${$config?.checkedLicense?.error || ''}`}
/>
{:else if $config?.configurationError}
<ErrorInfo message={$config?.configurationError} />

View File

@@ -8,6 +8,7 @@
import Link from '../elements/Link.svelte';
import { focusedConnectionOrDatabase } from '../stores';
import { tick } from 'svelte';
import { _val } from '../translations';
export let list;
export let module;
@@ -38,8 +39,19 @@
$: matcher = module.createMatcher && module.createMatcher(filter, passProps?.searchSettings);
$: listTranslated = (list || []).map(data => ({
...data,
group: data?.group && _val(data.group),
title: data?.title && _val(data.title),
description: data?.description && _val(data.description),
args: (data?.args || []).map(x => ({
...x,
label: x?.label && _val(x.label),
})),
}));
$: dataLabeled = _.compact(
(list || []).map(data => {
(listTranslated || []).map(data => {
const matchResult = matcher ? matcher(data) : true;
let isMatched = true;
@@ -102,7 +114,8 @@
$: groups = groupFunc ? extendGroups(_.groupBy(dataLabeled, 'group'), emptyGroupNames) : null;
$: listLimited = isExpandedBySearch && !expandLimited ? filtered.slice(0, filter.trim().length < 3 ? 1 : 3) : list;
$: listLimited =
isExpandedBySearch && !expandLimited ? filtered.slice(0, filter.trim().length < 3 ? 1 : 3) : listTranslated;
$: isListLimited = isExpandedBySearch && listLimited.length < filtered.length;
$: listMissingItems = isListLimited ? filtered.slice(listLimited.length) : [];

View File

@@ -279,7 +279,7 @@
showModal(InputTextModal, {
header: _t('connection.createDatabase', { defaultMessage: 'Create database' }),
value: 'newdb',
label: _t('connection.databaseName', { defaultMessage: 'Database name' }),
label: _t('connection.database', { defaultMessage: 'Database name' }),
onConfirm: name =>
apiCall('server-connections/create-database', {
conid: data._id,

View File

@@ -446,8 +446,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
driver?.databaseEngineTypes?.includes('document') && {
onClick: handleNewCollection,
text: _t('database.newCollection', {
defaultMessage: 'New {collectionLabel}',
values: { collectionLabel: driver?.collectionSingularLabel ?? 'collection/container' },
defaultMessage: 'New collection/container'
}),
},
hasPermission(`dbops/query`) &&
@@ -468,12 +467,14 @@ await dbgateApi.executeQuery(${JSON.stringify(
{ divider: true },
isSqlOrDoc &&
isProApp() &&
!connection.isReadOnly &&
hasPermission(`dbops/import`) && {
onClick: handleImport,
text: _t('database.import', { defaultMessage: 'Import' }),
},
isSqlOrDoc &&
isProApp() &&
hasPermission(`dbops/export`) && {
onClick: handleExport,
text: _t('database.export', { defaultMessage: 'Export' }),

View File

@@ -1,5 +1,6 @@
<script lang="ts" context="module">
import { copyTextToClipboard } from '../utility/clipboard';
import { _t, _val } from '../translations';
export const extractKey = ({ schemaName, pureName }) => (schemaName ? `${schemaName}.${pureName}` : pureName);
export const createMatcher =
@@ -69,13 +70,13 @@
function createScriptTemplatesSubmenu(objectTypeField) {
return {
label: 'SQL template',
label: _t('dbObject.sqlTemplate', { defaultMessage: 'SQL template' }),
submenu: getSupportedScriptTemplates(objectTypeField),
};
}
interface DbObjMenuItem {
label?: string;
label?: string | (() => string);
tab?: string;
forceNewTab?: boolean;
initialData?: any;
@@ -113,19 +114,19 @@
divider: true,
},
isProApp() && {
label: 'Design query',
label: _t('dbObject.designQuery', { defaultMessage: 'Design query' }),
isQueryDesigner: true,
requiresWriteAccess: true,
},
isProApp() && {
label: 'Design perspective query',
label: _t('dbObject.designPerspectiveQuery', { defaultMessage: 'Design perspective query' }),
tab: 'PerspectiveTab',
forceNewTab: true,
icon: 'img perspective',
},
createScriptTemplatesSubmenu('tables'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE TABLE',
@@ -154,33 +155,33 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop table',
label: _t('dbObject.dropTable', { defaultMessage: 'Drop table' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/rename') &&
!driver?.dialect.disableRenameTable && {
label: 'Rename table',
label: _t('dbObject.renameTable', { defaultMessage: 'Rename table' }),
isRename: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/truncate') && {
label: 'Truncate table',
label: _t('dbObject.truncateTable', { defaultMessage: 'Truncate table' }),
isTruncate: true,
requiresWriteAccess: true,
},
{
label: 'Copy table name',
label: _t('dbObject.copyTableName', { defaultMessage: 'Copy table name' }),
isCopyTableName: true,
requiresWriteAccess: false,
},
hasPermission('dbops/table/backup') && {
label: 'Create table backup',
label: _t('dbObject.createTableBackup', { defaultMessage: 'Create table backup' }),
isDuplicateTable: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/view') && {
label: 'Show diagram',
label: _t('dbObject.showDiagram', { defaultMessage: 'Show diagram' }),
isDiagram: true,
},
{
@@ -204,18 +205,18 @@
divider: true,
},
isProApp() && {
label: 'Design query',
label: _t('dbObject.designQuery', { defaultMessage: 'Design query' }),
isQueryDesigner: true,
},
isProApp() && {
label: 'Design perspective query',
label: _t('dbObject.designPerspectiveQuery', { defaultMessage: 'Design perspective query' }),
tab: 'PerspectiveTab',
forceNewTab: true,
icon: 'img perspective',
},
createScriptTemplatesSubmenu('views'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE VIEW',
@@ -235,12 +236,12 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop view',
label: _t('dbObject.dropView', { defaultMessage: 'Drop view' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/edit') && {
label: 'Rename view',
label: _t('dbObject.renameView', { defaultMessage: 'Rename view' }),
isRename: true,
requiresWriteAccess: true,
},
@@ -260,12 +261,12 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop view',
label: _t('dbObject.dropView', { defaultMessage: 'Drop view' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/edit') && {
label: 'Rename view',
label: _t('dbObject.renameView', { defaultMessage: 'Rename view' }),
isRename: true,
requiresWriteAccess: true,
},
@@ -273,12 +274,12 @@
divider: true,
},
{
label: 'Query designer',
label: _t('dbObject.queryDesigner', { defaultMessage: 'Query designer' }),
isQueryDesigner: true,
},
createScriptTemplatesSubmenu('matviews'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE MATERIALIZED VIEW',
@@ -306,7 +307,7 @@
case 'queries':
return [
{
label: 'Open data',
label: _t('dbObject.openData', { defaultMessage: 'Open data' }),
tab: 'QueryDataTab',
forceNewTab: true,
},
@@ -318,18 +319,18 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop procedure',
label: _t('dbObject.dropProcedure', { defaultMessage: 'Drop procedure' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/edit') && {
label: 'Rename procedure',
label: _t('dbObject.renameProcedure', { defaultMessage: 'Rename procedure' }),
isRename: true,
requiresWriteAccess: true,
},
createScriptTemplatesSubmenu('procedures'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE PROCEDURE',
@@ -352,7 +353,7 @@
return [
...defaultDatabaseObjectAppObjectActions['triggers'],
hasPermission('dbops/model/edit') && {
label: 'Drop trigger',
label: _t('dbObject.dropTrigger', { defaultMessage: 'Drop trigger' }),
isDrop: true,
requiresWriteAccess: true,
},
@@ -360,7 +361,7 @@
divider: true,
},
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE TRIGGER',
@@ -384,7 +385,7 @@
divider: true,
},
isProApp() && {
label: 'Design perspective query',
label: _t('dbObject.designPerspectiveQuery', { defaultMessage: 'Design perspective query' }),
tab: 'PerspectiveTab',
forceNewTab: true,
icon: 'img perspective',
@@ -395,17 +396,17 @@
functionName: 'tableReader',
},
hasPermission('dbops/model/edit') && {
label: `Drop ${driver?.collectionSingularLabel ?? 'collection/container'}`,
label: _t('dbObject.dropCollection', { defaultMessage: 'Drop collection/container'}),
isDropCollection: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/rename') && {
label: `Rename ${driver?.collectionSingularLabel ?? 'collection/container'}`,
label: _t('dbObject.renameCollection', { defaultMessage: 'Rename collection/container'}),
isRenameCollection: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/backup') && {
label: `Create ${driver?.collectionSingularLabel ?? 'collection/container'} backup`,
label: _t('dbObject.createCollectionBackup', { defaultMessage: 'Create collection/container backup'}),
isDuplicateCollection: true,
requiresWriteAccess: true,
},
@@ -418,7 +419,7 @@
const menu: DbObjMenuItem[] = [
...defaultDatabaseObjectAppObjectActions['schedulerEvents'],
hasPermission('dbops/model/edit') && {
label: 'Drop event',
label: _t('dbObject.dropEvent', { defaultMessage: 'Drop event' }),
isDrop: true,
requiresWriteAccess: true,
},
@@ -426,12 +427,12 @@
if (data?.status === 'ENABLED') {
menu.push({
label: 'Disable',
label: _t('dbObject.disable', { defaultMessage: 'Disable' }),
isDisableEvent: true,
});
} else {
menu.push({
label: 'Enable',
label: _t('dbObject.enable', { defaultMessage: 'Enable' }),
isEnableEvent: true,
});
}
@@ -441,7 +442,7 @@
divider: true,
},
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE SCHEDULER EVENT',
@@ -474,7 +475,7 @@
if (menu.isQueryDesigner) {
openNewTab(
{
title: 'Query #',
title: _t('dbObject.query', { defaultMessage: 'Query #' }),
icon: 'img query-design',
tabComponent: 'QueryDesignTab',
focused: true,
@@ -499,7 +500,7 @@
} else if (menu.isDiagram) {
openNewTab(
{
title: 'Diagram #',
title: _t('dbObject.diagram', { defaultMessage: 'Diagram #' }),
icon: 'img diagram',
tabComponent: 'DiagramTab',
props: {
@@ -589,7 +590,7 @@
});
} else if (menu.isDropCollection) {
showModal(ConfirmModal, {
message: `Really drop collection ${data.pureName}?`,
message: _t('dbObject.confirmDropCollection', { defaultMessage: 'Really drop collection {name}?', values: { name: data.pureName } }),
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
runOperationOnDatabase(dbid, {
@@ -603,8 +604,8 @@
} else if (menu.isRenameCollection) {
const driver = await getDriver();
showModal(InputTextModal, {
label: `New ${driver?.collectionSingularLabel ?? 'collection/container'} name`,
header: `Rename ${driver?.collectionSingularLabel ?? 'collection/container'}`,
label: _t('dbObject.newCollectionName', { defaultMessage: 'New collection/container name' }),
header: _t('dbObject.renameCollection', { defaultMessage: 'Rename collection/container' }),
value: data.pureName,
onConfirm: async newName => {
const dbid = _.pick(data, ['conid', 'database']);
@@ -620,7 +621,7 @@
const driver = await getDriver();
showModal(ConfirmModal, {
message: `Really create ${driver?.collectionSingularLabel ?? 'collection/container'} copy named ${newName}?`,
message: _t('dbObject.confirmCloneCollection', { defaultMessage: 'Really create collection/container copy named {name}?', values: { name: newName } }),
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
runOperationOnDatabase(dbid, {
@@ -718,7 +719,7 @@
const filteredSumenus = coreMenus.map(item => {
if (!item.submenu) {
return item;
return { ...item , label: _val(item.label)};
}
return {
...item,
@@ -768,7 +769,7 @@
openNewTab(
{
// title: getObjectTitle(connection, schemaName, pureName),
title: tabComponent ? getObjectTitle(connection, schemaName, pureName) : 'Query #',
title: tabComponent ? getObjectTitle(connection, schemaName, pureName) : _t('dbObject.query', { defaultMessage: 'Query #' }),
focused: tabComponent == null,
tooltip,
icon:

View File

@@ -1,3 +1,4 @@
import { __t } from '../translations';
export function matchDatabaseObjectAppObject(obj1, obj2) {
return (
obj1?.objectTypeField == obj2?.objectTypeField &&
@@ -11,12 +12,12 @@ export function matchDatabaseObjectAppObject(obj1, obj2) {
function getTableLikeActions(dataTab) {
return [
{
label: 'Open data',
label: __t('dbObject.openData', { defaultMessage: 'Open data' }),
tab: dataTab,
defaultActionId: 'openTable',
},
{
label: 'Open raw data',
label: __t('dbObject.openRawData', { defaultMessage: 'Open raw data' }),
tab: dataTab,
defaultActionId: 'openRawTable',
isRawMode: true,
@@ -33,13 +34,13 @@ function getTableLikeActions(dataTab) {
// defaultActionId: 'openForm',
// },
{
label: 'Open structure',
label: __t('dbObject.openStructure', { defaultMessage: 'Open structure' }),
tab: 'TableStructureTab',
icon: 'img table-structure',
defaultActionId: 'openStructure',
},
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -53,7 +54,7 @@ export const defaultDatabaseObjectAppObjectActions = {
matviews: getTableLikeActions('ViewDataTab'),
procedures: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -61,7 +62,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
functions: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -69,7 +70,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
triggers: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -77,12 +78,12 @@ export const defaultDatabaseObjectAppObjectActions = {
],
collections: [
{
label: 'Open data',
label: __t('dbObject.openData', { defaultMessage: 'Open data' }),
tab: 'CollectionDataTab',
defaultActionId: 'openTable',
},
{
label: 'Open JSON',
label: __t('dbObject.openJson', { defaultMessage: 'Open JSON' }),
tab: 'CollectionDataTab',
defaultActionId: 'openJson',
initialData: {
@@ -94,7 +95,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
schedulerEvents: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -102,7 +103,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
queries: [
{
label: 'Show query',
label: __t('dbObject.showQuery', { defaultMessage: 'Show query' }),
tab: 'QueryDataTab',
defaultActionId: 'showAppQuery',
icon: 'img app-query',

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import FontIcon from '../icons/FontIcon.svelte';
import { isProApp } from '../utility/proTools';
import { _t } from '../translations';
export let icon;
export let title;
@@ -21,7 +22,7 @@
data-testid={$$props['data-testid']}
title={disabled
? isProFeature && !isProApp()
? 'This feature is available only in DbGate Premium'
? _t('common.featurePremium', { defaultMessage: 'This feature is available only in DbGate Premium' })
: disabledMessage
: undefined}
>

View File

@@ -1,6 +1,6 @@
<script context="module">
function getCommandTitle(command) {
let res = command.text;
let res = _val(command.text);
if (command.keyText || command.keyTextFromGroup) {
res += ` (${formatKeyText(command.keyText || command.keyTextFromGroup)})`;
}
@@ -12,6 +12,8 @@
import { commandsCustomized } from '../stores';
import { formatKeyText } from '../utility/common';
import ToolStripButton from './ToolStripButton.svelte';
import _ from 'lodash';
import { _val } from '../translations';
export let command;
export let component = ToolStripButton;
@@ -32,6 +34,6 @@
{iconAfter}
{...$$restProps}
>
{buttonLabel || cmd.toolbarName || cmd.name}
{(_val(buttonLabel) || _val(cmd?.toolbarName) || _val(cmd?.name))}
</svelte:component>
{/if}

View File

@@ -23,7 +23,8 @@
import hasPermission from '../utility/hasPermission';
import ToolStripCommandButton from './ToolStripCommandButton.svelte';
import ToolStripDropDownButton from './ToolStripDropDownButton.svelte';
import _ from 'lodash';
import { _val } from '../translations';
export let quickExportHandlerRef = null;
export let command = 'sqlDataGrid.export';
export let label = 'Export';
@@ -39,7 +40,7 @@
{#if hasPermission('dbops/export')}
{#if quickExportHandlerRef}
<ToolStripDropDownButton menu={getExportMenu} {label} icon="icon export" />
<ToolStripDropDownButton menu={getExportMenu} label={_val(label)} icon="icon export" />
{:else}
<ToolStripCommandButton {command} />
{/if}

View File

@@ -1,9 +1,9 @@
<script context="module">
registerCommand({
id: 'commandPalette.show',
category: 'Command palette',
name: 'Show',
toolbarName: 'Command palette',
category: __t('command.commandPalette', { defaultMessage: 'Command palette' }),
name: __t('command.commandPalette.show', { defaultMessage: 'Show' }),
toolbarName: __t('command.commandPalette', { defaultMessage: 'Command palette' }),
toolbarOrder: 0,
keyText: 'F1',
toolbar: true,
@@ -15,9 +15,9 @@
registerCommand({
id: 'database.search',
category: 'Database',
toolbarName: 'Database search',
name: 'Search',
category: __t('command.database', { defaultMessage: 'Database' }),
toolbarName: __t('command.database.databaseSearch', { defaultMessage: 'Database search' }),
name: __t('command.database.search', { defaultMessage: 'Search' }),
keyText: isElectronAvailable() ? 'CtrlOrCommand+P' : 'F3',
onClick: () => visibleCommandPalette.set('database'),
testEnabled: () => getVisibleCommandPalette() != 'database',
@@ -81,6 +81,7 @@
import { getLocalStorage } from '../utility/storageCache';
import registerCommand from './registerCommand';
import { formatKeyText, switchCurrentDatabase } from '../utility/common';
import { _val, __t } from '../translations';
let domInput;
let filter = '';
@@ -117,7 +118,7 @@
: sortedComands
).filter(x => !x.isGroupCommand),
{
extract: x => x.text,
extract: x => _val(x.text),
pre: '<b>',
post: '</b>',
}

View File

@@ -4,11 +4,12 @@ import getElectron from '../utility/getElectron';
import registerCommand from './registerCommand';
import { apiCall } from '../utility/api';
import { switchCurrentDatabase } from '../utility/common';
import { __t } from '../translations';
registerCommand({
id: 'database.changeState',
category: 'Database',
name: 'Change status',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.changeStatus', { defaultMessage: 'Change status' }),
getSubCommands: () => {
const current = getCurrentDatabase();
if (!current) return [];

View File

@@ -3,6 +3,7 @@ import { recentDatabases, currentDatabase, getRecentDatabases } from '../stores'
import registerCommand from './registerCommand';
import { getConnectionLabel } from 'dbgate-tools';
import { switchCurrentDatabase } from '../utility/common';
import { __t } from '../translations';
currentDatabase.subscribe(value => {
if (!value) return;
@@ -24,8 +25,8 @@ function switchDatabaseCommand(db) {
registerCommand({
id: 'database.switch',
category: 'Database',
name: 'Change to recent',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.changeRecent', { defaultMessage: 'Change to recent' }),
menuName: 'Switch recent database',
keyText: 'CtrlOrCommand+D',
getSubCommands: () => getRecentDatabases().map(switchDatabaseCommand),

View File

@@ -1,5 +1,7 @@
import { commands } from '../stores';
import { invalidateCommandDefinitions } from './invalidateCommands';
import _ from 'lodash';
import { _val } from '../translations';
export interface SubCommand {
text: string;
@@ -8,10 +10,10 @@ export interface SubCommand {
export interface GlobalCommand {
id: string;
category: string; // null for group commands
category: string | (() => string); // null for group commands
isGroupCommand?: boolean;
name: string;
text?: string /* category: name */;
name: string | (() => string);
text?: string | (() => string);
keyText?: string;
keyTextFromGroup?: string; // automatically filled from group
group?: string;
@@ -23,11 +25,11 @@ export interface GlobalCommand {
toolbar?: boolean;
enabled?: boolean;
showDisabled?: boolean;
toolbarName?: string;
toolbarName?: string | (() => string);
menuName?: string;
toolbarOrder?: number;
disableHandleKeyText?: string;
isRelatedToTab?: boolean,
isRelatedToTab?: boolean;
systemCommand?: boolean;
}
@@ -41,7 +43,10 @@ export default function registerCommand(command: GlobalCommand) {
return {
...x,
[command.id]: {
text: `${command.category}: ${command.name}`,
text:
_.isFunction(command.category) || _.isFunction(command.name)
? () => `${_val(command.category)}: ${_val(command.name)}`
: `${command.category}: ${command.name}`,
...command,
enabled: !testEnabled,
},

View File

@@ -8,6 +8,7 @@ import {
getCloudSigninTokenHolder,
getExtensions,
getVisibleToolbar,
promoWidgetPreview,
visibleToolbar,
visibleWidgetSideBar,
} from '../stores';
@@ -50,6 +51,8 @@ import { isProApp } from '../utility/proTools';
import { openWebLink } from '../utility/simpleTools';
import { _t } from '../translations';
import ExportImportConnectionsModal from '../modals/ExportImportConnectionsModal.svelte';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { __t } from '../translations';
// function themeCommand(theme: ThemeDefinition) {
// return {
@@ -67,42 +70,42 @@ import ExportImportConnectionsModal from '../modals/ExportImportConnectionsModal
registerCommand({
id: 'theme.changeTheme',
category: 'Theme',
name: 'Change',
toolbarName: 'Change theme',
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' }),
// getSubCommands: () => get(extensions).themes.map(themeCommand),
});
registerCommand({
id: 'toolbar.show',
category: 'Toolbar',
name: 'Show',
category: __t('command.toolbar', { defaultMessage: 'Toolbar' }),
name: __t('command.toolbar.show', { defaultMessage: 'Show' }),
onClick: () => visibleToolbar.set(true),
testEnabled: () => !getVisibleToolbar(),
});
registerCommand({
id: 'toolbar.hide',
category: 'Toolbar',
name: 'Hide',
category: __t('command.toolbar', { defaultMessage: 'Toolbar' }),
name: __t('command.toolbar.hide', { defaultMessage: 'Hide' }),
onClick: () => visibleToolbar.set(false),
testEnabled: () => getVisibleToolbar(),
});
registerCommand({
id: 'about.show',
category: 'About',
name: 'Show',
toolbarName: 'About',
category: __t('command.about', { defaultMessage: 'About' }),
name: __t('command.about.show', { defaultMessage: 'Show' }),
toolbarName: __t('command.about.toolbar', { defaultMessage: 'About' }),
onClick: () => showModal(AboutModal),
});
registerCommand({
id: 'toggle.sidebar',
category: 'Sidebar',
name: 'Show',
toolbarName: 'Toggle sidebar',
category: __t('command.sidebar', { defaultMessage: 'Sidebar' }),
name: __t('command.sidebar.show', { defaultMessage: 'Show' }),
toolbarName: __t('command.sidebar.toggleToolbar', { defaultMessage: 'Toggle sidebar' }),
keyText: 'CtrlOrCommand+B',
onClick: () => visibleWidgetSideBar.update(x => !x),
});
@@ -111,10 +114,10 @@ registerCommand({
id: 'new.connection',
toolbar: true,
icon: 'icon new-connection',
toolbarName: 'Add connection',
category: 'New',
toolbarName: __t('command.new.connection', { defaultMessage: 'Add connection' }),
category: __t('command.new', { defaultMessage: 'New'}),
toolbarOrder: 1,
name: 'Connection',
name: __t('command.new.connection', { defaultMessage: 'Connection' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: () => {
openNewTab({
@@ -129,10 +132,10 @@ registerCommand({
id: 'new.connectionOnCloud',
toolbar: true,
icon: 'img cloud-connection',
toolbarName: 'Add connection',
category: 'New',
toolbarName: __t('command.new.connection', { defaultMessage: 'Add connection' }),
category: __t('command.new', { defaultMessage: 'New' }),
toolbarOrder: 1,
name: 'Connection on Cloud',
name: __t('command.new.connectionCloud', { defaultMessage: 'Connection on Cloud' }),
testEnabled: () =>
!getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase && !!getCloudSigninTokenHolder(),
onClick: () => {
@@ -151,16 +154,16 @@ registerCommand({
id: 'new.connection.folder',
toolbar: true,
icon: 'icon add-folder',
toolbarName: 'Add connection folder',
category: 'New',
toolbarName: __t('command.new.connectionFolderToolbar', { defaultMessage: 'Add connection folder' }),
category: __t('command.new', { defaultMessage: 'New' }),
toolbarOrder: 1,
name: 'Connection folder',
name: __t('command.new.connectionFolder', { defaultMessage: 'Connection folder' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal,
onClick: () => {
showModal(InputTextModal, {
value: '',
label: 'New connection folder name',
header: 'Create connection folder',
label: _t('connection.createNewFolderName', { defaultMessage: 'New connection folder name' }),
header: _t('connection.createNewFolder', { defaultMessage: 'Create connection folder' }),
onConfirm: async folder => {
emptyConnectionGroupNames.update(names => {
if (!folder) return names;
@@ -174,21 +177,21 @@ registerCommand({
registerCommand({
id: 'new.query',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon file',
toolbar: true,
toolbarOrder: 2,
name: 'Query',
toolbarName: 'New query',
name: __t('command.new.query', { defaultMessage: 'Query' }),
toolbarName: __t('command.new.queryToolbar', { defaultMessage: 'New query' }),
keyText: 'CtrlOrCommand+T',
onClick: () => newQuery(),
});
registerCommand({
id: 'new.shell',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img shell',
name: 'JavaScript Shell',
name: __t('command.new.shell', { defaultMessage: 'JavaScript Shell' }),
menuName: 'New JavaScript shell',
onClick: () => {
openNewTab({
@@ -202,9 +205,9 @@ registerCommand({
if (isProApp()) {
registerCommand({
id: 'new.queryDesign',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img query-design',
name: 'Query design',
name: __t('command.new.queryDesign', { defaultMessage: 'Query design' }),
menuName: 'New query design',
onClick: () => newQueryDesign(),
testEnabled: () =>
@@ -216,9 +219,9 @@ if (isProApp()) {
if (isProApp()) {
registerCommand({
id: 'new.modelTransform',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img transform',
name: 'Model transform',
name: __t('command.new.modelTransform', { defaultMessage: 'Model transform' }),
menuName: 'New model transform',
onClick: () => {
openNewTab(
@@ -260,9 +263,9 @@ if (isProApp()) {
if (isProApp()) {
registerCommand({
id: 'new.perspective',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img perspective',
name: 'Perspective',
name: __t('command.new.perspective', { defaultMessage: 'Perspective' }),
menuName: 'New perspective',
onClick: () => newPerspective(),
});
@@ -271,9 +274,9 @@ if (isProApp()) {
if (isProApp()) {
registerCommand({
id: 'new.application',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img app',
name: 'Application',
name: __t('command.new.application', { defaultMessage: 'Application' }),
menuName: 'New application',
onClick: () => {
openNewTab({
@@ -287,9 +290,9 @@ if (isProApp()) {
registerCommand({
id: 'new.diagram',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img diagram',
name: 'ER Diagram',
name: __t('command.new.diagram', { defaultMessage: 'ER Diagram' }),
menuName: 'New ER diagram',
testEnabled: () =>
getCurrentDatabase() &&
@@ -299,9 +302,9 @@ registerCommand({
registerCommand({
id: 'new.archiveFolder',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img archive',
name: 'Archive folder',
name: __t('command.new.archiveFolder', { defaultMessage: 'Archive folder' }),
onClick: () => {
showModal(InputTextModal, {
value: '',
@@ -333,11 +336,11 @@ registerCommand({
registerCommand({
id: 'new.table',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon table',
name: 'Table',
name: __t('command.new.table', { defaultMessage: 'Table' }),
toolbar: true,
toolbarName: 'New table',
toolbarName: __t('command.new.tableToolbar', { defaultMessage: 'New table' }),
testEnabled: () => {
if (!hasPermission('dbops/model/edit')) return false;
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
@@ -353,11 +356,11 @@ registerCommand({
registerCommand({
id: 'new.collection',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon table',
name: 'Collection',
name: __t('command.new.collection', { defaultMessage: 'Collection' }),
toolbar: true,
toolbarName: 'New collection/container',
toolbarName: __t('command.new.collectionToolbar', { defaultMessage: 'New collection/container' }),
testEnabled: () => {
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
return !!get(currentDatabase) && driver?.databaseEngineTypes?.includes('document');
@@ -379,9 +382,9 @@ registerCommand({
registerCommand({
id: 'new.markdown',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img markdown',
name: 'Markdown page',
name: __t('command.new.markdown', { defaultMessage: 'Markdown page' }),
onClick: () => {
openNewTab({
title: 'Page #',
@@ -394,9 +397,9 @@ registerCommand({
if (isProApp()) {
registerCommand({
id: 'new.modelCompare',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon compare',
name: 'Compare DB',
name: __t('command.new.modelCompare', { defaultMessage: 'Compare DB' }),
toolbar: true,
onClick: () => {
openNewTab({
@@ -410,9 +413,9 @@ if (isProApp()) {
registerCommand({
id: 'new.jsonl',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img archive',
name: 'JSON Lines',
name: __t('command.new.jsonl', { defaultMessage: 'JSON Lines' }),
menuName: 'New JSON lines file',
onClick: () => {
openNewTab(
@@ -430,9 +433,9 @@ registerCommand({
registerCommand({
id: 'new.sqliteDatabase',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img sqlite-database',
name: 'SQLite database',
name: __t('command.new.sqliteDatabase', { defaultMessage: 'SQLite database' }),
menuName: _t('command.new.sqliteDatabase', { defaultMessage: 'New SQLite database' }),
onClick: () => {
showModal(InputTextModal, {
@@ -450,9 +453,9 @@ registerCommand({
registerCommand({
id: 'new.duckdbDatabase',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img sqlite-database',
name: 'DuckDB database',
name: __t('command.new.duckdbDatabase', { defaultMessage: 'DuckDB database' }),
menuName: _t('command.new.duckdbDatabase', { defaultMessage: 'New DuckDB database' }),
onClick: () => {
showModal(InputTextModal, {
@@ -470,8 +473,8 @@ registerCommand({
registerCommand({
id: 'tabs.changelog',
category: 'Tabs',
name: 'Changelog',
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.changelog', { defaultMessage: 'Changelog' }),
onClick: () => {
openNewTab({
title: 'ChangeLog',
@@ -486,7 +489,7 @@ registerCommand({
id: 'group.save',
category: null,
isGroupCommand: true,
name: 'Save',
name: __t('command.save', { defaultMessage: 'Save' }),
keyText: 'CtrlOrCommand+S',
group: 'save',
});
@@ -495,7 +498,7 @@ registerCommand({
id: 'group.saveAs',
category: null,
isGroupCommand: true,
name: 'Save As',
name: __t('command.saveAs', { defaultMessage: 'Save As' }),
keyText: 'CtrlOrCommand+Shift+S',
group: 'saveAs',
});
@@ -504,7 +507,7 @@ registerCommand({
id: 'group.undo',
category: null,
isGroupCommand: true,
name: 'Undo',
name: __t('command.undo', { defaultMessage: 'Undo' }),
keyText: 'CtrlOrCommand+Z',
group: 'undo',
});
@@ -513,15 +516,15 @@ registerCommand({
id: 'group.redo',
category: null,
isGroupCommand: true,
name: 'Redo',
name: __t('command.redo', { defaultMessage: 'Redo' }),
keyText: 'CtrlOrCommand+Y',
group: 'redo',
});
registerCommand({
id: 'file.open',
category: 'File',
name: 'Open',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.open', { defaultMessage: 'Open' }),
keyText: 'CtrlOrCommand+O',
testEnabled: () => getElectron() != null,
onClick: openElectronFile,
@@ -529,36 +532,36 @@ registerCommand({
registerCommand({
id: 'file.openArchive',
category: 'File',
name: 'Open DB Model/Archive',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.openArchive', { defaultMessage: 'Open DB Model/Archive' }),
testEnabled: () => getElectron() != null,
onClick: openArchiveFolder,
});
registerCommand({
id: 'folder.showLogs',
category: 'Folder',
name: 'Open logs',
category: __t('command.folder', { defaultMessage: 'Folder' }),
name: __t('command.folder.openLogs', { defaultMessage: 'Open logs' }),
testEnabled: () => getElectron() != null,
onClick: () => electron.showItemInFolder(getCurrentConfig().logsFilePath),
});
registerCommand({
id: 'folder.showData',
category: 'Folder',
name: 'Open data folder',
category: __t('command.folder', { defaultMessage: 'Folder' }),
name: __t('command.folder.openData', { defaultMessage: 'Open data folder' }),
testEnabled: () => getElectron() != null,
onClick: () => electron.showItemInFolder(getCurrentConfig().connectionsFilePath),
});
registerCommand({
id: 'app.resetSettings',
category: 'File',
name: 'Reset layout data & settings',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.resetLayout', { defaultMessage: 'Reset layout data & settings' }),
testEnabled: () => true,
onClick: () => {
showModal(ConfirmModal, {
message: `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();
@@ -575,8 +578,8 @@ registerCommand({
registerCommand({
id: 'app.exportConnections',
category: 'Settings',
name: 'Export connections',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.exportConnections', { defaultMessage: 'Export connections' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: () => {
showModal(ExportImportConnectionsModal, {
@@ -587,8 +590,8 @@ registerCommand({
registerCommand({
id: 'app.importConnections',
category: 'Settings',
name: 'Import connections',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.importConnections', { defaultMessage: 'Import connections' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: async () => {
const files = await electron.showOpenDialog({
@@ -613,8 +616,8 @@ registerCommand({
registerCommand({
id: 'file.import',
category: 'File',
name: 'Import data',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.import', { defaultMessage: 'Import data' }),
toolbar: true,
icon: 'icon import',
onClick: () =>
@@ -634,8 +637,8 @@ registerCommand({
registerCommand({
id: 'view.reset',
category: 'View',
name: 'Reset view',
category: __t('command.view', { defaultMessage: 'View' }),
name: __t('command.view.reset', { defaultMessage: 'Reset view' }),
onClick: () => {
const keys = [
'leftPanelWidth',
@@ -662,14 +665,14 @@ registerCommand({
'currentArchive',
];
for (const key of keys) removeLocalStorage(key);
showSnackbarSuccess('Restart DbGate (or reload on web) for applying changes');
showSnackbarSuccess(_t('command.view.restart', { defaultMessage: 'Restart DbGate (or reload on web) for applying changes' }));
},
});
registerCommand({
id: 'sql.generator',
category: 'SQL',
name: 'SQL Generator',
category: __t('command.sql', { defaultMessage: 'SQL' }),
name: __t('command.sql.generator', { defaultMessage: 'SQL Generator' }),
toolbar: true,
icon: 'icon sql-generator',
testEnabled: () =>
@@ -685,11 +688,11 @@ registerCommand({
registerCommand({
id: 'database.export',
category: 'Database',
name: 'Export database',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.export', { defaultMessage: 'Export database' }),
toolbar: true,
icon: 'icon export',
testEnabled: () => getCurrentDatabase() != null && hasPermission(`dbops/export`),
testEnabled: () => getCurrentDatabase() != null && hasPermission(`dbops/export`) && isProApp(),
onClick: () => {
openImportExportTab({
targetStorageType: getDefaultFileFormat(getExtensions()).storageType,
@@ -703,8 +706,8 @@ registerCommand({
if (isProApp()) {
registerCommand({
id: 'database.compare',
category: 'Database',
name: 'Compare databases',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.compare', { defaultMessage: 'Compare databases' }),
toolbar: true,
icon: 'icon compare',
testEnabled: () =>
@@ -736,8 +739,8 @@ if (isProApp()) {
registerCommand({
id: 'database.chat',
category: 'Database',
name: 'Database chat',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.chat', { defaultMessage: 'Database chat' }),
toolbar: true,
icon: 'icon ai',
testEnabled: () =>
@@ -761,11 +764,11 @@ if (isProApp()) {
if (hasPermission('settings/change')) {
registerCommand({
id: 'settings.commands',
category: 'Settings',
name: 'Keyboard shortcuts',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }),
onClick: () => {
openNewTab({
title: 'Keyboard Shortcuts',
title: _t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }),
icon: 'icon keyboard',
tabComponent: 'CommandListTab',
props: {},
@@ -776,9 +779,9 @@ if (hasPermission('settings/change')) {
registerCommand({
id: 'settings.show',
category: 'Settings',
name: 'Change',
toolbarName: 'Settings',
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'),
});
@@ -786,8 +789,8 @@ if (hasPermission('settings/change')) {
registerCommand({
id: 'cloud.logout',
category: 'Cloud',
name: 'Logout',
category: __t('command.cloud', { defaultMessage: 'Cloud' }),
name: __t('command.cloud.logout', { defaultMessage: 'Logout' }),
onClick: () => {
cloudSigninTokenHolder.set(null);
},
@@ -795,8 +798,8 @@ registerCommand({
registerCommand({
id: 'file.exit',
category: 'File',
name: isMac() ? 'Quit' : 'Exit',
category: __t('command.file', { defaultMessage: 'File' }),
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'),
@@ -804,16 +807,16 @@ registerCommand({
registerCommand({
id: 'app.logout',
category: 'App',
name: 'Logout',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.logout', { defaultMessage: 'Logout' }),
testEnabled: () => getCurrentConfig()?.isUserLoggedIn,
onClick: doLogout,
});
registerCommand({
id: 'app.loggedUserCommands',
category: 'App',
name: 'Logged user',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.loggedUser', { defaultMessage: 'Logged user' }),
getSubCommands: () => {
const config = getCurrentConfig();
if (!config) return [];
@@ -830,16 +833,16 @@ registerCommand({
registerCommand({
id: 'app.disconnect',
category: 'App',
name: 'Disconnect',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.disconnect', { defaultMessage: 'Disconnect' }),
testEnabled: () => getCurrentConfig()?.singleConnection != null && !getCurrentConfig()?.isUserLoggedIn,
onClick: () => disconnectServerConnection(getCurrentConfig()?.singleConnection?._id),
});
registerCommand({
id: 'file.checkForUpdates',
category: 'App',
name: 'Check for updates',
id: 'app.checkForUpdates',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.checkForUpdates', { defaultMessage: 'Check for updates' }),
// testEnabled: () => true,
testEnabled: () => getAppUpdaterActive(),
onClick: () => getElectron().send('check-for-updates'),
@@ -865,7 +868,7 @@ export function registerFileCommands({
id: idPrefix + '.save',
group: 'save',
category,
name: 'Save',
name: __t('command.save', { defaultMessage: 'Save' }),
// keyText: 'CtrlOrCommand+S',
icon: 'icon save',
toolbar: true,
@@ -877,14 +880,14 @@ export function registerFileCommands({
id: idPrefix + '.saveAs',
group: 'saveAs',
category,
name: 'Save As',
name: __t('command.saveAs', { defaultMessage: 'Save As' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save-as', folder, format, fileExtension),
});
registerCommand({
id: idPrefix + '.saveToDisk',
category,
name: 'Save to disk',
name: __t('command.saveToDisk', { defaultMessage: 'Save to disk' }),
testEnabled: () => getCurrentEditor() != null && getElectron() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save-to-disk', folder, format, fileExtension),
});
@@ -894,7 +897,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.execute',
category,
name: 'Execute',
name: __t('command.execute', { defaultMessage: 'Execute' }),
icon: 'icon run',
toolbar: true,
isRelatedToTab: true,
@@ -908,7 +911,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.kill',
category,
name: 'Kill',
name: __t('command.kill', { defaultMessage: 'Kill' }),
icon: 'icon close',
toolbar: true,
isRelatedToTab: true,
@@ -921,7 +924,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.toggleComment',
category,
name: 'Toggle comment',
name: __t('command.toggleComment', { defaultMessage: 'Toggle comment' }),
keyText: 'CtrlOrCommand+/',
disableHandleKeyText: 'CtrlOrCommand+/',
testEnabled: () => getCurrentEditor() != null,
@@ -933,7 +936,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.copy',
category,
name: 'Copy',
name: __t('command.copy', { defaultMessage: 'Copy' }),
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().copy(),
@@ -941,7 +944,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.paste',
category,
name: 'Paste',
name: __t('command.paste', { defaultMessage: 'Paste' }),
disableHandleKeyText: 'CtrlOrCommand+V',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().paste(),
@@ -952,7 +955,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.find',
category,
name: 'Find',
name: __t('command.find', { defaultMessage: 'Find' }),
keyText: 'CtrlOrCommand+F',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().find(),
@@ -961,7 +964,7 @@ export function registerFileCommands({
id: idPrefix + '.replace',
category,
keyText: isMac() ? 'Alt+Command+F' : 'CtrlOrCommand+H',
name: 'Replace',
name: __t('command.replace', { defaultMessage: 'Replace' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().replace(),
});
@@ -970,7 +973,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.undo',
category,
name: 'Undo',
name: __t('command.undo', { defaultMessage: 'Undo' }),
group: 'undo',
icon: 'icon undo',
testEnabled: () => getCurrentEditor()?.canUndo(),
@@ -980,7 +983,7 @@ export function registerFileCommands({
id: idPrefix + '.redo',
category,
group: 'redo',
name: 'Redo',
name: __t('command.redo', { defaultMessage: 'Redo' }),
icon: 'icon redo',
testEnabled: () => getCurrentEditor()?.canRedo(),
onClick: () => getCurrentEditor().redo(),
@@ -990,24 +993,24 @@ export function registerFileCommands({
registerCommand({
id: 'app.minimize',
category: 'Application',
name: 'Minimize',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.minimize', { defaultMessage: 'Minimize' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'minimize'),
});
registerCommand({
id: 'app.maximize',
category: 'Application',
name: 'Maximize',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.maximize', { defaultMessage: 'Maximize' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'maximize'),
});
registerCommand({
id: 'app.toggleFullScreen',
category: 'Application',
name: 'Toggle full screen',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.toggleFullScreen', { defaultMessage: 'Toggle full screen' }),
keyText: 'F11',
testEnabled: () => getElectron() != null,
onClick: async () => {
@@ -1021,45 +1024,45 @@ registerCommand({
registerCommand({
id: 'app.toggleDevTools',
category: 'Application',
name: 'Toggle Dev Tools',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.toggleDevTools', { defaultMessage: 'Toggle Dev Tools' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'devtools'),
});
registerCommand({
id: 'app.reload',
category: 'Application',
name: 'Reload',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.reload', { defaultMessage: 'Reload' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'reload'),
});
registerCommand({
id: 'app.openDocs',
category: 'Application',
name: 'Documentation',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.documentation', { defaultMessage: 'Documentation' }),
onClick: () => openWebLink('https://docs.dbgate.io/'),
});
registerCommand({
id: 'app.openWeb',
category: 'Application',
name: 'DbGate web',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.web', { defaultMessage: 'DbGate web' }),
onClick: () => openWebLink('https://www.dbgate.io/'),
});
registerCommand({
id: 'app.openIssue',
category: 'Application',
name: 'Report problem or feature request',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.openIssue', { defaultMessage: 'Report problem or feature request' }),
onClick: () => openWebLink('https://github.com/dbgate/dbgate/issues/new'),
});
registerCommand({
id: 'app.openSponsoring',
category: 'Application',
name: 'Become sponsor',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.becomeSponsor', { defaultMessage: 'Become sponsor' }),
testEnabled: () => !isProApp(),
onClick: () => openWebLink('https://opencollective.com/dbgate'),
});
@@ -1073,8 +1076,8 @@ registerCommand({
registerCommand({
id: 'app.zoomIn',
category: 'Application',
name: 'Zoom in',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.zoomIn', { defaultMessage: 'Zoom in' }),
keyText: 'CtrlOrCommand+=',
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'zoomin'),
@@ -1082,8 +1085,8 @@ registerCommand({
registerCommand({
id: 'app.zoomOut',
category: 'Application',
name: 'Zoom out',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.zoomOut', { defaultMessage: 'Zoom out' }),
keyText: 'CtrlOrCommand+-',
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'zoomout'),
@@ -1091,16 +1094,16 @@ registerCommand({
registerCommand({
id: 'app.zoomReset',
category: 'Application',
name: 'Reset zoom',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.zoomReset', { defaultMessage: 'Reset zoom' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'zoomreset'),
});
registerCommand({
id: 'edit.undo',
category: 'Edit',
name: 'Undo',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.undo', { defaultMessage: 'Undo' }),
keyText: 'CtrlOrCommand+Z',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1109,8 +1112,8 @@ registerCommand({
registerCommand({
id: 'edit.redo',
category: 'Edit',
name: 'Redo',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.redo', { defaultMessage: 'Redo' }),
systemCommand: true,
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'redo'),
@@ -1118,8 +1121,8 @@ registerCommand({
registerCommand({
id: 'edit.cut',
category: 'Edit',
name: 'Cut',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.cut', { defaultMessage: 'Cut' }),
keyText: 'CtrlOrCommand+X',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1128,8 +1131,8 @@ registerCommand({
registerCommand({
id: 'edit.copy',
category: 'Edit',
name: 'Copy',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.copy', { defaultMessage: 'Copy' }),
keyText: 'CtrlOrCommand+C',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1138,8 +1141,8 @@ registerCommand({
registerCommand({
id: 'edit.paste',
category: 'Edit',
name: 'Paste',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.paste', { defaultMessage: 'Paste' }),
keyText: 'CtrlOrCommand+V',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1148,8 +1151,8 @@ registerCommand({
registerCommand({
id: 'edit.selectAll',
category: 'Edit',
name: 'Select All',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.selectAll', { defaultMessage: 'Select All' }),
keyText: 'CtrlOrCommand+A',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1158,12 +1161,47 @@ registerCommand({
registerCommand({
id: 'app.unsetCurrentDatabase',
category: 'Application',
name: 'Unset current database',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.unsetCurrentDatabase', { defaultMessage: 'Unset current database' }),
testEnabled: () => getCurrentDatabase() != null,
onClick: () => currentDatabase.set(null),
});
let loadedCampaignList = [];
registerCommand({
id: 'internal.loadCampaigns',
category: __t('command.internal', { defaultMessage: 'Internal' }),
name: __t('command.internal.loadCampaigns', { defaultMessage: 'Load campaign list' }),
testEnabled: () => getBoolSettingsValue('internal.showCampaigns', false),
onClick: async () => {
const resp = await apiCall('cloud/promo-widget-list', {});
loadedCampaignList = resp;
},
});
registerCommand({
id: 'internal.showCampaigns',
category: __t('command.internal', { defaultMessage: 'Internal' }),
name: __t('command.internal.showCampaigns', { defaultMessage: 'Show campaigns' }),
testEnabled: () => getBoolSettingsValue('internal.showCampaigns', false) && loadedCampaignList?.length > 0,
getSubCommands: () => {
return loadedCampaignList.map(campaign => ({
text: `${campaign.campaignName} (${campaign.countries || 'Global'}) - #${campaign.quantileRank ?? '*'}/${
campaign.quantileGroupCount ?? '*'
} - ${campaign.variantIdentifier}`,
onClick: async () => {
promoWidgetPreview.set(
await apiCall('cloud/promo-widget-preview', {
campaign: campaign.campaignIdentifier,
variant: campaign.variantIdentifier,
})
);
},
}));
},
});
const electron = getElectron();
if (electron) {
electron.addEventListener('run-command', (e, commandId) => runCommand(commandId));

View File

@@ -3,16 +3,16 @@
registerCommand({
id: 'collectionDataGrid.openQuery',
category: 'Data grid',
name: 'Open query',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.openQuery', { defaultMessage: 'Open query' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().openQuery(),
});
registerCommand({
id: 'collectionDataGrid.export',
category: 'Data grid',
name: 'Export',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.export', { defaultMessage: 'Export' }),
keyText: 'CtrlOrCommand+E',
icon: 'icon export',
testEnabled: () => getCurrentEditor() != null,
@@ -140,6 +140,7 @@
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
import { mongoFilterBehaviour, standardFilterBehaviours } from 'dbgate-tools';
import { openImportExportTab } from '../utility/importExportTools';
import { __t } from '../translations';
export let conid;
export let display;

View File

@@ -12,6 +12,7 @@
import { showModal } from '../modals/modalTools';
import DefineDictionaryDescriptionModal from '../modals/DefineDictionaryDescriptionModal.svelte';
import { sleep } from '../utility/common';
import { isProApp } from '../utility/proTools';
export let column;
export let conid = undefined;
@@ -72,29 +73,35 @@
column.foreignKey && [{ divider: true }, { onClick: openReferencedTable, text: column.foreignKey.refTableName }],
setGrouping && { divider: true },
setGrouping && { onClick: () => setGrouping('GROUP'), text: 'Group by' },
setGrouping && { onClick: () => setGrouping('MAX'), text: 'MAX' },
setGrouping && { onClick: () => setGrouping('MIN'), text: 'MIN' },
setGrouping && { onClick: () => setGrouping('SUM'), text: 'SUM' },
setGrouping && { onClick: () => setGrouping('AVG'), text: 'AVG' },
setGrouping && { onClick: () => setGrouping('COUNT'), text: 'COUNT' },
setGrouping && { onClick: () => setGrouping('COUNT DISTINCT'), text: 'COUNT DISTINCT' },
isProApp() &&
setGrouping && [
{ divider: true },
{ onClick: () => setGrouping('GROUP'), text: 'Group by' },
{ onClick: () => setGrouping('MAX'), text: 'MAX' },
{ onClick: () => setGrouping('MIN'), text: 'MIN' },
{ onClick: () => setGrouping('SUM'), text: 'SUM' },
{ onClick: () => setGrouping('AVG'), text: 'AVG' },
{ onClick: () => setGrouping('COUNT'), text: 'COUNT' },
{ onClick: () => setGrouping('COUNT DISTINCT'), text: 'COUNT DISTINCT' },
],
isTypeDateTime(column.dataType) && [
{ divider: true },
{ onClick: () => setGrouping('GROUP:YEAR'), text: 'Group by YEAR' },
{ onClick: () => setGrouping('GROUP:MONTH'), text: 'Group by MONTH' },
{ onClick: () => setGrouping('GROUP:DAY'), text: 'Group by DAY' },
],
isProApp() &&
isTypeDateTime(column.dataType) && [
{ divider: true },
{ onClick: () => setGrouping('GROUP:YEAR'), text: 'Group by YEAR' },
{ onClick: () => setGrouping('GROUP:MONTH'), text: 'Group by MONTH' },
{ onClick: () => setGrouping('GROUP:DAY'), text: 'Group by DAY' },
],
{ divider: true },
allowDefineVirtualReferences && { onClick: handleDefineVirtualForeignKey, text: 'Define virtual foreign key' },
column.foreignKey && {
onClick: handleCustomizeDescriptions,
text: 'Customize description',
},
isProApp() &&
allowDefineVirtualReferences && { onClick: handleDefineVirtualForeignKey, text: 'Define virtual foreign key' },
column.foreignKey &&
isProApp() && {
onClick: handleCustomizeDescriptions,
text: 'Customize description',
},
];
}
</script>

View File

@@ -17,6 +17,7 @@
import SelectField from '../forms/SelectField.svelte';
import ColumnEditorModal from '../tableeditor/ColumnEditorModal.svelte';
import { tick } from 'svelte';
import { _t } from '../translations';
export let managerSize;
export let display: GridDisplay;
@@ -154,8 +155,8 @@
class="colmode"
value={isDynamicStructure ? 'variable' : 'fixed'}
options={[
{ label: 'Fixed columns (like SQL)', value: 'fixed' },
{ label: 'Variable columns (like MongoDB)', value: 'variable' },
{ label: _t('column.fixed', {defaultMessage: 'Fixed columns (like SQL)'}), value: 'fixed' },
{ label: _t('column.variable', {defaultMessage: 'Variable columns (like MongoDB)'}) , value: 'variable' },
]}
on:change={e => {
dispatchChangeSet({
@@ -175,7 +176,7 @@
{/if}
<SearchBoxWrapper>
<SearchInput
placeholder="Search columns"
placeholder={_t('column.search', {defaultMessage: 'Search columns'})}
value={currentFilter}
onChange={value => display.setSearchInColumns(value)}
data-testid="ColumnManager_searchColumns"
@@ -186,8 +187,8 @@
on:click={() => {
showModal(InputTextModal, {
value: '',
label: 'Column name',
header: 'Add new column',
label: _t('column.name', {defaultMessage: 'Column name'}),
header: _t('column.addNew', {defaultMessage: 'Add new column'}),
onConfirm: name => {
display.addDynamicColumn(name);
tick().then(() => {

View File

@@ -7,6 +7,7 @@
import { showModal } from '../modals/modalTools';
import ColumnEditorModal from '../tableeditor/ColumnEditorModal.svelte';
import { editorDeleteColumn } from 'dbgate-tools';
import { isProApp } from '../utility/proTools';
export let column;
export let display;
@@ -59,13 +60,17 @@
on:mouseup
>
<div>
<span class="expandColumnIcon" style={`margin-right: ${5 + (column.uniquePath.length - 1) * 10}px`}>
<FontIcon
icon={column.isExpandable ? plusExpandIcon(display.isExpandedColumn(column.uniqueName)) : 'icon invisible-box'}
on:click={() => display.toggleExpandedColumn(column.uniqueName)}
data-testid="ColumnManagerRow_expand_{column.uniqueName}"
/>
</span>
{#if isProApp()}
<span class="expandColumnIcon" style={`margin-right: ${5 + (column.uniquePath.length - 1) * 10}px`}>
<FontIcon
icon={column.isExpandable
? plusExpandIcon(display.isExpandedColumn(column.uniqueName))
: 'icon invisible-box'}
on:click={() => display.toggleExpandedColumn(column.uniqueName)}
data-testid="ColumnManagerRow_expand_{column.uniqueName}"
/>
</span>
{/if}
{#if isJsonView}
<FontIcon icon="img column" />
{:else}

View File

@@ -17,6 +17,7 @@
import FontIcon from '../icons/FontIcon.svelte';
import DictionaryLookupModal from '../modals/DictionaryLookupModal.svelte';
import ValueLookupModal from '../modals/ValueLookupModal.svelte';
import { _t } from '../translations';
export let isReadOnly = false;
export let filterBehaviour;
@@ -64,43 +65,43 @@
function createMenu() {
const res = [
{ onClick: () => setFilter(''), text: 'Clear Filter' },
{ onClick: () => filterMultipleValues(), text: 'Filter multiple values' },
{ onClick: () => setFilter(''), text: _t('filter.clear', { defaultMessage: 'Clear Filter' }) },
{ onClick: () => filterMultipleValues(), text: _t('filter.multipleValues', { defaultMessage: 'Filter multiple values' }) },
];
if (filterBehaviour.supportEquals) {
res.push(
{ onClick: () => openFilterWindow('='), text: 'Equals...' },
{ onClick: () => openFilterWindow('<>'), text: 'Does Not Equal...' }
{ onClick: () => openFilterWindow('='), text: _t('filter.equals', { defaultMessage: 'Equals...' }) },
{ onClick: () => openFilterWindow('<>'), text: _t('filter.doesNotEqual', { defaultMessage: 'Does Not Equal...' }) }
);
}
if (filterBehaviour.supportExistsTesting) {
res.push(
{ onClick: () => setFilter('EXISTS'), text: 'Field exists' },
{ onClick: () => setFilter('NOT EXISTS'), text: 'Field does not exist' }
{ onClick: () => setFilter('EXISTS'), text: _t('filter.fieldExists', { defaultMessage: 'Field exists' }) },
{ onClick: () => setFilter('NOT EXISTS'), text: _t('filter.fieldDoesNotExist', { defaultMessage: 'Field does not exist' }) }
);
}
if (filterBehaviour.supportNotEmptyArrayTesting) {
res.push({ onClick: () => setFilter('NOT EMPTY ARRAY'), text: 'Array is not empty' });
res.push({ onClick: () => setFilter('NOT EMPTY ARRAY'), text: _t('filter.arrayIsNotEmpty', { defaultMessage: 'Array is not empty' }) });
}
if (filterBehaviour.supportEmptyArrayTesting) {
res.push({ onClick: () => setFilter('EMPTY ARRAY'), text: 'Array is empty' });
res.push({ onClick: () => setFilter('EMPTY ARRAY'), text: _t('filter.arrayIsEmpty', { defaultMessage: 'Array is empty' }) });
}
if (filterBehaviour.supportNullTesting) {
res.push(
{ onClick: () => setFilter('NULL'), text: 'Is Null' },
{ onClick: () => setFilter('NOT NULL'), text: 'Is Not Null' }
{ onClick: () => setFilter('NULL'), text: _t('filter.isNull', { defaultMessage: 'Is Null' }) },
{ onClick: () => setFilter('NOT NULL'), text: _t('filter.isNotNull', { defaultMessage: 'Is Not Null' }) }
);
}
if (filterBehaviour.supportEmpty) {
res.push(
{ onClick: () => setFilter('EMPTY, NULL'), text: 'Is Empty Or Null' },
{ onClick: () => setFilter('NOT EMPTY NOT NULL'), text: 'Has Not Empty Value' }
{ onClick: () => setFilter('EMPTY, NULL'), text: _t('filter.isEmptyOrNull', { defaultMessage: 'Is Empty Or Null' }) },
{ onClick: () => setFilter('NOT EMPTY NOT NULL'), text: _t('filter.hasNotEmptyValue', { defaultMessage: 'Has Not Empty Value' }) }
);
}
@@ -108,10 +109,10 @@
res.push(
{ divider: true },
{ onClick: () => openFilterWindow('>'), text: 'Greater Than...' },
{ onClick: () => openFilterWindow('>='), text: 'Greater Than Or Equal To...' },
{ onClick: () => openFilterWindow('<'), text: 'Less Than...' },
{ onClick: () => openFilterWindow('<='), text: 'Less Than Or Equal To...' }
{ onClick: () => openFilterWindow('>'), text: _t('filter.greaterThan', { defaultMessage: 'Greater Than...' }) },
{ onClick: () => openFilterWindow('>='), text: _t('filter.greaterThanOrEqualTo', { defaultMessage: 'Greater Than Or Equal To...' }) },
{ onClick: () => openFilterWindow('<'), text: _t('filter.lessThan', { defaultMessage: 'Less Than...' }) },
{ onClick: () => openFilterWindow('<='), text: _t('filter.lessThanOrEqualTo', { defaultMessage: 'Less Than Or Equal To...' }) }
);
}
@@ -119,26 +120,26 @@
res.push(
{ divider: true },
{ onClick: () => openFilterWindow('+'), text: 'Contains...' },
{ onClick: () => openFilterWindow('~'), text: 'Does Not Contain...' },
{ onClick: () => openFilterWindow('^'), text: 'Begins With...' },
{ onClick: () => openFilterWindow('!^'), text: 'Does Not Begin With...' },
{ onClick: () => openFilterWindow('$'), text: 'Ends With...' },
{ onClick: () => openFilterWindow('!$'), text: 'Does Not End With...' }
{ onClick: () => openFilterWindow('+'), text: _t('filter.contains', { defaultMessage: 'Contains...' }) },
{ onClick: () => openFilterWindow('~'), text: _t('filter.doesNotContain', { defaultMessage: 'Does Not Contain...' }) },
{ onClick: () => openFilterWindow('^'), text: _t('filter.beginsWith', { defaultMessage: 'Begins With...' }) },
{ onClick: () => openFilterWindow('!^'), text: _t('filter.doesNotBeginWith', { defaultMessage: 'Does Not Begin With...' }) },
{ onClick: () => openFilterWindow('$'), text: _t('filter.endsWith', { defaultMessage: 'Ends With...' }) },
{ onClick: () => openFilterWindow('!$'), text: _t('filter.doesNotEndWith', { defaultMessage: 'Does Not End With...' }) }
);
}
if (filterBehaviour.supportBooleanValues) {
res.push(
{ onClick: () => setFilter('TRUE'), text: 'Is True' },
{ onClick: () => setFilter('FALSE'), text: 'Is False' }
{ onClick: () => setFilter('TRUE'), text: _t('filter.isTrue', { defaultMessage: 'Is True' }) },
{ onClick: () => setFilter('FALSE'), text: _t('filter.isFalse', { defaultMessage: 'Is False' }) }
);
}
if (filterBehaviour.supportBooleanOrNull) {
res.push(
{ onClick: () => setFilter('TRUE, NULL'), text: 'Is True or NULL' },
{ onClick: () => setFilter('FALSE, NULL'), text: 'Is False or NULL' }
{ onClick: () => setFilter('TRUE, NULL'), text: _t('filter.isTrueOrNull', { defaultMessage: 'Is True or NULL' }) },
{ onClick: () => setFilter('FALSE, NULL'), text: _t('filter.isFalseOrNull', { defaultMessage: 'Is False or NULL' }) }
);
}
@@ -146,44 +147,44 @@
res.push(
{ divider: true },
{ onClick: () => setFilter('TOMORROW'), text: 'Tomorrow' },
{ onClick: () => setFilter('TODAY'), text: 'Today' },
{ onClick: () => setFilter('YESTERDAY'), text: 'Yesterday' },
{ onClick: () => setFilter('TOMORROW'), text: _t('filter.tomorrow', { defaultMessage: 'Tomorrow' }) },
{ onClick: () => setFilter('TODAY'), text: _t('filter.today', { defaultMessage: 'Today' }) },
{ onClick: () => setFilter('YESTERDAY'), text: _t('filter.yesterday', { defaultMessage: 'Yesterday' }) },
{ divider: true },
{ onClick: () => setFilter('NEXT WEEK'), text: 'Next Week' },
{ onClick: () => setFilter('THIS WEEK'), text: 'This Week' },
{ onClick: () => setFilter('LAST WEEK'), text: 'Last Week' },
{ onClick: () => setFilter('NEXT WEEK'), text: _t('filter.nextWeek', { defaultMessage: 'Next Week' }) },
{ onClick: () => setFilter('THIS WEEK'), text: _t('filter.thisWeek', { defaultMessage: 'This Week' }) },
{ onClick: () => setFilter('LAST WEEK'), text: _t('filter.lastWeek', { defaultMessage: 'Last Week' }) },
{ divider: true },
{ onClick: () => setFilter('NEXT MONTH'), text: 'Next Month' },
{ onClick: () => setFilter('THIS MONTH'), text: 'This Month' },
{ onClick: () => setFilter('LAST MONTH'), text: 'Last Month' },
{ onClick: () => setFilter('NEXT MONTH'), text: _t('filter.nextMonth', { defaultMessage: 'Next Month' }) },
{ onClick: () => setFilter('THIS MONTH'), text: _t('filter.thisMonth', { defaultMessage: 'This Month' }) },
{ onClick: () => setFilter('LAST MONTH'), text: _t('filter.lastMonth', { defaultMessage: 'Last Month' }) },
{ divider: true },
{ onClick: () => setFilter('NEXT YEAR'), text: 'Next Year' },
{ onClick: () => setFilter('THIS YEAR'), text: 'This Year' },
{ onClick: () => setFilter('LAST YEAR'), text: 'Last Year' }
{ onClick: () => setFilter('NEXT YEAR'), text: _t('filter.nextYear', { defaultMessage: 'Next Year' }) },
{ onClick: () => setFilter('THIS YEAR'), text: _t('filter.thisYear', { defaultMessage: 'This Year' }) },
{ onClick: () => setFilter('LAST YEAR'), text: _t('filter.lastYear', { defaultMessage: 'Last Year' }) }
);
}
if (filterBehaviour.supportDatetimeComparison) {
res.push(
{ divider: true },
{ onClick: () => openFilterWindow('<='), text: 'Before...' },
{ onClick: () => openFilterWindow('>='), text: 'After...' },
{ onClick: () => openFilterWindow('>=;<='), text: 'Between...' }
{ onClick: () => openFilterWindow('<='), text: _t('filter.before', { defaultMessage: 'Before...' }) },
{ onClick: () => openFilterWindow('>='), text: _t('filter.after', { defaultMessage: 'After...' }) },
{ onClick: () => openFilterWindow('>=;<='), text: _t('filter.between', { defaultMessage: 'Between...' }) }
);
}
if (filterBehaviour.supportSqlCondition) {
res.push(
{ divider: true },
{ onClick: () => openFilterWindow('sql'), text: 'SQL condition ...' },
{ onClick: () => openFilterWindow('sqlRight'), text: 'SQL condition - right side ...' }
{ onClick: () => openFilterWindow('sql'), text: _t('filter.sqlCondition', { defaultMessage: 'SQL condition ...' }) },
{ onClick: () => openFilterWindow('sqlRight'), text: _t('filter.sqlConditionRight', { defaultMessage: 'SQL condition - right side ...' }) }
);
}

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'dataGrid.switchToForm',
category: 'Data grid',
name: 'Switch to form',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.switchToform', { defaultMessage: 'Switch to form' }),
icon: 'icon form',
keyText: 'F4',
testEnabled: () => getCurrentEditor()?.switchViewEnabled('form'),
@@ -13,8 +13,8 @@
registerCommand({
id: 'dataGrid.switchToJson',
category: 'Data grid',
name: 'Switch to JSON',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.switchToJSON', { defaultMessage: 'Switch to JSON' }),
icon: 'icon json',
keyText: 'F4',
testEnabled: () => getCurrentEditor()?.switchViewEnabled('json'),
@@ -23,8 +23,8 @@
registerCommand({
id: 'dataGrid.switchToTable',
category: 'Data grid',
name: 'Switch to table',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.witchToTable', { defaultMessage: 'Switch to table'}),
icon: 'icon table',
keyText: 'F4',
testEnabled: () => getCurrentEditor()?.switchViewEnabled('table'),
@@ -33,8 +33,8 @@
registerCommand({
id: 'dataGrid.toggleLeftPanel',
category: 'Data grid',
name: 'Toggle left panel',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.toggleLeftPanel', { defaultMessage: 'Toggle left panel' }),
keyText: 'CtrlOrCommand+L',
testEnabled: () => getCurrentEditor()?.canShowLeftPanel(),
onClick: () => getCurrentEditor().toggleLeftPanel(),
@@ -68,6 +68,8 @@
import registerCommand from '../commands/registerCommand';
import { registerMenu } from '../utility/contextMenu';
import { getLocalStorage, setLocalStorage } from '../utility/storageCache';
import { __t, _t } from '../translations';
import { isProApp } from '../utility/proTools';
export let config;
export let setConfig;
@@ -173,7 +175,7 @@
<div class="left" slot="1">
<WidgetColumnBar>
<WidgetColumnBarItem
title="Columns"
title={_t('dataGrid.columns', { defaultMessage: 'Columns' })}
name="columns"
height="45%"
skip={isFormView}
@@ -183,7 +185,7 @@
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="Filters"
title={_t('dataGrid.filters', { defaultMessage: 'Filters' })}
name="filters"
height={showReferences && display?.hasReferences && !isFormView ? '15%' : '30%'}
skip={!display?.filterable}
@@ -201,20 +203,20 @@
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="References"
title={_t('dataGrid.references', { defaultMessage: 'References' })}
name="references"
height="30%"
collapsed={isDetailView}
skip={!(showReferences && display?.hasReferences)}
skip={!(showReferences && display?.hasReferences && isProApp())}
data-testid="DataGrid_itemReferences"
>
<ReferenceManager {...$$props} {managerSize} />
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="Macros"
title={_t('dataGrid.macros', { defaultMessage: 'Macros' })}
name="macros"
skip={!showMacros}
skip={!(showMacros && isProApp())}
collapsed={!expandMacros}
data-testid="DataGrid_itemMacros"
>

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'dataGrid.refresh',
category: 'Data grid',
name: _t('common.refresh', { defaultMessage: 'Refresh' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('common.refresh', { defaultMessage: 'Refresh' }),
keyText: 'F5 | CtrlOrCommand+R',
toolbar: true,
isRelatedToTab: true,
@@ -15,8 +15,8 @@
registerCommand({
id: 'dataGrid.deepRefresh',
category: 'Data grid',
name: 'Refresh with structure',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('common.datagrid.deepRefresh', { defaultMessage: 'Refresh with structure' }),
keyText: 'Ctrl+F5',
toolbar: true,
isRelatedToTab: true,
@@ -27,8 +27,8 @@
registerCommand({
id: 'dataGrid.revertRowChanges',
category: 'Data grid',
name: _t('command.datagrid.revertRowChanges', { defaultMessage: 'Revert row changes' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.revertRowChanges', { defaultMessage: 'Revert row changes' }),
keyText: 'CtrlOrCommand+U',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertRowChanges(),
@@ -36,9 +36,9 @@
registerCommand({
id: 'dataGrid.revertAllChanges',
category: 'Data grid',
name: _t('command.datagrid.revertAllChanges', { defaultMessage: 'Revert all changes' }),
toolbarName: _t('command.datagrid.revertAllChanges.toolbar', { defaultMessage: 'Revert all' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.revertAllChanges', { defaultMessage: 'Revert all changes' }),
toolbarName: __t('command.datagrid.revertAllChanges.toolbar', { defaultMessage: 'Revert all' }),
icon: 'icon undo',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertAllChanges(),
@@ -46,9 +46,9 @@
registerCommand({
id: 'dataGrid.deleteSelectedRows',
category: 'Data grid',
name: _t('command.datagrid.deleteSelectedRows', { defaultMessage: 'Delete selected rows' }),
toolbarName: _t('command.datagrid.deleteSelectedRows.toolbar', { defaultMessage: 'Delete row(s)' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.deleteSelectedRows', { defaultMessage: 'Delete selected rows' }),
toolbarName: __t('command.datagrid.deleteSelectedRows.toolbar', { defaultMessage: 'Delete row(s)' }),
keyText: isMac() ? 'Command+Backspace' : 'CtrlOrCommand+Delete',
icon: 'icon minus',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
@@ -57,9 +57,9 @@
registerCommand({
id: 'dataGrid.insertNewRow',
category: 'Data grid',
name: _t('command.datagrid.insertNewRow', { defaultMessage: 'Insert new row' }),
toolbarName: _t('command.datagrid.insertNewRow.toolbar', { defaultMessage: 'New row' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.insertNewRow', { defaultMessage: 'Insert new row' }),
toolbarName: __t('command.datagrid.insertNewRow.toolbar', { defaultMessage: 'New row' }),
icon: 'icon add',
keyText: isMac() ? 'Command+I' : 'Insert',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
@@ -68,9 +68,9 @@
registerCommand({
id: 'dataGrid.addNewColumn',
category: 'Data grid',
name: _t('command.datagrid.addNewColumn', { defaultMessage: 'Add new column' }),
toolbarName: _t('command.datagrid.addNewColumn.toolbar', { defaultMessage: 'New column' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.addNewColumn', { defaultMessage: 'Add new column' }),
toolbarName: __t('command.datagrid.addNewColumn.toolbar', { defaultMessage: 'New column' }),
icon: 'icon add-column',
testEnabled: () => getCurrentDataGrid()?.addNewColumnEnabled(),
onClick: () => getCurrentDataGrid().addNewColumn(),
@@ -78,9 +78,9 @@
registerCommand({
id: 'dataGrid.cloneRows',
category: 'Data grid',
name: _t('command.datagrid.cloneRows', { defaultMessage: 'Clone rows' }),
toolbarName: _t('command.datagrid.cloneRows.toolbar', { defaultMessage: 'Clone row(s)' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.cloneRows', { defaultMessage: 'Clone rows' }),
toolbarName: __t('command.datagrid.cloneRows.toolbar', { defaultMessage: 'Clone row(s)' }),
keyText: 'CtrlOrCommand+Shift+C',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
onClick: () => getCurrentDataGrid().cloneRows(),
@@ -88,8 +88,8 @@
registerCommand({
id: 'dataGrid.setNull',
category: 'Data grid',
name: _t('command.datagrid.setNull', { defaultMessage: 'Set NULL' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.setNull', { defaultMessage: 'Set NULL' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () =>
getCurrentDataGrid()?.getGrider()?.editable && !getCurrentDataGrid()?.getEditorTypes()?.supportFieldRemoval,
@@ -98,8 +98,8 @@
registerCommand({
id: 'dataGrid.removeField',
category: 'Data grid',
name: _t('command.datagrid.removeField', { defaultMessage: 'Remove field' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.removeField', { defaultMessage: 'Remove field' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () =>
getCurrentDataGrid()?.getGrider()?.editable && getCurrentDataGrid()?.getEditorTypes()?.supportFieldRemoval,
@@ -108,8 +108,8 @@
registerCommand({
id: 'dataGrid.undo',
category: 'Data grid',
name: _t('command.datagrid.undo', { defaultMessage: 'Undo' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.undo', { defaultMessage: 'Undo' }),
group: 'undo',
icon: 'icon undo',
toolbar: true,
@@ -120,8 +120,8 @@
registerCommand({
id: 'dataGrid.redo',
category: 'Data grid',
name: _t('command.datagrid.redo', { defaultMessage: 'Redo' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.redo', { defaultMessage: 'Redo' }),
group: 'redo',
icon: 'icon redo',
toolbar: true,
@@ -132,16 +132,16 @@
registerCommand({
id: 'dataGrid.reconnect',
category: 'Data grid',
name: _t('command.datagrid.reconnect', { defaultMessage: 'Reconnect' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.reconnect', { defaultMessage: 'Reconnect' }),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().reconnect(),
});
registerCommand({
id: 'dataGrid.copyToClipboard',
category: 'Data grid',
name: _t('command.datagrid.copyToClipboard', { defaultMessage: 'Copy to clipboard' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.copyToClipboard', { defaultMessage: 'Copy to clipboard' }),
keyText: 'CtrlOrCommand+C',
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentDataGrid() != null,
@@ -150,57 +150,57 @@
registerCommand({
id: 'dataGrid.editJsonDocument',
category: 'Data grid',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
keyText: 'CtrlOrCommand+J',
name: _t('command.datagrid.editJsonDocument', { defaultMessage: 'Edit row as JSON document' }),
name: __t('command.datagrid.editJsonDocument', { defaultMessage: 'Edit row as JSON document' }),
testEnabled: () => getCurrentDataGrid()?.editJsonEnabled(),
onClick: () => getCurrentDataGrid().editJsonDocument(),
});
registerCommand({
id: 'dataGrid.openSelectionInMap',
category: 'Data grid',
name: _t('command.datagrid.openSelectionInMap', { defaultMessage: 'Open selection in map' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.openSelectionInMap', { defaultMessage: 'Open selection in map' }),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().openSelectionInMap(),
});
registerCommand({
id: 'dataGrid.viewJsonDocument',
category: 'Data grid',
name: _t('command.datagrid.viewJsonDocument', { defaultMessage: 'View row as JSON document' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.viewJsonDocument', { defaultMessage: 'View row as JSON document' }),
testEnabled: () => getCurrentDataGrid()?.viewJsonDocumentEnabled(),
onClick: () => getCurrentDataGrid().viewJsonDocument(),
});
registerCommand({
id: 'dataGrid.viewJsonValue',
category: 'Data grid',
name: _t('command.datagrid.viewJsonValue', { defaultMessage: 'View cell as JSON document' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.viewJsonValue', { defaultMessage: 'View cell as JSON document' }),
testEnabled: () => getCurrentDataGrid()?.viewJsonValueEnabled(),
onClick: () => getCurrentDataGrid().viewJsonValue(),
});
registerCommand({
id: 'dataGrid.openJsonArrayInSheet',
category: 'Data grid',
name: _t('command.datagrid.openJsonArrayInSheet', { defaultMessage: 'Open array as table' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.openJsonArrayInSheet', { defaultMessage: 'Open array as table' }),
testEnabled: () => getCurrentDataGrid()?.openJsonArrayInSheetEnabled(),
onClick: () => getCurrentDataGrid().openJsonArrayInSheet(),
});
registerCommand({
id: 'dataGrid.saveCellToFile',
category: 'Data grid',
name: _t('command.datagrid.saveCellToFile', { defaultMessage: 'Save cell to file' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.saveCellToFile', { defaultMessage: 'Save cell to file' }),
testEnabled: () => getCurrentDataGrid()?.saveCellToFileEnabled(),
onClick: () => getCurrentDataGrid().saveCellToFile(),
});
registerCommand({
id: 'dataGrid.loadCellFromFile',
category: 'Data grid',
name: _t('command.datagrid.loadCellFromFile', { defaultMessage: 'Load cell from file' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.loadCellFromFile', { defaultMessage: 'Load cell from file' }),
testEnabled: () => getCurrentDataGrid()?.loadCellFromFileEnabled(),
onClick: () => getCurrentDataGrid().loadCellFromFile(),
});
@@ -216,62 +216,62 @@
//
registerCommand({
id: 'dataGrid.filterSelected',
category: 'Data grid',
name: 'Filter selected value',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.filterSelected', { defaultMessage : 'Filter selected value'}),
keyText: 'CtrlOrCommand+Shift+F',
testEnabled: () => getCurrentDataGrid()?.getDisplay().filterable,
onClick: () => getCurrentDataGrid().filterSelectedValue(),
});
registerCommand({
id: 'dataGrid.findColumn',
category: 'Data grid',
name: 'Find column',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.findColumn', { defaultMessage: 'Find column'}),
keyText: 'CtrlOrCommand+F',
testEnabled: () => getCurrentDataGrid() != null,
getSubCommands: () => getCurrentDataGrid().buildFindMenu(),
});
registerCommand({
id: 'dataGrid.hideColumn',
category: 'Data grid',
name: 'Hide column',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datgrid.hideColumn', { defaultMessage: 'Hide column' }),
keyText: isMac() ? 'Alt+Command+F' : 'CtrlOrCommand+H',
testEnabled: () => getCurrentDataGrid()?.canShowLeftPanel(),
onClick: () => getCurrentDataGrid().hideColumn(),
});
registerCommand({
id: 'dataGrid.clearFilter',
category: 'Data grid',
name: 'Clear filter',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.clearFilter', { defaultMessage : 'Clear filter'}),
keyText: 'CtrlOrCommand+Shift+E',
testEnabled: () => getCurrentDataGrid()?.clearFilterEnabled(),
onClick: () => getCurrentDataGrid().clearFilter(),
});
registerCommand({
id: 'dataGrid.generateSqlFromData',
category: 'Data grid',
name: 'Generate SQL',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.generateSql', { defaultMessage: 'Generate SQL'}),
keyText: 'CtrlOrCommand+G',
testEnabled: () => getCurrentDataGrid()?.generateSqlFromDataEnabled(),
onClick: () => getCurrentDataGrid().generateSqlFromData(),
});
registerCommand({
id: 'dataGrid.openFreeTable',
category: 'Data grid',
name: 'Edit selection as table',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.editSelection', { defaultMessage: 'Edit selection as table'}),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().openFreeTable(),
});
registerCommand({
id: 'dataGrid.newJson',
category: 'Data grid',
name: 'Add JSON document',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.addJsonDocument', { defaultMessage: 'Add JSON document'}),
testEnabled: () => getCurrentDataGrid()?.addJsonDocumentEnabled(),
onClick: () => getCurrentDataGrid().addJsonDocument(),
});
registerCommand({
id: 'dataGrid.editCellValue',
category: 'Data grid',
name: 'Edit cell value',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.editCell', { defaultMessage: 'Edit cell value' }),
testEnabled: () => getCurrentDataGrid()?.editCellValueEnabled(),
onClick: () => getCurrentDataGrid().editCellValue(),
});
@@ -279,8 +279,8 @@
if (isProApp()) {
registerCommand({
id: 'dataGrid.sendToDataDeploy',
category: 'Data grid',
name: 'Send to data deployer',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.sendToDataDeployer', { defaultMessage: 'Send to data deployer' }),
testEnabled: () => getCurrentDataGrid()?.sendToDataDeployEnabled(),
onClick: () => getCurrentDataGrid().sendToDataDeploy(),
});
@@ -422,7 +422,7 @@
import { openJsonLinesData } from '../utility/openJsonLinesData';
import contextMenuActivator from '../utility/contextMenuActivator';
import InputTextModal from '../modals/InputTextModal.svelte';
import { _t } from '../translations';
import { __t, _t, _val } from '../translations';
import { isProApp } from '../utility/proTools';
import SaveArchiveModal from '../modals/SaveArchiveModal.svelte';
import hasPermission from '../utility/hasPermission';
@@ -1417,7 +1417,11 @@
function handleGridWheel(event) {
if (event.shiftKey) {
scrollHorizontal(event.deltaY, event.deltaX);
if (isMac()) {
scrollHorizontal(event.deltaX, event.deltaY);
} else {
scrollHorizontal(event.deltaY, event.deltaX);
}
} else {
scrollHorizontal(event.deltaX, event.deltaY);
scrollVertical(event.deltaX, event.deltaY);
@@ -1792,15 +1796,15 @@
{ command: 'dataGrid.refresh' },
{ placeTag: 'copy' },
{
text: 'Copy advanced',
text: _t('datagrid.copyAdvanced', { defaultMessage: 'Copy advanced'}),
submenu: [
_.keys(copyRowsFormatDefs).map(format => ({
text: copyRowsFormatDefs[format].label,
text: _val(copyRowsFormatDefs[format].label),
onClick: () => copyToClipboardCore(format),
})),
{ divider: true },
_.keys(copyRowsFormatDefs).map(format => ({
text: `Set format: ${copyRowsFormatDefs[format].name}`,
text: _t('datagrid.setFormat', { defaultMessage: 'Set format: ' }) + (_val(copyRowsFormatDefs[format].name)),
onClick: () => ($copyRowsFormat = format),
})),
@@ -1870,7 +1874,7 @@
return [
menu,
{
text: copyRowsFormatDefs[$copyRowsFormat].label,
text: _val(copyRowsFormatDefs[$copyRowsFormat].label),
onClick: () => copyToClipboardCore($copyRowsFormat),
keyText: 'CtrlOrCommand+C',
tag: 'copy',

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'jslTableGrid.export',
category: 'Data grid',
name: 'Export',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.export', { defaultMessage: 'Export' }),
icon: 'icon export',
keyText: 'CtrlOrCommand+E',
testEnabled: () => getCurrentEditor() != null,
@@ -56,6 +56,7 @@
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
import { openImportExportTab } from '../utility/importExportTools';
import { __t } from '../translations';
export let jslid;
export let display;

View File

@@ -11,6 +11,8 @@
import FontIcon from '../icons/FontIcon.svelte';
import TokenizedFilteredText from '../widgets/TokenizedFilteredText.svelte';
import { _t } from '../translations';
export let managerSize;
export let display: GridDisplay;
export let onReferenceClick = ref => {};
@@ -24,12 +26,12 @@
</script>
<SearchBoxWrapper>
<SearchInput placeholder="Search references" bind:value={filter} />
<SearchInput placeholder={_t('dataGrid.searchReferences', { defaultMessage: 'Search references' })} bind:value={filter} />
<CloseSearchButton bind:filter />
</SearchBoxWrapper>
<ManagerInnerContainer width={managerSize}>
{#if foreignKeys.length > 0}
<div class="bold nowrap ml-1">References tables ({foreignKeys.length})</div>
<div class="bold nowrap ml-1">{_t('dataGrid.referencesTables', { defaultMessage: 'References tables' })} ({foreignKeys.length})</div>
{#each foreignKeys.filter(fk => filterName(filter, fk.refTableName)) as fk}
<div
class="link"
@@ -53,7 +55,7 @@
{/if}
{#if dependencies.length > 0}
<div class="bold nowrap ml-1">Dependent tables ({dependencies.length})</div>
<div class="bold nowrap ml-1">{_t('dataGrid.dependentTables', { defaultMessage: 'Dependent tables' })} ({dependencies.length})</div>
{#each dependencies.filter(fk => filterName(filter, fk.pureName)) as fk}
<div
class="link"

View File

@@ -1,18 +1,19 @@
<script context="module" lang="ts">
import { __t } from '../translations'
const getCurrentEditor = () => getActiveComponent('SqlDataGridCore');
registerCommand({
id: 'sqlDataGrid.openQuery',
category: 'Data grid',
name: 'Open query',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.openQuery', { defaultMessage : 'Open query' }),
testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/query'),
onClick: () => getCurrentEditor().openQuery(),
});
registerCommand({
id: 'sqlDataGrid.export',
category: 'Data grid',
name: 'Export',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('common.export', { defaultMessage : 'Export' }),
icon: 'icon export',
keyText: 'CtrlOrCommand+E',
testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/export'),

View File

@@ -30,6 +30,7 @@
import SqlFormView from '../formview/SqlFormView.svelte';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { getDictionaryDescription } from '../utility/dictionaryDescriptionTools';
import { isProApp } from '../utility/proTools';
export let conid;
export let database;
@@ -82,7 +83,8 @@
extendedDbInfo?.tables?.find(x => x.pureName == pureName && x.schemaName == schemaName)
?.tablePermissionRole == 'read',
isRawMode,
$settingsValue
$settingsValue,
isProApp()
)
: null;

View File

@@ -3,9 +3,9 @@
registerCommand({
id: 'designer.arrange',
category: 'Designer',
category: __t('command.designer', { defaultMessage: 'Designer' }),
icon: 'icon arrange',
name: 'Arrange',
name: __t('command.designer.arrange', { defaultMessage: 'Arrange' }),
toolbar: true,
isRelatedToTab: true,
testEnabled: () => getCurrentEditor()?.canArrange(),
@@ -15,9 +15,9 @@
registerCommand({
id: 'diagram.export',
category: 'Designer',
toolbarName: 'Export diagram',
name: 'Export diagram',
category: __t('command.designer', { defaultMessage: 'Designer' }),
toolbarName: __t('command.designer.exportDiagram', { defaultMessage: 'Export diagram' }),
name: __t('command.designer.exportDiagram', { defaultMessage: 'Export diagram' }),
icon: 'icon report',
toolbar: true,
isRelatedToTab: true,
@@ -27,9 +27,9 @@
registerCommand({
id: 'diagram.deleteSelectedTables',
category: 'Designer',
toolbarName: 'Remove',
name: 'Remove selected tables',
category: __t('command.designer', { defaultMessage: 'Designer' }),
toolbarName: __t('command.designer.remove', { defaultMessage: 'Remove' }),
name: __t('command.designer.removeSelectedTables', { defaultMessage: 'Remove selected tables' }),
icon: 'icon delete',
toolbar: true,
isRelatedToTab: true,
@@ -67,6 +67,7 @@
import { isProApp } from '../utility/proTools';
import dragScroll from '../utility/dragScroll';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import { __t } from '../translations';
export let value;
export let onChange;

View File

@@ -5,6 +5,7 @@
import ObjectListControl from '../elements/ObjectListControl.svelte';
import Link from './Link.svelte';
import { _t } from '../translations';
export let collection;
export let title;
@@ -24,18 +25,18 @@
columns={[
{
fieldName: 'baseColumns',
header: 'Base columns',
header: _t('foreignKey.baseColumns', { defaultMessage: 'Base columns' }),
slot: 0,
sortable: true,
},
{
fieldName: 'refTableName',
header: 'Referenced table',
header: _t('foreignKey.refTableName', { defaultMessage: 'Referenced table' }),
sortable: true,
},
{
fieldName: 'refColumns',
header: 'Referenced columns',
header: _t('foreignKey.refColumns', { defaultMessage: 'Referenced columns' }),
slot: 1,
sortable: true,
},
@@ -60,5 +61,5 @@
<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?.columns.map(x => x.refColumnName).join(', ')}</svelte:fragment>
<svelte:fragment slot="2" let:row><Link onClick={() => onRemove(row)}>Remove</Link></svelte:fragment>
<svelte:fragment slot="2" let:row><Link onClick={() => onRemove(row)}>{_t('common.remove', { defaultMessage: 'Remove' })}</Link></svelte:fragment>
</ObjectListControl>

View File

@@ -4,6 +4,7 @@
import Link from './Link.svelte';
import TableControl from './TableControl.svelte';
import { writable } from 'svelte/store';
import { _t } from '../translations';
export let title;
export let collection;
@@ -39,7 +40,7 @@
</span>
<span class="title mr-1">{title}</span>
{#if onAddNew}
<Link onClick={onAddNew}><FontIcon icon="icon add" /> Add new</Link>
<Link onClick={onAddNew}><FontIcon icon="icon add" />{_t('common.addNew', { defaultMessage: 'Add new' })}</Link>
{/if}
{#if multipleItemsActions && activeMultipleSelection && activeMultipleSelection?.length > 0}
{#each multipleItemsActions as item}
@@ -65,7 +66,7 @@
columns={_.compact([
!hideDisplayName && {
fieldName: displayNameFieldName || 'displayName',
header: 'Name',
header: _t('common.name', { defaultMessage: 'Name' }),
slot: -1,
sortable: true,
filterable: !!displayNameFieldName,

View File

@@ -5,6 +5,8 @@
import { onMount, afterUpdate } from 'svelte';
export let code = '';
export let inline = false;
export let onClick = null;
let domCode;
@@ -29,7 +31,11 @@
The `sql` class hints the language; highlight.js will
read it even though we register the grammar explicitly.
-->
<pre bind:this={domCode} class="sql">{code}</pre>
{#if inline}
<span bind:this={domCode} class="sql" class:clickable={!!onClick} on:click={onClick}>{code}</span>
{:else}
<pre bind:this={domCode} class="sql" class:clickable={!!onClick} on:click={onClick}>{code}</pre>
{/if}
{/key}
<style>
@@ -38,4 +44,8 @@
padding: 0;
padding: 0.5em;
}
.clickable {
cursor: pointer;
}
</style>

View File

@@ -27,6 +27,7 @@
import { evaluateCondition } from 'dbgate-sqltree';
import { compileCompoudEvalCondition } from 'dbgate-filterparser';
import { chevronExpandIcon } from '../icons/expandIcons';
import { _val } from '../translations';
export let columns: (TableControlColumn | false)[];
export let rows = null;
@@ -368,7 +369,7 @@
{/if}
{/key}
{:else}
{row[col.fieldName] || ''}
{ _val(row[col.fieldName]) || '' }
{/if}
</td>
{/each}

View File

@@ -5,6 +5,7 @@
import { getFormContext } from './FormProviderCore.svelte';
import TextField from './TextField.svelte';
import { _t } from '../translations';
export let name;
export let disabled = false;
@@ -29,7 +30,7 @@
setFieldValue(name, e.target['value']);
}
}}
placeholder={isCrypted ? '(Password is encrypted)' : undefined}
placeholder={isCrypted ? _t('common.passwordEncrypted', { defaultMessage: 'Password is encrypted' }) : undefined}
type={isCrypted || showPassword ? 'text' : 'password'}
/>
{#if !isCrypted}

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import TextField from './TextField.svelte';
import { _val } from '../translations';
export let name;
export let defaultValue;
@@ -11,7 +12,7 @@
<TextField
{...$$restProps}
value={$values?.[name] ?? defaultValue}
value={$values?.[name] ? _val($values[name]) : defaultValue}
on:input={e => setFieldValue(name, e.target['value'])}
on:input={e => {
if (saveOnInput) {

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'collectionJsonView.expandAll',
category: 'Collection data',
name: 'Expand all',
category: __t('command.collectionData', { defaultMessage: 'Collection data' }),
name: __t('command.collectionData.expandAll', { defaultMessage: 'Expand all' }),
isRelatedToTab: true,
icon: 'icon expand-all',
onClick: () => getCurrentEditor().handleExpandAll(),
@@ -12,8 +12,8 @@
});
registerCommand({
id: 'collectionJsonView.collapseAll',
category: 'Collection data',
name: 'Collapse all',
category: __t('command.collectionData', { defaultMessage: 'Collection data' }),
name: __t('command.collectionData.collapseAll', { defaultMessage: 'Collapse all' }),
isRelatedToTab: true,
icon: 'icon collapse-all',
onClick: () => getCurrentEditor().handleCollapseAll(),
@@ -37,6 +37,7 @@
import CollectionJsonRow from './CollectionJsonRow.svelte';
import { getIntSettingsValue } from '../settings/settingsTools';
import invalidateCommands from '../commands/invalidateCommands';
import { __t } from '../translations';
export let conid;
export let database;

View File

@@ -14,8 +14,8 @@
registerCommand({
id: 'dataForm.refresh',
category: 'Data form',
name: _t('common.refresh', { defaultMessage: 'Refresh' }),
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('common.refresh', { defaultMessage: 'Refresh' }),
keyText: 'F5 | CtrlOrCommand+R',
toolbar: true,
isRelatedToTab: true,
@@ -26,8 +26,8 @@
registerCommand({
id: 'dataForm.copyToClipboard',
category: 'Data form',
name: 'Copy to clipboard',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.copyToClipboard', { defaultMessage: 'Copy to clipboard' }),
keyText: 'CtrlOrCommand+C',
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentDataForm() != null,
@@ -36,8 +36,8 @@
registerCommand({
id: 'dataForm.revertRowChanges',
category: 'Data form',
name: 'Revert row changes',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.revertRowChanges', { defaultMessage: 'Revert row changes' }),
keyText: 'CtrlOrCommand+U',
testEnabled: () => getCurrentDataForm()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataForm().getGrider().revertRowChanges(0),
@@ -45,8 +45,8 @@
registerCommand({
id: 'dataForm.setNull',
category: 'Data form',
name: 'Set NULL',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.setNull', { defaultMessage: 'Set NULL' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () => getCurrentDataForm() != null && !getCurrentDataForm()?.getEditorTypes()?.supportFieldRemoval,
onClick: () => getCurrentDataForm().setFixedValue(null),
@@ -54,8 +54,8 @@
registerCommand({
id: 'dataForm.removeField',
category: 'Data form',
name: 'Remove field',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.removeField', { defaultMessage: 'Remove field' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () => getCurrentDataForm() != null && getCurrentDataForm()?.getEditorTypes()?.supportFieldRemoval,
onClick: () => getCurrentDataForm().setFixedValue(undefined),
@@ -63,8 +63,8 @@
registerCommand({
id: 'dataForm.undo',
category: 'Data form',
name: 'Undo',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.undo', { defaultMessage: 'Undo' }),
group: 'undo',
icon: 'icon undo',
toolbar: true,
@@ -75,8 +75,8 @@
registerCommand({
id: 'dataForm.redo',
category: 'Data form',
name: 'Redo',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.redo', { defaultMessage: 'Redo' }),
group: 'redo',
icon: 'icon redo',
toolbar: true,
@@ -87,16 +87,16 @@
registerCommand({
id: 'dataForm.reconnect',
category: 'Data grid',
name: 'Reconnect',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.reconnect', { defaultMessage: 'Reconnect' }),
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().reconnect(),
});
registerCommand({
id: 'dataForm.filterSelected',
category: 'Data form',
name: 'Filter this value',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.filterSelected', { defaultMessage: 'Filter this value' }),
keyText: 'CtrlOrCommand+Shift+F',
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().filterSelectedValue(),
@@ -104,16 +104,16 @@
registerCommand({
id: 'dataForm.addToFilter',
category: 'Data form',
name: 'Add to filter',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.addToFilter', { defaultMessage: 'Add to filter' }),
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().addToFilter(),
});
registerCommand({
id: 'dataForm.goToFirst',
category: 'Data form',
name: 'First',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToFirst', { defaultMessage: 'First' }),
keyText: 'CtrlOrCommand+Home',
toolbar: true,
isRelatedToTab: true,
@@ -124,8 +124,8 @@
registerCommand({
id: 'dataForm.goToPrevious',
category: 'Data form',
name: 'Previous',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToPrevious', { defaultMessage: 'Previous' }),
keyText: 'CtrlOrCommand+ArrowUp',
toolbar: true,
isRelatedToTab: true,
@@ -136,8 +136,8 @@
registerCommand({
id: 'dataForm.goToNext',
category: 'Data form',
name: 'Next',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToNext', { defaultMessage: 'Next' }),
keyText: 'CtrlOrCommand+ArrowDown',
toolbar: true,
isRelatedToTab: true,
@@ -148,8 +148,8 @@
registerCommand({
id: 'dataForm.goToLast',
category: 'Data form',
name: 'Last',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToLast', { defaultMessage: 'Last' }),
keyText: 'CtrlOrCommand+End',
toolbar: true,
isRelatedToTab: true,
@@ -197,7 +197,7 @@
import resizeObserver from '../utility/resizeObserver';
import openReferenceForm from './openReferenceForm';
import { useSettings } from '../utility/metadataLoaders';
import { _t } from '../translations';
import { _t, __t } from '../translations';
export let conid;
export let database;
@@ -243,20 +243,16 @@
function getRowCountInfo(allRowCount) {
if (rowCountNotAvailable) {
return `Row: ${((display.config.formViewRecordNumber || 0) + 1).toLocaleString()} / ???`;
return _t('dataForm.rowCount', { defaultMessage: 'Row: {rowCount} / ???', values: { rowCount: ((display.config.formViewRecordNumber || 0) + 1).toLocaleString() } });
}
if (rowData == null) {
if (allRowCount != null) {
return `Out of bounds: ${(
(display.config.formViewRecordNumber || 0) + 1
).toLocaleString()} / ${allRowCount.toLocaleString()}`;
return _t('dataForm.outOfBounds', { defaultMessage: 'Out of bounds: {current} / {total}', values: { current: ((display.config.formViewRecordNumber || 0) + 1).toLocaleString(), total: allRowCount.toLocaleString() } });
}
return 'No data';
return _t('dataForm.noData', { defaultMessage: 'No data' });
}
if (allRowCount == null || display == null) return 'Loading row count...';
return `Row: ${(
(display.config.formViewRecordNumber || 0) + 1
).toLocaleString()} / ${allRowCount.toLocaleString()}`;
if (allRowCount == null || display == null) return _t('dataForm.loadingRowCount', { defaultMessage: 'Loading row count...' });
return _t('dataForm.rowCount', { defaultMessage: 'Row: {current} / {total}', values: { current: ((display.config.formViewRecordNumber || 0) + 1).toLocaleString(), total: allRowCount.toLocaleString() } });
}
export function getGrider() {
@@ -720,7 +716,7 @@
</div>
{#if isLoading}
<LoadingInfo wrapper message="Loading data" />
<LoadingInfo wrapper message={_t('common.loadingData', { defaultMessage: 'Loading data' })} />
{/if}
<style>

View File

@@ -9,6 +9,7 @@
import FormViewFilterColumn from './FormViewFilterColumn.svelte';
import { stringFilterBehaviour } from 'dbgate-tools';
import CheckboxField from '../forms/CheckboxField.svelte';
import { _t } from '../translations';
// import PrimaryKeyFilterEditor from './PrimaryKeyFilterEditor.svelte';
export let managerSize;
@@ -36,7 +37,7 @@
{#if isFormView}
<div class="m-1">
<div>Column name filter</div>
<div>{_t('datagrid.columnNameFilter', { defaultMessage: 'Column name filter' })}</div>
<div class="flex">
<input
type="text"
@@ -63,7 +64,7 @@
{#if hasMultiColumnFilter}
<div class="m-1">
<div class="space-between">
<span>Multi column filter</span>
<span>{_t('dataGrid.multiColumnFilter', { defaultMessage: 'Multi column filter' })}</span>
{#if multiColumnFilter}
<div class="flex items-center gap-2">
<CheckboxField

View File

@@ -1,22 +1,31 @@
<script lang="ts">
import JsonUiCountdown from './JsonUiCountdown.svelte';
import JsonUiHeading from './JsonUiHeading.svelte';
import JsonUiHighlight from './JsonUiHighlight.svelte';
import JsonUiLinkButton from './JsonUiLinkButton.svelte';
import JsonUiLinkButtonBlock from './JsonUiLinkButtonBlock.svelte';
import JsonUiMarkdown from './JsonUiMarkdown.svelte';
import JsonUiTextBlock from './JsonUiTextBlock.svelte';
import JsonUiTickList from './JsonUiTickList.svelte';
import { JsonUiBlock } from './jsonuitypes';
export let blocks: JsonUiBlock[] = [];
export let passProps = {};
const componentMap = {
text: JsonUiTextBlock,
heading: JsonUiHeading,
ticklist: JsonUiTickList,
button: JsonUiLinkButton,
markdown: JsonUiMarkdown,
highlight: JsonUiHighlight,
countdown: JsonUiCountdown,
buttonblock: JsonUiLinkButtonBlock,
} as const;
</script>
{#each blocks as block, i}
{#if block.type in componentMap}
<svelte:component this={componentMap[block.type]} {...block} />
<svelte:component this={componentMap[block.type]} {...block} {...passProps} />
{/if}
{/each}

View File

@@ -0,0 +1,87 @@
<script lang="ts">
import { onMount } from 'svelte';
import { openWebLink } from '../utility/simpleTools';
export let colorClass: string = 'premium-gradient';
export let validTo;
export let link;
function formatRemaining(validTo, now) {
let diffMs = validTo.getTime() - now.getTime();
if (diffMs <= 0) return '0 minutes';
const totalMinutes = Math.floor(diffMs / 60000);
const days = Math.floor(totalMinutes / (24 * 60));
const hours = Math.floor((totalMinutes % (24 * 60)) / 60);
const minutes = totalMinutes % 60;
const parts = [];
const en = (n, unit) => ({
num: n,
unit: n == 1 ? unit : unit + 's',
});
if (days) parts.push(en(days, 'day'));
if (hours) parts.push(en(hours, 'hour'));
// Always include minutes to report down to minutes
parts.push(en(minutes, 'minute'));
return parts;
}
let currentDate = new Date();
onMount(() => {
const interval = setInterval(() => {
currentDate = new Date();
}, 5000);
return () => {
clearInterval(interval);
};
});
$: parts = formatRemaining(new Date(validTo), currentDate);
</script>
{#if validTo}
<div
class="countdown {colorClass}"
class:isLink={!!link}
on:click={() => {
if (link) {
openWebLink(link);
}
}}
>
<span class="big">Offer ends in:</span><br />
{#each parts as part}
<span class="part">
<span class="big">{part.num}</span>
{part.unit}
</span>
{/each}
</div>
{/if}
<style>
.countdown {
text-align: center;
margin: 10px;
border: 1px solid;
padding: 5px;
}
.countdown.isLink {
cursor: pointer;
}
.big {
font-size: large;
font-weight: bold;
}
.part {
margin: 0 5px;
}
</style>

View File

@@ -0,0 +1,35 @@
<script lang="ts">
import { openWebLink } from '../utility/simpleTools';
export let text: string;
export let colorClass: string = 'premium-gradient';
export let link: string;
</script>
<div
class="highlight {colorClass}"
class:isLink={!!link}
on:click={() => {
if (link) {
openWebLink(link);
}
}}
>
{text}
</div>
<style>
.highlight {
display: block;
text-align: center;
margin: 10px;
font-size: large;
font-weight: bold;
border: 1px solid;
padding: 5px;
}
.highlight.isLink {
cursor: pointer;
}
</style>

View File

@@ -5,9 +5,6 @@
export let text: string;
export let link: string;
export let colorClass: string = '';
// very light url guard
const safe = /^(https?:)?\/\//i.test(link) || link.startsWith('/');
</script>
<div class="center">

View File

@@ -0,0 +1,21 @@
<script lang="ts">
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import { openWebLink } from '../utility/simpleTools';
export let text: string;
export let link: string;
export let colorClass: string = '';
export let items: any[] = [];
</script>
<div class="center">
{#each items as item}
<FormStyledButton on:click={() => openWebLink(item.link)} value={item.text} skipWidth {colorClass} />
{/each}
</div>
<style>
.center {
text-align: center;
}
</style>

View File

@@ -0,0 +1,15 @@
<script lang="ts">
import Markdown from '../elements/Markdown.svelte';
export let text: string;
</script>
<div>
<Markdown source={text} />
</div>
<style>
div {
margin: 10px;
}
</style>

View File

@@ -6,6 +6,7 @@
import MacroHeader from './MacroHeader.svelte';
import MacroInfoTab from './MacroInfoTab.svelte';
import { _t } from '../translations';
const selectedMacro = getContext('selectedMacro') as any;
@@ -17,7 +18,7 @@
<TabControl
tabs={[
{
label: 'Macro detail',
label: _t('datagrid.macros.detail', { defaultMessage: 'Macro detail' }),
component: MacroInfoTab,
props: {
onExecute,

View File

@@ -2,6 +2,7 @@
import { getContext } from 'svelte';
import FontIcon from '../icons/FontIcon.svelte';
import ToolbarButton from '../buttons/ToolbarButton.svelte';
import { _t } from '../translations';
export let onExecute;
@@ -16,8 +17,8 @@
</div>
</div>
<div class="buttons">
<ToolbarButton icon="icon run" on:click={onExecute}>Execute</ToolbarButton>
<ToolbarButton icon="icon close" on:click={() => ($selectedMacro = null)}>Close</ToolbarButton>
<ToolbarButton icon="icon run" on:click={onExecute}>{_t('common.execute', { defaultMessage: 'Execute' })}</ToolbarButton>
<ToolbarButton icon="icon close" on:click={() => ($selectedMacro = null)}>{_t('common.close', { defaultMessage: 'Close' })}</ToolbarButton>
</div>
</div>

View File

@@ -5,6 +5,7 @@
import WidgetTitle from '../widgets/WidgetTitle.svelte';
import MacroParameters from './MacroParameters.svelte';
import { _t } from '../translations';
const selectedMacro = getContext('selectedMacro') as any;
@@ -13,23 +14,23 @@
<div class="wrapper">
<div class="section">
<WidgetTitle>Execute</WidgetTitle>
<FormStyledButton value="Execute" on:click={onExecute} />
<WidgetTitle>{_t('common.execute', { defaultMessage: 'Execute' })}</WidgetTitle>
<FormStyledButton value={_t('common.execute', { defaultMessage: 'Execute' })} on:click={onExecute} />
</div>
<div class="section">
<WidgetTitle>Parameters</WidgetTitle>
<WidgetTitle>{_t('common.parameters', { defaultMessage: 'Parameters' })}</WidgetTitle>
{#if $selectedMacro?.args && $selectedMacro?.args?.length > 0}
{#key $selectedMacro?.name}
<MacroParameters args={$selectedMacro?.args||[]} namePrefix={`${$selectedMacro?.name}#`} />
{/key}
{:else}
<div class="m-1">This macro has no parameters</div>
<div class="m-1">{_t('datagrid.macros.noParameters', { defaultMessage: 'This macro has no parameters' })}</div>
{/if}
</div>
<div class="section">
<WidgetTitle>Description</WidgetTitle>
<WidgetTitle>{_t('common.description', { defaultMessage: 'Description' })}</WidgetTitle>
<div class="m-1">{$selectedMacro?.description}</div>
</div>
</div>

View File

@@ -8,6 +8,7 @@
import SearchBoxWrapper from '../elements/SearchBoxWrapper.svelte';
import SearchInput from '../elements/SearchInput.svelte';
import macros from './macros';
import { _t } from '../translations';
let filter = '';
export let managerSize;
@@ -16,7 +17,7 @@
<ManagerInnerContainer width={managerSize}>
<SearchBoxWrapper>
<SearchInput placeholder="Search macros" bind:value={filter} />
<SearchInput placeholder={_t('datagrid.searchMacros', { defaultMessage: "Search macros"})} bind:value={filter} />
</SearchBoxWrapper>
<AppObjectList
list={_.sortBy(macros, 'title').filter(x => (macroCondition ? macroCondition(x) : true))}

View File

@@ -1,37 +1,39 @@
import { __t } from '../translations';
const macros = [
{
title: 'Remove diacritics',
title: __t('datagrid.macros.removeDiacritics', { defaultMessage: 'Remove diacritics' }),
name: 'removeDiacritics',
group: 'Text',
description: 'Removes diacritics from selected cells',
group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }),
description: __t('datagrid.macros.removeDiacriticsDescription', { defaultMessage: 'Removes diacritics from selected cells' }),
type: 'transformValue',
code: `return modules.lodash.deburr(value)`,
},
{
title: 'Search & replace text',
title: __t('datagrid.macros.searchReplaceText', { defaultMessage: 'Search & replace text' }),
name: 'stringReplace',
group: 'Text',
description: 'Search & replace text or regular expression',
group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }),
description: __t('datagrid.macros.searchReplaceTextDescription', { defaultMessage: 'Search & replace text or regular expression' }),
type: 'transformValue',
args: [
{
type: 'text',
label: 'Find',
label: __t('datagrid.macros.searchReplaceTextFind', { defaultMessage: 'Find' }),
name: 'find',
},
{
type: 'text',
label: 'Replace with',
label: __t('datagrid.macros.searchReplaceTextReplaceWith', { defaultMessage: 'Replace with' }),
name: 'replace',
},
{
type: 'checkbox',
label: 'Case sensitive',
label: __t('datagrid.macros.searchReplaceTextCaseSensitive', { defaultMessage: 'Case sensitive' }),
name: 'caseSensitive',
},
{
type: 'checkbox',
label: 'Regular expression',
label: __t('datagrid.macros.searchReplaceTextIsRegex', { defaultMessage: 'Regular expression' }),
name: 'isRegex',
},
],
@@ -42,16 +44,16 @@ return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace
`,
},
{
title: 'Change text case',
title: __t('datagrid.macros.changeTextCase', { defaultMessage: 'Change text case' }),
name: 'changeTextCase',
group: 'Text',
description: 'Uppercase, lowercase and other case functions',
group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }),
description: __t('datagrid.macros.changeTextCaseDescription', { defaultMessage: 'Uppercase, lowercase and other case functions' }),
type: 'transformValue',
args: [
{
type: 'select',
options: ['toUpper', 'toLower', 'lowerCase', 'upperCase', 'kebabCase', 'snakeCase', 'camelCase', 'startCase'],
label: 'Type',
label: __t('datagrid.macros.changeTextCaseType', { defaultMessage: 'Type' }),
name: 'type',
default: 'toUpper',
},
@@ -59,81 +61,81 @@ return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace
code: `return modules.lodash[args.type](value)`,
},
{
title: 'Pad left',
title: __t('datagrid.macros.padLeft', { defaultMessage: 'Pad left' }),
name: 'padLeft',
group: 'Text',
group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }),
args: [
{
type: 'text',
label: 'Character',
label: __t('datagrid.macros.padCharacter', { defaultMessage: 'Character' }),
name: 'character',
default: '0',
},
{
type: 'text',
label: 'Length',
label: __t('datagrid.macros.padLength', { defaultMessage: 'Length' }),
name: 'length',
default: '3',
},
],
description:
'Returns string of a specified length in which the beginning of the current string is padded with spaces or other character',
__t('datagrid.macros.padLeftDescription', { defaultMessage: 'Returns string of a specified length in which the beginning of the current string is padded with spaces or other character' }),
type: 'transformValue',
code: `return modules.lodash.padStart(value, +args.length, args.character)`,
},
{
title: 'Pad right',
title: __t('datagrid.macros.padRight', { defaultMessage: 'Pad right' }),
name: 'padRight',
group: 'Text',
group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }),
args: [
{
type: 'text',
label: 'Character',
label: __t('datagrid.macros.padCharacter', { defaultMessage: 'Character' }),
name: 'character',
default: '0',
},
{
type: 'text',
label: 'Length',
label: __t('datagrid.macros.padLength', { defaultMessage: 'Length' }),
name: 'length',
default: '3',
},
],
description:
'Returns string of a specified length in which the end of the current string is padded with spaces or other character',
__t('datagrid.macros.padRightDescription', { defaultMessage: 'Returns string of a specified length in which the end of the current string is padded with spaces or other character' }),
type: 'transformValue',
code: `return modules.lodash.padEnd(value, +args.length, args.character)`,
},
{
title: 'Trim',
title: __t('datagrid.macros.trim', { defaultMessage: 'Trim' }),
name: 'trim',
group: 'Text',
description: 'Removes leading and trailing whitespace ',
group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }),
description: __t('datagrid.macros.trimDescription', { defaultMessage: 'Removes leading and trailing whitespace' }),
type: 'transformValue',
code: `return modules.lodash.trim(value)`,
},
{
title: 'Row index',
title: __t('datagrid.macros.rowIndex', { defaultMessage: 'Row index' }),
name: 'rowIndex',
group: 'Tools',
description: 'Index of row from 1 (autoincrement)',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.rowIndexDescription', { defaultMessage: 'Index of row from 1 (autoincrement)' }),
type: 'transformValue',
code: `return rowIndex + 1`,
},
{
title: 'Generate UUID',
title: __t('datagrid.macros.generateUUID', { defaultMessage: 'Generate UUID' }),
name: 'uuidv1',
group: 'Tools',
description: 'Generate unique identifier',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.generateUUIDDescription', { defaultMessage: 'Generate unique identifier' }),
type: 'transformValue',
args: [
{
type: 'select',
options: [
{ value: 'uuidv1', name: 'V1 - from timestamp' },
{ value: 'uuidv4', name: 'V4 - random generated' },
{ value: 'uuidv4', name: 'V4 - random generated'},
],
label: 'Version',
label: __t('datagrid.macros.version', { defaultMessage: 'Version' }),
name: 'version',
default: 'uuidv1',
},
@@ -141,26 +143,26 @@ return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace
code: `return modules[args.version]()`,
},
{
title: 'Convert to integer',
title: __t('datagrid.macros.toInt', { defaultMessage: 'Convert to integer' }),
name: 'toInt',
group: 'Tools',
description: 'Converts to integral number',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.toIntDescription', { defaultMessage: 'Converts to integral number' }),
type: 'transformValue',
code: `return modules.lodash.isNaN(parseInt(value)) ? null : parseInt(value)`,
},
{
title: 'Convert to number',
title: __t('datagrid.macros.toNumber', { defaultMessage: 'Convert to number' }),
name: 'toNumber',
group: 'Tools',
description: 'Converts to number',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.toNumberDescription', { defaultMessage: 'Converts to number' }),
type: 'transformValue',
code: `return modules.lodash.isNaN(parseFloat(value)) ? null : parseFloat(value)`,
},
{
title: 'Convert to boolean',
title: __t('datagrid.macros.toBoolean', { defaultMessage: 'Convert to boolean' }),
name: 'toBoolean',
group: 'Tools',
description: 'Converts to boolean',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.toBooleanDescription', { defaultMessage: 'Converts to boolean' }),
type: 'transformValue',
code: `
if (modules.lodash.isString(value)) {
@@ -176,10 +178,10 @@ return !!value;
`,
},
{
title: 'Convert to string',
title: __t('datagrid.macros.toString', { defaultMessage: 'Convert to string' }),
name: 'toString',
group: 'Tools',
description: 'Converts to string',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.toStringDescription', { defaultMessage: 'Converts to string' }),
type: 'transformValue',
code: `
if (value==null) return null;
@@ -188,15 +190,15 @@ return !!value;
`,
},
{
title: 'Current date',
title: __t('datagrid.macros.currentDate', { defaultMessage: 'Current date' }),
name: 'currentDate',
group: 'Tools',
description: 'Gets current date',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.currentDateDescription', { defaultMessage: 'Gets current date' }),
type: 'transformValue',
args: [
{
type: 'text',
label: 'Format',
label: __t('datagrid.macros.format', { defaultMessage: 'Format' }),
name: 'format',
default: 'YYYY-MM-DD HH:mm:ss',
},
@@ -204,10 +206,10 @@ return !!value;
code: `return modules.moment().format(args.format)`,
},
{
title: 'Duplicate columns',
title: __t('datagrid.macros.duplicateColumns', { defaultMessage: 'Duplicate columns' }),
name: 'duplicateColumns',
group: 'Tools',
description: 'Duplicate selected columns',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.duplicateColumnsDescription', { defaultMessage: 'Duplicate selected columns' }),
type: 'transformRow',
code: `
return {
@@ -218,22 +220,22 @@ return !!value;
args: [
{
type: 'text',
label: 'Prefix',
label: __t('datagrid.macros.prefix', { defaultMessage: 'Prefix' }),
name: 'prefix',
},
{
type: 'text',
label: 'Postfix',
label: __t('datagrid.macros.postfix', { defaultMessage: 'Postfix' }),
name: 'postfix',
default: '_copy',
},
],
},
{
title: 'Split columns',
title: __t('datagrid.macros.splitColumns', { defaultMessage: 'Split columns' }),
name: 'splitColumns',
group: 'Tools',
description: 'Split selected columns',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.splitColumnsDescription', { defaultMessage: 'Split selected columns' }),
type: 'transformRow',
code: `
const res = {...row};
@@ -252,22 +254,22 @@ return !!value;
args: [
{
type: 'text',
label: 'Delimiter',
label: __t('datagrid.macros.delimiter', { defaultMessage: 'Delimiter' }),
name: 'delimiter',
default: ',',
},
],
},
{
title: 'Calculation',
title: __t('datagrid.macros.calculation', { defaultMessage: 'Calculation' }),
name: 'calculation',
group: 'Tools',
description: 'Custom expression. Use row.column_name for accessing column values, value for original value',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.calculationDescription', { defaultMessage: 'Custom expression. Use row.column_name for accessing column values, value for original value' }),
type: 'transformValue',
args: [
{
type: 'text',
label: 'Expression',
label: __t('datagrid.macros.expression', { defaultMessage: 'Expression' }),
name: 'expression',
default: 'value',
},
@@ -275,10 +277,10 @@ return !!value;
code: `return eval(args.expression);`,
},
{
title: 'Extract date fields',
title: __t('datagrid.macros.extractDateFields', { defaultMessage: 'Extract date fields' }),
name: 'extractDateFields',
group: 'Tools',
description: 'Extract yaear, month, day and other date/time fields from selection and adds it as new columns',
group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }),
description: __t('datagrid.macros.extractDateFieldsDescription', { defaultMessage: 'Extract year, month, day and other date/time fields from selection and adds it as new columns' }),
type: 'transformRow',
code: `
let mom = null;
@@ -311,37 +313,37 @@ return !!value;
args: [
{
type: 'text',
label: 'Year name',
label: __t('datagrid.macros.yearName', { defaultMessage: 'Year name' }),
name: 'year',
default: 'year',
},
{
type: 'text',
label: 'Month name',
label: __t('datagrid.macros.monthName', { defaultMessage: 'Month name' }) ,
name: 'month',
default: 'month',
},
{
type: 'text',
label: 'Day name',
label: __t('datagrid.macros.dayName', { defaultMessage: 'Day name' }),
name: 'day',
default: 'day',
},
{
type: 'text',
label: 'Hour name',
label: __t('datagrid.macros.hourName', { defaultMessage: 'Hour name' }),
name: 'hour',
default: 'hour',
},
{
type: 'text',
label: 'Minute name',
label: __t('datagrid.macros.minuteName', { defaultMessage: 'Minute name' }),
name: 'minute',
default: 'minute',
},
{
type: 'text',
label: 'Second name',
label: __t('datagrid.macros.secondName', { defaultMessage: 'Second name' }),
name: 'second',
default: 'second',
},

View File

@@ -9,6 +9,8 @@
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { commandsCustomized } from '../stores';
import { _t } from '../translations';
import _ from 'lodash';
export let tabs;
export let onConfirm;
@@ -27,10 +29,10 @@
<FormProvider>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Confirm close tabs</svelte:fragment>
<svelte:fragment slot="header">{_t('datagrid.closeTabs.header', { defaultMessage: 'Confirm close tabs' })}</svelte:fragment>
<div>
Following files are modified, really close tabs? After closing, you could reopen them in history
{_t('datagrid.closeTabs.modifiedFiles', { defaultMessage: 'Following files are modified, really close tabs? After closing, you could reopen them in history' })}
<FontIcon icon="icon history" />
widget
</div>
@@ -41,7 +43,7 @@
<svelte:fragment slot="footer">
<FormSubmit
value="Close tabs"
value={_t('datagrid.closeTabs.close', { defaultMessage: 'Close tabs' })}
on:click={() => {
closeCurrentModal();
onConfirm();
@@ -49,7 +51,7 @@
/>
<FormStyledButton
type="button"
value="Cancel"
value={_t('common.cancel', { defaultMessage: 'Cancel' })}
on:click={() => {
closeCurrentModal();
onCancel();

View File

@@ -11,6 +11,7 @@
import KeyboardModal from './KeyboardModal.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, showModal } from './modalTools';
import { _t } from '../translations';
export let command;
@@ -23,16 +24,16 @@
<FormProviderCore {values}>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Configure commmand</svelte:fragment>
<svelte:fragment slot="header">{_t('commandModal.configure', { defaultMessage: 'Configure command' })}</svelte:fragment>
<FormTextField label="Category" name="category" disabled />
<FormTextField label="Name" name="name" disabled />
<FormTextField label={_t('commandModal.category', { defaultMessage: 'Category' })} name="category" disabled />
<FormTextField label={_t('commandModal.name', { defaultMessage: 'Name' })} name="name" disabled />
<div class="row">
<FormTextField label="Keyboard shortcut" name="keyText" templateProps={{ noMargin: true }} focused />
<FormTextField label={_t('commandModal.keyboardShortcut', { defaultMessage: 'Keyboard shortcut' })} name="keyText" templateProps={{ noMargin: true }} focused />
<FormStyledButton
type="button"
value="Keyboard"
value={_t('commandModal.keyboard', { defaultMessage: 'Keyboard' })}
on:click={handleKeyboard}
data-testid="CommandModal_keyboardButton"
/>
@@ -56,7 +57,7 @@
/>
<FormStyledButton
type="button"
value="Reset"
value={_t('common.reset', { defaultMessage: 'Reset' })}
on:click={() => {
closeCurrentModal();
apiCall('config/update-settings', {
@@ -64,7 +65,7 @@
});
}}
/>
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment>
</ModalBase>
</FormProviderCore>

View File

@@ -13,6 +13,7 @@
import { parseCellValue, safeJsonParse, stringifyCellValue } from 'dbgate-tools';
import { showSnackbarError } from '../utility/snackbar';
import ErrorMessageModal from './ErrorMessageModal.svelte';
import { _t } from '../translations';
export let onSave;
export let value;
@@ -49,14 +50,14 @@
if (parsed) {
textValue = JSON.stringify(parsed, null, 2);
} else {
showModal(ErrorMessageModal, { message: 'Not valid JSON' });
showModal(ErrorMessageModal, { message: _t('dataGrid.formatJson.invalid', { defaultMessage: 'Not valid JSON' }) });
}
}
</script>
<FormProvider>
<ModalBase {...$$restProps}>
<div slot="header">Edit cell value</div>
<div slot="header">{_t('dataGrid.editCellValue', { defaultMessage: 'Edit cell value' })}</div>
<div class="editor">
<AceEditor bind:value={textValue} bind:this={editor} onKeyDown={handleKeyDown} mode={syntaxMode} />
@@ -72,21 +73,21 @@
closeCurrentModal();
}}
/>
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</div>
<div>
<FormStyledButton type="button" value="Format JSON" on:click={handleFormatJson} />
<FormStyledButton type="button" skipWidth={true} value={_t('dataGrid.formatJson', { defaultMessage: 'Format JSON' })} on:click={handleFormatJson} />
Code highlighting:
{_t('dataGrid.codeHighlighting', { defaultMessage: 'Code highlighting:' })}
<SelectField
isNative
value={syntaxMode}
on:change={e => (syntaxMode = e.detail)}
options={[
{ value: 'text', label: 'None (raw text)' },
{ value: 'text', label: _t('dataGrid.codeHighlighting.none', { defaultMessage: 'None (raw text)' }) },
{ value: 'json', label: 'JSON' },
{ value: 'html', label: 'HTML' },
{ value: 'html', label: 'HTML'},
{ value: 'xml', label: 'XML' },
]}
/>

View File

@@ -6,8 +6,9 @@
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let title = 'Error';
export let title = _t('common.error', { defaultMessage: 'Error' });
export let message;
export let showAsCode = false;
</script>
@@ -30,7 +31,7 @@
{/if}
<div slot="footer">
<FormSubmit value="Close" on:click={closeCurrentModal} data-testid="ErrorMessageModal_closeButton" />
<FormSubmit value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} data-testid="ErrorMessageModal_closeButton" />
</div>
</ModalBase>
</FormProvider>

View File

@@ -6,6 +6,7 @@
import FormTextField from '../forms/FormTextField.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let header;
export let value;
@@ -29,7 +30,7 @@
<svelte:fragment slot="footer">
<FormSubmit value="OK" on:click={e => handleSubmit(e.detail)} data-testid="InputTextModal_ok" />
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} data-testid="InputTextModal_cancel" />
<FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} data-testid="InputTextModal_cancel" />
</svelte:fragment>
</ModalBase>
</FormProvider>

View File

@@ -5,6 +5,7 @@
import keycodes from '../utility/keycodes';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let onChange;
let value;
@@ -38,7 +39,7 @@
</script>
<ModalBase {...$$restProps} simple>
<div class="mb-2">Show desired key combination and press ENTER</div>
<div class="mb-2">_{_t('commandModal.showKeyCombination', { defaultMessage: 'Show desired key combination and press ENTER' })}</div>
<div class="largeFormMarker">
<TextField on:keydown={handleKeyDown} bind:value focused />
</div>

View File

@@ -10,6 +10,7 @@
import ErrorMessageModal from './ErrorMessageModal.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, showModal } from './modalTools';
import { _t } from '../translations';
export let driver;
export let dbid;
@@ -44,14 +45,14 @@
<FormProvider initialValues={{ name: '' }}>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">
Create {driver?.collectionSingularLabel ?? 'collection/container'}
{_t('dbObject.createCollection', { defaultMessage: 'Create collection/container'})}
</svelte:fragment>
<FormArgumentList args={driver?.newCollectionFormParams} />
<svelte:fragment slot="footer">
<FormSubmit value="OK" on:click={e => handleSubmit(e.detail)} disabled={isSaving} />
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</svelte:fragment>
</ModalBase>
</FormProvider>

View File

@@ -7,6 +7,7 @@
import { isProApp } from '../utility/proTools';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let multiTabIndex = undefined;
@@ -14,8 +15,8 @@
{
icon: 'icon sql-file',
colorClass: 'color-icon-blue',
title: 'Query',
description: 'SQL query editor',
title: _t('common.query', { defaultMessage: 'Query' }),
description: _t('common.queryEditor', { defaultMessage: 'SQL query editor' }),
action: () => {
newQuery({ multiTabIndex });
},
@@ -25,47 +26,47 @@
{
icon: 'icon connection',
colorClass: 'color-icon-yellow',
title: 'Connection',
description: 'Database connection stored locally',
title: _t('common.connection', { defaultMessage: 'Connection' }),
description: _t('newObject.connectionLocal', { defaultMessage: 'Database connection stored locally' }),
command: 'new.connection',
changeWidget: 'database',
testid: 'NewObjectModal_connection',
disabledMessage: 'You are not allowed to create new connections',
disabledMessage: _t('newObject.connectionLocalDisabled', { defaultMessage: 'You are not allowed to create new connections' }),
},
{
icon: 'icon cloud-connection',
colorClass: 'color-icon-blue',
title: 'Connection on Cloud',
description: 'Database connection stored on DbGate Cloud',
title: _t('common.connectionOnCloud', { defaultMessage: 'Connection on Cloud' }),
description: _t('newObject.connectionOnCloudDescription', { defaultMessage: 'Database connection stored on DbGate Cloud' }),
command: 'new.connectionOnCloud',
changeWidget: 'cloud-private',
testid: 'NewObjectModal_connectionOnCloud',
disabledMessage: 'For creating connections on DbGate Cloud, you need to be logged in',
disabledMessage: _t('newObject.connectionOnCloudDisabled', { defaultMessage: 'For creating connections on DbGate Cloud, you need to be logged in' }),
},
{
icon: 'icon query-design',
colorClass: 'color-icon-red',
title: 'Query Designer',
description: 'Design SQL queries visually',
title: _t('common.queryDesigner', { defaultMessage: 'Query Designer' }),
description: _t('newObject.queryDesignerDescription', { defaultMessage: 'Design SQL queries visually' }),
command: 'new.queryDesign',
testid: 'NewObjectModal_queryDesign',
disabledMessage: 'Query Designer is not available for current database',
disabledMessage: _t('newObject.queryDesignerDisabled', { defaultMessage: 'Query Designer is not available for current database' }),
isProFeature: true,
},
{
icon: 'icon diagram',
colorClass: 'color-icon-blue',
title: 'ER Diagram',
description: 'Visualize database structure',
title: _t('common.erDiagram', { defaultMessage: 'ER Diagram' }),
description: _t('newObject.erDiagramDescription', { defaultMessage: 'Visualize database structure' }),
command: 'new.diagram',
testid: 'NewObjectModal_diagram',
disabledMessage: 'ER Diagram is not available for current database',
disabledMessage: _t('newObject.erDiagramDisabled', { defaultMessage: 'ER Diagram is not available for current database' }),
},
{
icon: 'icon perspective',
colorClass: 'color-icon-yellow',
title: 'Perspective',
description: 'Join complex data from multiple databases',
title: _t('common.perspective', { defaultMessage: 'Perspective' }),
description: _t('newObject.perspectiveDescription', { defaultMessage: 'Join complex data from multiple databases' }),
command: 'new.perspective',
testid: 'NewObjectModal_perspective',
isProFeature: true,
@@ -73,55 +74,56 @@
{
icon: 'icon table',
colorClass: 'color-icon-blue',
title: 'Table',
description: 'Create table in the current database',
title: _t('common.table', { defaultMessage: 'Table' }),
description: _t('newObject.tableDescription', { defaultMessage: 'Create table in the current database' }),
command: 'new.table',
testid: 'NewObjectModal_table',
disabledMessage: 'Table creation is not available for current database',
disabledMessage: _t('newObject.tableDisabled', { defaultMessage: 'Table creation is not available for current database' }),
},
{
icon: 'icon sql-generator',
colorClass: 'color-icon-green',
title: 'SQL Generator',
description: 'Generate SQL scripts for database objects',
title: _t('common.sqlGenerator', { defaultMessage: 'SQL Generator' }),
description: _t('newObject.sqlGeneratorDescription', { defaultMessage: 'Generate SQL scripts for database objects' }),
command: 'sql.generator',
testid: 'NewObjectModal_sqlGenerator',
disabledMessage: 'SQL Generator is not available for current database',
disabledMessage: _t('newObject.sqlGeneratorDisabled', { defaultMessage: 'SQL Generator is not available for current database' }),
},
{
icon: 'icon export',
colorClass: 'color-icon-green',
title: 'Export database',
description: 'Export to file like CSV, JSON, Excel, or other DB',
title: _t('common.exportDatabase', { defaultMessage: 'Export database' }),
description: _t('newObject.exportDescription', { defaultMessage: 'Export to file like CSV, JSON, Excel, or other DB' }),
command: 'database.export',
isProFeature: true,
testid: 'NewObjectModal_databaseExport',
disabledMessage: 'Export is not available for current database',
disabledMessage: _t('newObject.exportDisabled', { defaultMessage: 'Export is not available for current database' }),
},
{
icon: 'icon compare',
colorClass: 'color-icon-red',
title: 'Compare database',
description: 'Compare database schemas',
title: _t('common.compare', { defaultMessage: 'Compare database' }),
description: _t('newObject.compareDescription', { defaultMessage: 'Compare database schemas' }),
command: 'database.compare',
testid: 'NewObjectModal_databaseCompare',
disabledMessage: 'Database comparison is not available for current database',
disabledMessage: _t('newObject.compareDisabled', { defaultMessage: 'Database comparison is not available for current database' }),
isProFeature: true,
},
{
icon: 'icon ai',
colorClass: 'color-icon-blue',
title: 'Database Chat',
description: 'Chat with your database using AI',
title: _t('common.databaseChat', { defaultMessage: 'Database Chat' }),
description: _t('newObject.databaseChatDescription', { defaultMessage: 'Chat with your database using AI' }),
command: 'database.chat',
isProFeature: true,
disabledMessage: 'Database chat is not available for current database',
disabledMessage: _t('newObject.databaseChatDisabled', { defaultMessage: 'Database chat is not available for current database' }),
testid: 'NewObjectModal_databaseChat',
},
];
</script>
<ModalBase simplefix {...$$restProps}>
<div class="create-header">Create new</div>
<div class="create-header">{_t('common.createNew', { defaultMessage: 'Create new' })}</div>
<div class="wrapper">
{#each NEW_ITEMS as item}
{@const enabled = item.command

View File

@@ -10,6 +10,7 @@
import { closeCurrentModal } from './modalTools';
import FormRadioGroupItem from '../forms/FormRadioGroupItem.svelte';
import FormValues from '../forms/FormValues.svelte';
import { _t } from '../translations';
export let condition1;
export let onFilter;
@@ -44,10 +45,10 @@
<FormProvider initialValues={{ condition1, condition2: '=', joinOperator: ' ' }} template={FormFieldTemplateLarge}>
<ModalBase {...$$restProps}>
<div slot="header">Set filter</div>
<div slot="header">{_t('filter.setFilter', {defaultMessage: 'Set filter'})}</div>
<div class="largeFormMarker">
<div class="row">Show rows where</div>
<div class="row">{_t('filter.showRowsWhere', {defaultMessage: 'Show rows where'})}</div>
<div class="row">
<div class="col-6 mr-1">
<SetFilterModal_Select {filterBehaviour} name="condition1" />
@@ -62,9 +63,9 @@
</div>
<div class="row">
<FormRadioGroupItem name="joinOperator" value=" " text="And" />
<FormRadioGroupItem name="joinOperator" value=" " text={_t('filter.and', {defaultMessage: 'And'})} />
{#if !filterBehaviour.disableOr}
<FormRadioGroupItem name="joinOperator" value="," text="Or" />
<FormRadioGroupItem name="joinOperator" value="," text={_t('filter.or', {defaultMessage: 'Or'})} />
{/if}
</div>
@@ -84,7 +85,7 @@
<div slot="footer">
<FormSubmit value="OK" on:click={handleOk} />
<FormButton type="button" value="Close" on:click={closeCurrentModal} />
<FormButton type="button" value={_t('common.close', {defaultMessage: 'Close'})} on:click={closeCurrentModal} />
</div>
</ModalBase>
</FormProvider>

View File

@@ -1,56 +1,57 @@
<script lang="ts">
import _ from 'lodash';
import FormSelectFieldRaw from '../forms/FormSelectFieldRaw.svelte';
import { _t } from '../translations';
export let name;
export let filterBehaviour;
function getOptions() {
const res = [];
if (filterBehaviour.supportEquals) {
res.push({ value: '=', label: 'equals' }, { value: '<>', label: 'does not equal' });
}
res.push({ value: '=', label: _t('filter.modal.equals', {defaultMessage: 'equals'}) }, { value: '<>', label: _t('filter.modal.doesNotEqual', {defaultMessage: 'does not equal'}) });
};
if (filterBehaviour.supportStringInclusion) {
res.push(
{ value: '+', label: 'contains' },
{ value: '~', label: 'does not contain' },
{ value: '^', label: 'begins with' },
{ value: '!^', label: 'does not begin with' },
{ value: '$', label: 'ends with' },
{ value: '!$', label: 'does not end with' }
{ value: '+', label: _t('filter.modal.contains', {defaultMessage: 'contains'}) },
{ value: '~', label: _t('filter.modal.doesNotContain', {defaultMessage: 'does not contain'}) },
{ value: '^', label: _t('filter.modal.beginsWith', {defaultMessage: 'begins with'}) },
{ value: '!^', label: _t('filter.modal.doesNotBeginWith', {defaultMessage: 'does not begin with'}) },
{ value: '$', label: _t('filter.modal.endsWith', {defaultMessage: 'ends with'}) },
{ value: '!$', label: _t('filter.modal.doesNotEndWith', {defaultMessage: 'does not end with'}) }
);
}
if (filterBehaviour.supportNumberLikeComparison) {
res.push(
{ value: '<', label: 'is smaller' },
{ value: '>', label: 'is greater' },
{ value: '<=', label: 'is smaller or equal' },
{ value: '>=', label: 'is greater or equal' }
{ value: '<', label: _t('filter.isSmaller', {defaultMessage: 'is smaller'}) },
{ value: '>', label: _t('filter.isGreater', {defaultMessage: 'is greater'}) },
{ value: '<=', label: _t('filter.isSmallerOrEqual', {defaultMessage: 'is smaller or equal'}) },
{ value: '>=', label: _t('filter.isGreaterOrEqual', {defaultMessage: 'is greater or equal'}) }
);
}
if (filterBehaviour.supportDatetimeComparison) {
res.push(
{ value: '<', label: 'is before' },
{ value: '>', label: 'is after' },
{ value: '<=', label: 'is before or equal' },
{ value: '>=', label: 'is after or equal' }
{ value: '<', label: _t('filter.isBefore', {defaultMessage: 'is before'}) },
{ value: '>', label: _t('filter.isAfter', {defaultMessage: 'is after'}) },
{ value: '<=', label: _t('filter.isBeforeOrEqual', {defaultMessage: 'is before or equal'}) },
{ value: '>=', label: _t('filter.isAfterOrEqual', {defaultMessage: 'is after or equal'}) }
);
}
if (filterBehaviour.supportNullTesting) {
res.push({ value: 'NULL', label: 'is NULL' }, { value: 'NOT NULL', label: 'is not NULL' });
res.push({ value: 'NULL', label: _t('filter.modal.isNull', {defaultMessage: 'is NULL'}) }, { value: 'NOT NULL', label: _t('filter.modal.isNotNull', {defaultMessage: 'is not NULL'}) });
}
if (filterBehaviour.supportExistsTesting) {
res.push({ value: 'EXISTS', label: 'field exists' }, { value: 'NOT EXISTS', label: 'field does not exist' });
res.push({ value: 'EXISTS', label: _t('filter.modal.fieldExists', {defaultMessage: 'field exists'}) }, { value: 'NOT EXISTS', label: _t('filter.modal.fieldDoesNotExist', {defaultMessage: 'field does not exist'}) });
}
if (filterBehaviour.supportSqlCondition) {
res.push(
{ value: 'sql', label: 'SQL condition' },
{ value: 'sqlRight', label: 'SQL condition - right side only' }
{ value: 'sql', label: _t('filter.modal.sqlCondition', {defaultMessage: 'SQL condition'}) },
{ value: 'sqlRight', label: _t('filter.modal.sqlConditionRight', {defaultMessage: 'SQL condition - right side only'}) }
);
}

View File

@@ -0,0 +1,59 @@
<script lang='ts'>
import _ from 'lodash';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import newQuery from '../query/newQuery';
import SqlEditor from '../query/SqlEditor.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let sql;
export let onConfirm;
export let engine = null;
</script>
<ModalBase {...$$restProps}>
<div slot="header">SQL Script</div>
<div class="editor">
<SqlEditor {engine} value={sql} readOnly />
</div>
<div slot="footer">
<FormStyledButton
type="button"
value={_t('common.close', { defaultMessage: 'Close' })}
on:click={closeCurrentModal}
data-testid="ShowSqlModal_closeButton"
/>
<FormStyledButton
type="button"
value="Open script"
on:click={() => {
newQuery({
initialData: sql,
});
closeCurrentModal();
}}
data-testid="ShowSqlModal_openScriptButton"
/>
</div>
</ModalBase>
<style>
.editor {
position: relative;
height: 30vh;
width: 40vw;
}
.form-margin {
margin: var(--dim-large-form-margin);
}
.flex-wrap {
flex-wrap: wrap;
}
</style>

View File

@@ -16,6 +16,7 @@
import { apiCall } from '../utility/api';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import { base64ToHex } from 'dbgate-tools';
import { _t } from '../translations';
export let onConfirm;
export let conid;
@@ -74,15 +75,15 @@
<FormProvider>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Choose value from {field}</svelte:fragment>
<svelte:fragment slot="header">{_t('dataGrid.chooseValue', { defaultMessage: 'Choose value from {field}', values: { field } })}</svelte:fragment>
<!-- <FormTextField name="search" label='Search' placeholder="Search" bind:value={search} /> -->
<div class="largeFormMarker">
<SearchInput placeholder="Search" bind:value={search} isDebounced />
<SearchInput placeholder={_t('common.search', { defaultMessage: 'Search' })} bind:value={search} isDebounced />
</div>
{#if isLoading}
<LoadingInfo message="Loading data" />
<LoadingInfo message={_t('common.loadingData', { defaultMessage: 'Loading data' })} />
{/if}
{#if !isLoading && rows}
@@ -112,7 +113,7 @@
},
{
fieldName: 'value',
header: 'Value',
header: _t('dataGrid.value', { defaultMessage: 'Value' }),
formatter: row => (row.value == null ? '(NULL)' : row.value?.$binary?.base64 ? base64ToHex(row.value.$binary.base64) : row.value),
},
]}
@@ -147,7 +148,7 @@
}}
/>
{/if}
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment>
</ModalBase>
</FormProvider>

View File

@@ -75,7 +75,7 @@
--token-base: #303030;
--token-text: #ddd;
--token-keyword: white;
--token-keyword: #096dd9;
--token-selector-tag: white;
--token-literal: white;
--token-section: white;

View File

@@ -4,6 +4,8 @@
import RowsFilterSwitcher from '../forms/RowsFilterSwitcher.svelte';
import SearchInput from '../elements/SearchInput.svelte';
import { filterName } from 'dbgate-tools';
import InlineButton from '../buttons/InlineButton.svelte';
import FontIcon from '../icons/FontIcon.svelte';
export let items: any[];
export let showProcedure = false;
@@ -12,8 +14,10 @@
export let startLine = 0;
export let onMessageClick = null;
export let onExplainError = null;
export let engine = null;
export let filter = '';
export let onClear = null;
$: time0 = items[0] && new Date(items[0].time).getTime();
@@ -37,6 +41,17 @@
<div class="main">
<div class="topbar">
{#if onClear}
<InlineButton
icon="img clear"
on:click={() => {
onClear();
}}
>
<FontIcon icon="icon delete" padRight />
Clear
</InlineButton>
{/if}
<RowsFilterSwitcher
icon="img debug"
label="Debug"
@@ -92,6 +107,7 @@
previousRow={index > 0 ? items[index - 1] : null}
{onMessageClick}
{onExplainError}
{engine}
/>
{/each}
</table>

View File

@@ -17,6 +17,10 @@
import FontIcon from '../icons/FontIcon.svelte';
import { plusExpandIcon } from '../icons/expandIcons';
import InlineButton from '../buttons/InlineButton.svelte';
import SqlHighlighter from '../elements/SqlHighlighter.svelte';
import { showModal } from '../modals/modalTools';
import ShowSqlModal from '../modals/ShowSqlModal.svelte';
import openNewTab from '../utility/openNewTab';
export let row;
export let index;
@@ -29,6 +33,7 @@
export let previousRow = null;
export let onMessageClick = null;
export let onExplainError = null;
export let engine = null;
let isExpanded = false;
</script>
@@ -55,10 +60,39 @@
}}><FontIcon icon="img ai" /> Explain</InlineButton
>
{/if}
{#if row.jslid}
<InlineButton
title="Show data"
inlineBlock
data-testid={`MessageViewRow-showDataButton-${index}`}
on:click={e => {
openNewTab({
title: 'Query data #',
icon: 'img query-data',
tabComponent: 'ArchiveFileTab',
props: {
jslid: row.jslid,
},
});
}}><FontIcon icon="img query-data" /> Show Data</InlineButton
>
{/if}
{#if row.sql}
<SqlHighlighter
code={row.sql.substring(0, 100) + (row.sql.length > 100 ? '...' : '')}
inline
onClick={() => {
showModal(ShowSqlModal, {
sql: row.sql,
engine,
});
}}
/>
{/if}
</td>
<td>{moment(row.time).format('HH:mm:ss')}</td>
<td>{formatDuration(new Date(row.time).getTime() - time0)}</td>
<td> {previousRow ? formatDuration(new Date(row.time).getTime() - new Date(previousRow.time).getTime()) : 'n/a'}</td>
<td>{previousRow ? formatDuration(new Date(row.time).getTime() - new Date(previousRow.time).getTime()) : 'n/a'}</td>
{#if showProcedure}
<td>{row.procedure || ''}</td>
{/if}

View File

@@ -12,12 +12,13 @@
export let showLine = false;
export let showCaller = false;
export let eventName;
export let executeNumber;
export let executeNumber = null;
export let showNoMessagesAlert = false;
export let startLine = 0;
export let onChangeErrors = null;
export let onMessageClick = null;
export let onExplainError = null;
export let engine = null;
const cachedMessagesRef = createRef([]);
const lastErrorMessageCountRef = createRef(0);
@@ -43,6 +44,11 @@
return () => {};
});
function handleClearMessages() {
cachedMessagesRef.set([]);
displayedMessages = [];
}
$: {
if (executeNumber >= 0) {
displayedMessages = [];
@@ -79,5 +85,7 @@
{showCaller}
{startLine}
{onExplainError}
{engine}
onClear={executeNumber == null ? handleClearMessages : null}
/>
{/if}

View File

@@ -4,6 +4,7 @@
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormTextAreaField from '../forms/FormTextAreaField.svelte';
import FormArgumentList from '../forms/FormArgumentList.svelte';
import { _t } from '../translations';
const { values } = getFormContext();
@@ -16,8 +17,8 @@
$: advancedFields = driver?.getAdvancedConnectionFields ? driver?.getAdvancedConnectionFields() : null;
</script>
<FormTextAreaField label="Allowed databases, one per line" name="allowedDatabases" disabled={isConnected} rows={8} />
<FormTextField label="Allowed databases regular expression" name="allowedDatabasesRegex" disabled={isConnected} />
<FormTextAreaField label={_t('connection.allowedDatabases', { defaultMessage: 'Allowed databases, one per line' })} name="allowedDatabases" disabled={isConnected} rows={8} />
<FormTextField label={_t('connection.allowedDatabasesRegex', { defaultMessage: 'Allowed databases regular expression' })} name="allowedDatabasesRegex" disabled={isConnected} />
{#if advancedFields}
<FormArgumentList args={advancedFields} />

View File

@@ -87,13 +87,13 @@
</script>
<FormSelectField
label="Connection type"
label={_t('connection.type', { defaultMessage: 'Connection type' })}
name="engine"
isNative
disabled={isConnected}
data-testid="ConnectionDriverFields_connectionType"
options={[
{ label: '(select connection type)', value: '' },
{ label: _t('connection.selectType', { defaultMessage: '(select connection type)' })},
..._.sortBy(
$extensions.drivers
// .filter(driver => !driver.isElectronOnly || electron)
@@ -109,7 +109,7 @@
{#if $authTypes && driver?.showConnectionField('authType', $values, showConnectionFieldArgs) && driver?.authTypeFirst}
{#key $authTypes}
<FormSelectField
label={driver?.authTypeLabel ?? 'Authentication'}
label={driver?.authTypeLabel ?? _t('connection.authentication', { defaultMessage: 'Authentication' })}
data-testid="ConnectionDriverFields_authType"
name="authType"
isNative
@@ -125,7 +125,7 @@
{#if driver?.showConnectionField('clusterNodes', $values, showConnectionFieldArgs)}
<FormClusterNodesField
label="Cluster nodes"
label={_t('connection.clusterNodes', { defaultMessage: 'Cluster nodes' })}
name="clusterNodes"
disabled={isConnected || disabledFields.includes('clusterNodes')}
data-testid="ConnectionDriverFields_clusterNodes"
@@ -134,7 +134,7 @@
{#if driver?.showConnectionField('autoDetectNatMap', $values, showConnectionFieldArgs)}
<FormCheckboxField
label="Auto detect NAT map (use for Redis Cluster in Docker network)"
label={_t('connection.autoDetectNatMap', { defaultMessage: 'Auto detect NAT map (use for Redis Cluster in Docker network)' })}
name="autoDetectNatMap"
disabled={isConnected}
data-testid="ConnectionDriverFields_autoDetectNatMap"
@@ -144,13 +144,13 @@
{#if driver?.showConnectionField('databaseFile', $values, showConnectionFieldArgs)}
{#if electron && !driver?.dialect?.useServerDatabaseFile}
<FormElectronFileSelector
label="Database file"
label={_t('connection.databaseFile', { defaultMessage: 'Database file' })}
name="databaseFile"
disabled={isConnected || disabledFields.includes('databaseFile')}
/>
{:else}
<FormTextField
label="Database file (path on server)"
label={_t('connection.databaseFilePath', { defaultMessage: 'Database file (path on server)' })}
name="databaseFile"
disabled={isConnected || disabledFields.includes('databaseFile')}
/>
@@ -164,8 +164,8 @@
name="useDatabaseUrl"
matchValueToOption={(value, option) => !!option.value == !!value}
options={[
{ label: 'Fill database connection details', value: '', default: true },
{ label: 'Use database URL', value: '1' },
{ label: _t('connection.fillDetails', { defaultMessage: 'Fill database connection details' }), value: '', default: true },
{ label: _t('connection.useUrl', { defaultMessage: 'Use database URL' }), value: '1' },
]}
/>
</div>
@@ -173,7 +173,7 @@
{#if driver?.showConnectionField('databaseUrl', $values, showConnectionFieldArgs)}
<FormTextField
label="Database URL"
label={_t('connection.databaseUrl', { defaultMessage: 'Database URL' })}
name="databaseUrl"
data-testid="ConnectionDriverFields_databaseUrl"
placeholder={driver?.databaseUrlPlaceholder}
@@ -183,7 +183,7 @@
{#if driver?.showConnectionField('localDataCenter', $values, showConnectionFieldArgs)}
<FormTextField
label="Local DataCenter"
label={_t('connection.localDataCenter', { defaultMessage: 'Local DataCenter' })}
name="localDataCenter"
data-testid="ConnectionDriverFields_localDataCenter"
placeholder={driver?.defaultLocalDataCenter}
@@ -203,7 +203,7 @@
{#if $authTypes && driver?.showConnectionField('authType', $values, showConnectionFieldArgs) && !driver?.authTypeFirst}
{#key $authTypes}
<FormSelectField
label={driver?.authTypeLabel ?? 'Authentication'}
label={driver?.authTypeLabel ?? _t('connection.authentication', { defaultMessage: 'Authentication' })}
data-testid="ConnectionDriverFields_authType"
name="authType"
isNative
@@ -219,7 +219,7 @@
{#if driver?.showConnectionField('endpoint', $values, showConnectionFieldArgs)}
<FormTextField
label="Endpoint"
label='Endpoint'
name="endpoint"
disabled={isConnected || disabledFields.includes('endpoint')}
data-testid="ConnectionDriverFields_endpoint"
@@ -228,7 +228,7 @@
{#if driver?.showConnectionField('endpointKey', $values, showConnectionFieldArgs)}
<FormTextField
label="Key"
label={_t('connection.endpointKey', { defaultMessage: 'Key' })}
name="endpointKey"
disabled={isConnected || disabledFields.includes('endpointKey')}
data-testid="ConnectionDriverFields_endpointKey"
@@ -237,7 +237,7 @@
{#if driver?.showConnectionField('clientLibraryPath', $values, showConnectionFieldArgs)}
<FormTextField
label="Client library path"
label={_t('connection.clientLibraryPath', { defaultMessage: 'Client library path' })}
name="clientLibraryPath"
disabled={isConnected || disabledFields.includes('clientLibraryPath')}
data-testid="ConnectionDriverFields_clientLibraryPath"
@@ -248,7 +248,7 @@
<div class="row">
<div class="col-9 mr-1">
<FormTextField
label="Server"
label={_t('connection.server', { defaultMessage: 'Server' })}
name="server"
disabled={isConnected || disabledFields.includes('server')}
templateProps={{ noMargin: true }}
@@ -271,7 +271,7 @@
{#if getCurrentConfig().isDocker}
<div class="row">
<FontIcon icon="img warn" padRight />
Under docker, localhost and 127.0.0.1 will not work, use dockerhost instead
{ _t('connection.dockerWarning', { defaultMessage: 'Under docker, localhost and 127.0.0.1 will not work, use dockerhost instead' }) }
</div>
{/if}
{/if}
@@ -280,7 +280,7 @@
<div class="row">
<div class="col-9 mr-1">
<FormTextField
label={$values.serviceNameType == 'sid' ? 'SID' : 'Service name'}
label={$values.serviceNameType == 'sid' ? 'SID' : _t('connection.serviceName', { defaultMessage: 'Service name' })}
name="serviceName"
disabled={isConnected}
templateProps={{ noMargin: true }}
@@ -289,14 +289,14 @@
</div>
<div class="col-3">
<FormSelectField
label="Choose type"
label={_t('connection.chooseType', { defaultMessage: 'Choose type' })}
isNative
name="serviceNameType"
defaultValue="serviceName"
disabled={isConnected}
templateProps={{ noMargin: true }}
options={[
{ value: 'serviceName', label: 'Service name' },
{ value: 'serviceName', label: _t('connection.serviceName', { defaultMessage: 'Service name' }) },
{ value: 'sid', label: 'SID' },
]}
data-testid="ConnectionDriverFields_serviceNameType"
@@ -307,7 +307,7 @@
{#if driver?.showConnectionField('socketPath', $values, showConnectionFieldArgs)}
<FormTextField
label="Socket path"
label={_t('connection.socketPath', { defaultMessage: 'Socket path' })}
name="socketPath"
disabled={isConnected || disabledFields.includes('socketPath')}
placeholder={driver?.defaultSocketPath}
@@ -320,7 +320,7 @@
{#if showUser}
<div class="col-6 mr-1">
<FormTextField
label="User"
label={_t('connection.user', { defaultMessage: 'User' })}
name="user"
disabled={isConnected || disabledFields.includes('user')}
templateProps={{ noMargin: true }}
@@ -331,7 +331,7 @@
{#if showPassword}
<div class="col-6 mr-1">
<FormPasswordField
label="Password"
label={_t('connection.password', { defaultMessage: 'Password' })}
name="password"
disabled={isConnected || disabledFields.includes('password')}
templateProps={{ noMargin: true }}
@@ -343,7 +343,7 @@
{/if}
{#if showUser && !showPassword}
<FormTextField
label="User"
label={_t('connection.user', { defaultMessage: 'User' })}
name="user"
disabled={isConnected || disabledFields.includes('user')}
data-testid="ConnectionDriverFields_user"
@@ -351,7 +351,7 @@
{/if}
{#if !showUser && showPassword}
<FormPasswordField
label="Password"
label={_t('connection.password', { defaultMessage: 'Password' })}
name="password"
disabled={isConnected || disabledFields.includes('password')}
data-testid="ConnectionDriverFields_password"
@@ -378,7 +378,7 @@
{#if driver?.showConnectionField('accessKeyId', $values, showConnectionFieldArgs)}
<div class="col-6 mr-1">
<FormTextField
label="Access Key ID"
label={_t('connection.accessKeyId', { defaultMessage: 'Access Key ID' })}
name="accessKeyId"
disabled={isConnected || disabledFields.includes('accessKeyId')}
templateProps={{ noMargin: true }}
@@ -389,7 +389,7 @@
{#if driver?.showConnectionField('secretAccessKey', $values, showConnectionFieldArgs)}
<div class="col-6 mr-1">
<FormPasswordField
label="Secret access key"
label={_t('connection.secretAccessKey', { defaultMessage: 'Secret access key' })}
name="secretAccessKey"
disabled={isConnected || disabledFields.includes('secretAccessKey')}
templateProps={{ noMargin: true }}
@@ -401,16 +401,16 @@
{#if !disabledFields.includes('password') && showPasswordMode}
<FormSelectField
label="Password mode"
label={_t('connection.passwordMode', { defaultMessage: 'Password mode' })}
isNative
name="passwordMode"
defaultValue="saveEncrypted"
disabled={isConnected}
options={[
{ value: 'saveEncrypted', label: 'Save and encrypt' },
{ value: 'saveRaw', label: 'Save raw (UNSAFE!!)' },
{ value: 'askPassword', label: "Don't save, ask for password" },
{ value: 'askUser', label: "Don't save, ask for login and password" },
{ value: 'saveEncrypted', label: _t('connection.saveEncrypted', { defaultMessage: 'Save and encrypt' }) },
{ value: 'saveRaw', label: _t('connection.saveRaw', { defaultMessage: 'Save raw (UNSAFE!!)' }) },
{ value: 'askPassword', label: _t('connection.askPassword', { defaultMessage: "Don't save, ask for password" }) },
{ value: 'askUser', label: _t('connection.askUser', { defaultMessage: "Don't save, ask for login and password" }) },
]}
data-testid="ConnectionDriverFields_passwordMode"
/>
@@ -418,7 +418,7 @@
{#if driver?.showConnectionField('treeKeySeparator', $values, showConnectionFieldArgs)}
<FormTextField
label="Key separator"
label={_t('connection.keySeparator', { defaultMessage: 'Key separator' })}
name="treeKeySeparator"
disabled={isConnected}
placeholder=":"
@@ -428,7 +428,7 @@
{#if driver?.showConnectionField('windowsDomain', $values, showConnectionFieldArgs)}
<FormTextField
label="Domain (specify to use NTLM authentication)"
label={_t('connection.windowsDomain', { defaultMessage: 'Domain (specify to use NTLM authentication)' })}
name="windowsDomain"
disabled={isConnected}
data-testid="ConnectionDriverFields_windowsDomain"
@@ -437,7 +437,7 @@
{#if driver?.showConnectionField('isReadOnly', $values, showConnectionFieldArgs)}
<FormCheckboxField
label="Is read only"
label={_t('connection.isReadOnly', { defaultMessage: 'Is read only' })}
name="isReadOnly"
disabled={isConnected}
data-testid="ConnectionDriverFields_isReadOnly"
@@ -446,7 +446,7 @@
{#if driver?.showConnectionField('trustServerCertificate', $values, showConnectionFieldArgs)}
<FormCheckboxField
label="Trust server certificate"
label={_t('connection.trustServerCertificate', { defaultMessage: 'Trust server certificate' })}
name="trustServerCertificate"
disabled={isConnected}
data-testid="ConnectionDriverFields_trustServerCertificate"
@@ -455,18 +455,18 @@
{#if driver?.showConnectionField('defaultDatabase', $values, showConnectionFieldArgs)}
<FormDropDownTextField
label="Default database"
label={_t('connection.defaultDatabase', { defaultMessage: 'Default database' })}
name="defaultDatabase"
disabled={isConnected}
data-testid="ConnectionDriverFields_defaultDatabase"
asyncMenu={createDatabasesMenu}
placeholder="(not selected - optional)"
placeholder={_t('common.notSelectedOptional', { defaultMessage : "(not selected - optional)"})}
/>
{/if}
{#if defaultDatabase && driver?.showConnectionField('singleDatabase', $values, showConnectionFieldArgs)}
<FormCheckboxField
label={`Use only database ${defaultDatabase}`}
label={_t('connection.singleDatabase', { defaultMessage: 'Use only database {defaultDatabase}', values: { defaultDatabase } })}
name="singleDatabase"
disabled={isConnected}
data-testid="ConnectionDriverFields_singleDatabase"
@@ -475,7 +475,7 @@
{#if driver?.showConnectionField('useSeparateSchemas', $values, showConnectionFieldArgs)}
<FormCheckboxField
label={`Use schemas separately (use this if you have many large schemas)`}
label={_t('connection.useSeparateSchemas', { defaultMessage: 'Use schemas separately (use this if you have many large schemas)' })}
name="useSeparateSchemas"
disabled={isConnected}
data-testid="ConnectionDriverFields_useSeparateSchemas"
@@ -483,14 +483,14 @@
{/if}
{#if driver?.showConnectionField('connectionDefinition', $values, showConnectionFieldArgs)}
<FormFileInputField disabled={isConnected} label="Service account key JSON" name="connectionDefinition" />
<FormFileInputField disabled={isConnected} label={_t('connection.connectionDefinition', { defaultMessage: 'Service account key JSON' })} name="connectionDefinition" />
{/if}
{#if driver}
<div class="row">
<div class="col-6 mr-1">
<FormTextField
label="Display name"
label={_t('connection.displayName', { defaultMessage: 'Display name' })}
name="displayName"
templateProps={{ noMargin: true }}
disabled={isConnected}
@@ -501,7 +501,7 @@
<div class="col-6 mr-1">
<FormColorField
useSelector
label="Color"
label={_t('connection.color', { defaultMessage: 'Color' })}
name="connectionColor"
emptyLabel="(not selected)"
templateProps={{ noMargin: true }}

View File

@@ -12,6 +12,7 @@
import { usePlatformInfo } from '../utility/metadataLoaders';
import FontIcon from '../icons/FontIcon.svelte';
import { extensions, openedConnections, openedSingleDatabaseConnections } from '../stores';
import { _t } from '../translations';
const { values, setFieldValue } = getFormContext();
const electron = getElectron();
@@ -29,7 +30,7 @@
</script>
<FormCheckboxField
label="Use SSH tunnel"
label={_t('connection.sshTunnel.use', {defaultMessage: "Use SSH tunnel"})}
name="useSshTunnel"
disabled={isConnected}
data-testid="ConnectionSshTunnelFields_useSshTunnel"
@@ -59,13 +60,13 @@
<FormTextField label="Bastion host (Jump host)" name="sshBastionHost" disabled={isConnected || !useSshTunnel} />
<FormSelectField
label="SSH Authentication"
label={_t('connection.sshTunnel.authentication', {defaultMessage: "SSH Authentication"})}
name="sshMode"
isNative
defaultSelectValue="userPassword"
disabled={isConnected || !useSshTunnel}
options={[
{ value: 'userPassword', label: 'Username & password' },
{ value: 'userPassword', label: _t('connection.sshTunnel.authMethod.userPassword', {defaultMessage: "Username & password"}) },
{ value: 'agent', label: 'SSH agent' },
{ value: 'keyFile', label: 'Key file' },
]}
@@ -94,7 +95,7 @@
</div>
<div class="col-6">
<FormPasswordField
label="Password"
label={_t('connection.password', {defaultMessage: 'Password'})}
name="sshPassword"
disabled={isConnected || !useSshTunnel}
templateProps={{ noMargin: true }}
@@ -109,7 +110,7 @@
<div class="col-6 mr-1">
{#if electron}
<FormElectronFileSelector
label="Private key file"
label={_t('connection.sshTunnel.privateKeyFile', {defaultMessage: "Private key file"})}
name="sshKeyfile"
disabled={isConnected || !useSshTunnel}
templateProps={{ noMargin: true }}
@@ -118,7 +119,7 @@
/>
{:else}
<FormTextField
label="Private key file (path on server)"
label={_t('connection.sshTunnel.privateKeyFilePath', {defaultMessage: "Private key file (path on server)"})}
name="sshKeyfile"
disabled={isConnected || !useSshTunnel}
templateProps={{ noMargin: true }}
@@ -129,7 +130,7 @@
</div>
<div class="col-6">
<FormPasswordField
label="Key file passphrase"
label={_t('connection.sshTunnel.keyFilePassphrase', {defaultMessage: "Key file passphrase"})}
name="sshKeyfilePassword"
disabled={isConnected || !useSshTunnel}
templateProps={{ noMargin: true }}
@@ -142,9 +143,9 @@
{#if useSshTunnel && $values.sshMode == 'agent'}
<div class="ml-3 mb-3">
{#if $platformInfo && $platformInfo.sshAuthSock}
<FontIcon icon="img ok" /> SSH Agent found
<FontIcon icon="img ok" /> {_t('connection.sshTunnel.agentFound', {defaultMessage: "SSH Agent found"})}
{:else}
<FontIcon icon="img error" /> SSH Agent not found
<FontIcon icon="img error" /> {_t('connection.sshTunnel.agentNotFound', {defaultMessage: "SSH Agent not found"})}
{/if}
</div>
{/if}

View File

@@ -7,6 +7,7 @@
import getElectron from '../utility/getElectron';
import FormPasswordField from '../forms/FormPasswordField.svelte';
import { openedConnections, openedSingleDatabaseConnections } from '../stores';
import { _t } from '../translations';
const { values, setFieldValue } = getFormContext();
const electron = getElectron();
@@ -15,21 +16,21 @@
$: isConnected = $openedConnections.includes($values._id) || $openedSingleDatabaseConnections.includes($values._id);
</script>
<FormCheckboxField label="Use SSL" name="useSsl" disabled={isConnected} />
<FormElectronFileSelector label="CA Cert (optional)" name="sslCaFile" disabled={isConnected || !useSsl || !electron} />
<FormCheckboxField label={_t('connection.ssl.use', {defaultMessage: "Use SSL"})} name="useSsl" disabled={isConnected} />
<FormElectronFileSelector label={_t('connection.ssl.caCert', {defaultMessage: "CA Cert (optional)"})} name="sslCaFile" disabled={isConnected || !useSsl || !electron} />
<FormElectronFileSelector
label="Certificate (optional)"
label={_t('connection.ssl.certificate', {defaultMessage: "Certificate (optional)"})}
name="sslCertFile"
disabled={isConnected || !useSsl || !electron}
/>
<FormPasswordField
label="Certificate key file password (optional)"
label={_t('connection.ssl.certificateKeyFilePassword', {defaultMessage: "Certificate key file password (optional)"})}
name="sslCertFilePassword"
disabled={isConnected || !useSsl || !electron}
/>
<FormElectronFileSelector
label="Key file (optional)"
label={_t('connection.ssl.keyFile', {defaultMessage: "Key file (optional)"})}
name="sslKeyFile"
disabled={isConnected || !useSsl || !electron}
/>
<FormCheckboxField label="Reject unauthorized" name="sslRejectUnauthorized" disabled={isConnected || !useSsl} />
<FormCheckboxField label={_t('connection.ssl.rejectUnauthorized', {defaultMessage: "Reject unauthorized"})} name="sslRejectUnauthorized" disabled={isConnected || !useSsl} />

View File

@@ -44,6 +44,10 @@
import AiSettingsTab from './AiSettingsTab.svelte';
import { _t } 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;
@@ -93,7 +97,7 @@ ORDER BY
<SettingsFormProvider>
<ModalBase {...$$restProps} noPadding fixedHeight>
<div slot="header">Settings</div>
<div slot="header">{_t('settings.title', { defaultMessage: 'Settings' })}</div>
<FormValues let:values>
<TabControl
@@ -106,20 +110,20 @@ ORDER BY
maxHeight100
flex1
tabs={[
hasPermission('settings/change') && { identifier: 'general', label: 'General', slot: 1 },
isProApp() && electron && { identifier: 'license', label: 'License', slot: 7 },
hasPermission('settings/change') && { identifier: 'connection', label: 'Connection', slot: 2 },
{ identifier: 'theme', label: 'Themes', slot: 3 },
hasPermission('settings/change') && { identifier: 'default-actions', label: 'Default Actions', slot: 4 },
hasPermission('settings/change') && { identifier: 'behaviour', label: 'Behaviour', slot: 5 },
hasPermission('settings/change') && { identifier: 'external-tools', label: 'External tools', slot: 8 },
hasPermission('settings/change') && { identifier: 'other', label: 'Other', slot: 6 },
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">Appearance</div>
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Appearance' })}</div>
<FormCheckboxField
name="app.useNativeMenu"
label={isMac() ? 'Use native window title' : 'Use system native menu'}
@@ -129,29 +133,30 @@ ORDER BY
/>
{#if restartWarning}
<div class="ml-5 mb-3">
<FontIcon icon="img warn" /> Native menu settings will be applied after app restart
<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="Show server name alongside database name in title of the tab group"
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>
<div class="heading">{_t('settings.localization', { defaultMessage: 'Localization' })}</div>
<FormSelectField
label="Language"
label={_t('settings.localization.language', { defaultMessage: 'Language' })}
name="localization.language"
defaultValue={getSelectedLanguage()}
isNative
options={[
{ value: 'en', label: 'English' },
{ value: 'cs', label: 'Czech' },
{ value: 'cs', label: 'Čeština' },
{ value: 'sk', label: 'Slovenčina' },
]}
on:change={() => {
showModal(ConfirmModal, {
message: 'Application will be reloaded to apply new language settings',
message: _t('settings.localization.reloadWarning', { defaultMessage: 'Application will be reloaded to apply new language settings' }),
onConfirm: () => {
setTimeout(() => {
internalRedirectTo('/');
@@ -159,58 +164,58 @@ ORDER BY
},
});
}}
/> -->
/>
<div class="heading">Data grid</div>
<div class="heading">{_t('settings.dataGrid.title', { defaultMessage: 'Data grid' })}</div>
<FormTextField
name="dataGrid.pageSize"
label="Page size (number of rows for incremental loading, must be between 5 and 50000)"
label={_t('settings.dataGrid.pageSize', { defaultMessage: 'Page size (number of rows for incremental loading, must be between 5 and 50000)' })}
defaultValue="100"
/>
<FormCheckboxField name="dataGrid.showHintColumns" label="Show foreign key hints" defaultValue={true} />
<FormCheckboxField name="dataGrid.showHintColumns" label={_t('settings.dataGrid.showHintColumns', { defaultMessage: 'Show foreign key hints' })} defaultValue={true} />
<!-- <FormCheckboxField name="dataGrid.showHintColumns" label="Show foreign key hints" defaultValue={true} /> -->
<FormCheckboxField name="dataGrid.thousandsSeparator" label="Use thousands separator for numbers" />
<FormCheckboxField name="dataGrid.thousandsSeparator" label={_t('settings.dataGrid.thousandsSeparator', { defaultMessage: 'Use thousands separator for numbers' })} />
<FormTextField
name="dataGrid.defaultAutoRefreshInterval"
label="Default grid auto refresh interval in seconds"
label={_t('settings.dataGrid.defaultAutoRefreshInterval', { defaultMessage: 'Default grid auto refresh interval in seconds' })}
defaultValue="10"
/>
<FormCheckboxField name="dataGrid.alignNumbersRight" label="Align numbers to right" defaultValue={false} />
<FormCheckboxField name="dataGrid.alignNumbersRight" label={_t('settings.dataGrid.alignNumbersRight', { defaultMessage: 'Align numbers to right' })} defaultValue={false} />
<FormTextField
name="dataGrid.collectionPageSize"
label="Collection page size (for MongoDB JSON view, must be between 5 and 1000)"
label={_t('settings.dataGrid.collectionPageSize', { defaultMessage: 'Collection page size (for MongoDB JSON view, must be between 5 and 1000)' })}
defaultValue="50"
/>
<FormSelectField
label="Row coloring mode"
label={_t('settings.dataGrid.coloringMode', { defaultMessage: 'Row coloring mode' })}
name="dataGrid.coloringMode"
isNative
defaultValue="36"
options={[
{ value: '36', label: 'Every 3rd and 6th row' },
{ value: '2-primary', label: 'Every 2-nd row, primary color' },
{ value: '2-secondary', label: 'Every 2-nd row, secondary color' },
{ value: 'none', label: 'None' },
{ 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="Show all columns when searching"
label={_t('settings.dataGrid.showAllColumnsWhenSearch', { defaultMessage: 'Show all columns when searching' })}
defaultValue={false}
/>
<div class="heading">SQL editor</div>
<div class="heading">{_t('settings.sqlEditor', { defaultMessage: 'SQL editor' })}</div>
<div class="flex">
<div class="col-3">
<FormSelectField
label="SQL commands case"
label={_t('settings.sqlEditor.sqlCommandsCase', { defaultMessage: 'SQL commands case' })}
name="sqlEditor.sqlCommandsCase"
isNative
defaultValue="upperCase"
@@ -221,7 +226,7 @@ ORDER BY
/>
</div>
<div class="col-3">
<FormFieldTemplateLarge label="Editor keybinds" type="combo">
<FormFieldTemplateLarge label={_t('settings.editor.keybinds', { defaultMessage: 'Editor keybinds' })} type="combo">
<SelectField
isNative
defaultValue="default"
@@ -232,7 +237,7 @@ ORDER BY
</FormFieldTemplateLarge>
</div>
<div class="col-3">
<FormFieldTemplateLarge label="Enable word wrap" type="combo">
<FormFieldTemplateLarge label={_t('settings.editor.wordWrap', { defaultMessage: 'Enable word wrap' })} type="combo">
<CheckboxField
checked={$currentEditorWrapEnabled}
on:change={e => ($currentEditorWrapEnabled = e.target.checked)}
@@ -243,33 +248,33 @@ ORDER BY
<FormTextField
name="sqlEditor.limitRows"
label="Return only N rows from query"
placeholder="(No rows limit)"
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="Show table aliases in code completion"
label={_t('settings.sqlEditor.showTableAliasesInCodeCompletion', { defaultMessage: 'Show table aliases in code completion' })}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.disableSplitByEmptyLine"
label="Disable split by empty line"
label={_t('settings.sqlEditor.disableSplitByEmptyLine', { defaultMessage: 'Disable split by empty line' })}
defaultValue={false}
/>
<FormCheckboxField
name="sqlEditor.disableExecuteCurrentLine"
label="Disable current line execution (Execute current)"
label={_t('settings.sqlEditor.disableExecuteCurrentLine', { defaultMessage: 'Disable current line execution (Execute current)' })}
defaultValue={false}
/>
</svelte:fragment>
<svelte:fragment slot="2">
<div class="heading">Connection</div>
<div class="heading">{_t('settings.connection', { defaultMessage: 'Connection' })}</div>
<FormFieldTemplateLarge
label="Show only tabs from selected database"
label={_t('settings.connection.showOnlyTabsFromSelectedDatabase', { defaultMessage: 'Show only tabs from selected database' })}
type="checkbox"
labelProps={{
onClick: () => {
@@ -282,17 +287,17 @@ ORDER BY
<FormCheckboxField
name="connection.autoRefresh"
label="Automatic refresh of database model on background"
label={_t('settings.connection.autoRefresh', { defaultMessage: 'Automatic refresh of database model on background' })}
defaultValue={false}
/>
<FormTextField
name="connection.autoRefreshInterval"
label="Interval between automatic DB structure reloads in seconds"
label={_t('settings.connection.autoRefreshInterval', { defaultMessage: 'Interval between automatic DB structure reloads in seconds' })}
defaultValue="30"
disabled={values['connection.autoRefresh'] === false}
/>
<FormSelectField
label="Local host address for SSH connections"
label={_t('settings.connection.sshBindHost', { defaultMessage: 'Local host address for SSH connections' })}
name="connection.sshBindHost"
isNative
defaultValue="127.0.0.1"
@@ -303,25 +308,25 @@ ORDER BY
]}
/>
<div class="heading">Query sessions</div>
<div class="heading">{_t('settings.session', { defaultMessage: 'Query sessions' })}</div>
<FormCheckboxField
name="session.autoClose"
label="Automatic close query sessions after period without any activity"
label={_t('settings.session.autoClose', { defaultMessage: 'Automatic close query sessions after period without any activity' })}
defaultValue={true}
/>
<FormTextField
name="session.autoCloseTimeout"
label="Interval, after which query session without activity is closed (in minutes)"
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">Application theme</div>
<div class="heading">{_t('settings.appearance', { defaultMessage: 'Application theme' })}</div>
<FormFieldTemplateLarge
label="Use system theme"
label={_t('settings.appearance.useSystemTheme', { defaultMessage: 'Use system theme' })}
type="checkbox"
labelProps={{
onClick: () => {
@@ -352,19 +357,19 @@ ORDER BY
</div>
<div class="m-5">
More themes are available as <Link onClick={openThemePlugins}>plugins</Link>
{_t('settings.appearance.moreThemes', { defaultMessage: 'More themes are available as' })} <Link onClick={openThemePlugins}>plugins</Link>
<br />
After installing theme plugin (try search "theme" in available extensions) new themes will be available here.
{_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">Editor theme</div>
<div class="heading">{_t('settings.appearance.editorTheme', { defaultMessage: 'Editor theme' })}</div>
<div class="flex">
<div class="col-3">
<FormFieldTemplateLarge label="Theme" type="combo">
<FormFieldTemplateLarge label={_t('settings.appearance.editorTheme', { defaultMessage: 'Theme' })} type="combo">
<SelectField
isNative
notSelected="(use theme default)"
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)}
@@ -373,7 +378,7 @@ ORDER BY
</div>
<div class="col-3">
<FormFieldTemplateLarge label="Font size " type="combo">
<FormFieldTemplateLarge label={_t('settings.appearance.fontSize', { defaultMessage: 'Font size' })} type="combo">
<SelectField
isNative
notSelected="(default)"
@@ -385,7 +390,7 @@ ORDER BY
</div>
<div class="col-3">
<FormFieldTemplateLarge label="Custom size " type="text">
<FormFieldTemplateLarge label={_t('settings.appearance.customSize', { defaultMessage: 'Custom size' })} type="text">
<TextField
value={$currentEditorFontSize == 'custom' ? '' : $currentEditorFontSize}
on:change={e => ($currentEditorFontSize = e.target['value'])}
@@ -396,7 +401,7 @@ ORDER BY
</div>
<div class="col-3">
<FormTextField name="editor.fontFamily" label="Editor font family" />
<FormTextField name="editor.fontFamily" label={_t('settings.appearance.fontFamily', { defaultMessage: 'Editor font family' })} />
</div>
</div>
@@ -405,68 +410,68 @@ ORDER BY
</div>
</svelte:fragment>
<svelte:fragment slot="4">
<div class="heading">Default actions</div>
<div class="heading">{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}</div>
<FormSelectField
label="Connection click"
label={_t('settings.defaultActions.connectionClick', { defaultMessage: 'Connection click' })}
name="defaultAction.connectionClick"
isNative
defaultValue="connect"
options={[
{ value: 'openDetails', label: 'Edit / open details' },
{ value: 'connect', label: 'Connect' },
{ value: 'none', label: 'Do nothing' },
{ 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="Database click"
label={_t('settings.defaultActions.databaseClick', { defaultMessage: 'Database click' })}
name="defaultAction.databaseClick"
isNative
defaultValue="switch"
options={[
{ value: 'switch', label: 'Switch database' },
{ value: 'none', label: 'Do nothing' },
{ 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="Use last used action" defaultValue={true} />
<FormCheckboxField name="defaultAction.useLastUsedAction" label={_t('settings.defaultActions.useLastUsedAction', { defaultMessage: 'Use last used action' })} defaultValue={true} />
<FormDefaultActionField
label="Table click"
label={_t('settings.defaultActions.tableClick', { defaultMessage: 'Table click' })}
objectTypeField="tables"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label="View click"
label={_t('settings.defaultActions.viewClick', { defaultMessage: 'View click' })}
objectTypeField="views"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label="Materialized view click"
label={_t('settings.defaultActions.materializedViewClick', { defaultMessage: 'Materialized view click' })}
objectTypeField="matviews"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label="Procedure click"
label={_t('settings.defaultActions.procedureClick', { defaultMessage: 'Procedure click' })}
objectTypeField="procedures"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label="Function click"
label={_t('settings.defaultActions.functionClick', { defaultMessage: 'Function click' })}
objectTypeField="functions"
disabled={values['defaultAction.useLastUsedAction'] !== false}
/>
<FormDefaultActionField
label="NoSQL collection click"
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">Behaviour</div>
<div class="heading">{_t('settings.behaviour', { defaultMessage: 'Behaviour' })}</div>
<FormCheckboxField name="behaviour.useTabPreviewMode" label="Use tab preview mode" defaultValue={true} />
<FormCheckboxField name="behaviour.useTabPreviewMode" label={_t('settings.behaviour.useTabPreviewMode', { defaultMessage: 'Use tab preview mode' })} defaultValue={true} />
<FormCheckboxField
name="behaviour.jsonPreviewWrap"
@@ -475,58 +480,55 @@ ORDER BY
/>
<div class="tip">
<FontIcon icon="img tip" /> 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.
<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="Open detail on keyboard navigation"
label={_t('settings.behaviour.openDetailOnArrows', { defaultMessage: 'Open detail on keyboard navigation' })}
defaultValue={true}
disabled={values['behaviour.useTabPreviewMode'] === false}
/>
<div class="heading">Confirmations</div>
<div class="heading">{_t('settings.confirmations', { defaultMessage: 'Confirmations' })}</div>
<FormCheckboxField name="skipConfirm.tableDataSave" label="Skip confirmation when saving table data (SQL)" />
<FormCheckboxField name="skipConfirm.tableDataSave" label={_t('settings.confirmations.skipConfirm.tableDataSave', { defaultMessage: 'Skip confirmation when saving table data (SQL)' })} />
<FormCheckboxField
name="skipConfirm.collectionDataSave"
label="Skip confirmation when saving collection data (NoSQL)"
label={_t('settings.confirmations.skipConfirm.collectionDataSave', { defaultMessage: 'Skip confirmation when saving collection data (NoSQL)' })}
/>
</svelte:fragment>
<svelte:fragment slot="6">
<div class="heading">Other</div>
<div class="heading">{_t('settings.other', { defaultMessage: 'Other' })}</div>
<FormTextField name="other.gistCreateToken" label="API token for creating error gists" defaultValue="" />
<FormTextField name="other.gistCreateToken" label={_t('settings.other.gistCreateToken', { defaultMessage: 'API token for creating error gists' })} defaultValue="" />
<FormSelectField
label="Auto update application"
label={_t('settings.other.autoUpdateApplication', { defaultMessage: 'Auto update application' })}
name="app.autoUpdateMode"
isNative
defaultValue=""
options={[
{ value: 'skip', label: 'Do not check for new versions' },
{ value: '', label: 'Check for new versions' },
{ value: 'download', label: 'Check and download new versions' },
{ 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="Allow to send DB models and query snippets to AI service"
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">License</div>
<div class="heading">{_t('settings.other.license', { defaultMessage: 'License' })}</div>
<FormTextAreaField
name="other.licenseKey"
label="License key"
label={_t('settings.other.licenseKey', { defaultMessage: 'License key' })}
rows={7}
onChange={async value => {
licenseKeyCheckResult = await apiCall('config/check-license', { licenseKey: value });
@@ -536,28 +538,28 @@ ORDER BY
<div class="m-3 ml-5">
{#if licenseKeyCheckResult.status == 'ok'}
<div>
<FontIcon icon="img ok" /> License key is valid
<FontIcon icon="img ok" /> { _t('settings.other.licenseKey.valid', { defaultMessage: 'License key is valid' }) }
</div>
{#if licenseKeyCheckResult.validTo}
<div>
License valid to: {licenseKeyCheckResult.validTo}
{ _t('settings.other.licenseKey.validTo', { defaultMessage: 'License valid to:' }) } {licenseKeyCheckResult.validTo}
</div>
{/if}
{#if licenseKeyCheckResult.expiration}
<div>License key expiration: <b>{safeFormatDate(licenseKeyCheckResult.expiration)}</b></div>
<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 ?? 'License key is invalid'}
{licenseKeyCheckResult.errorMessage ?? _t('settings.other.licenseKey.invalid', { defaultMessage: 'License key is invalid' })}
{#if licenseKeyCheckResult.expiration}
<div>License key expiration: <b>{safeFormatDate(licenseKeyCheckResult.expiration)}</b></div>
<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="Check for new license key"
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 });
@@ -574,24 +576,32 @@ ORDER BY
</svelte:fragment>
<svelte:fragment slot="8">
<div class="heading">External tools</div>
<div class="heading">{_t('settings.externalTools', { defaultMessage: 'External tools' })}</div>
<FormTextField
name="externalTools.mysqldump"
label="mysqldump (backup MySQL database)"
label={_t('settings.other.externalTools.mysqldump', { defaultMessage: 'mysqldump (backup MySQL database)' })}
defaultValue="mysqldump"
/>
<FormTextField name="externalTools.mysql" label="mysql (restore MySQL database)" defaultValue="mysql" />
<FormTextField
name="externalTools.mysql"
label={_t('settings.other.externalTools.mysql', { defaultMessage: 'mysql (restore MySQL database)' })}
defaultValue="mysql"
/>
<FormTextField
name="externalTools.mysqlPlugins"
label="Folder with mysql plugins (for example for authentication). Set only in case of problems"
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="pg_dump (backup PostgreSQL database)"
label={_t('settings.other.externalTools.pg_dump', { defaultMessage: 'pg_dump (backup PostgreSQL database)' })}
defaultValue="pg_dump"
/>
<FormTextField name="externalTools.psql" label="psql (restore PostgreSQL database)" defaultValue="psql" />
<FormTextField
name="externalTools.psql"
label={_t('settings.other.externalTools.psql', { defaultMessage: 'psql (restore PostgreSQL database)' })}
defaultValue="psql"
/>
</svelte:fragment>
<svelte:fragment slot="9">
@@ -602,7 +612,7 @@ ORDER BY
<div slot="footer">
<!-- <FormSubmit value="OK" on:click={handleOk} /> -->
<FormStyledButton value="Close" on:click={closeCurrentModal} />
<FormStyledButton value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</div>
</ModalBase>
</SettingsFormProvider>

View File

@@ -9,6 +9,7 @@ import { safeJsonParse } from 'dbgate-tools';
import { apiCall } from './utility/api';
import { getOpenedTabsStorageName, isAdminPage } from './utility/pageDefs';
import { switchCurrentDatabase } from './utility/common';
import { tick } from 'svelte';
export interface TabDefinition {
title: string;
@@ -187,6 +188,8 @@ export const seenPremiumPromoWidget = writableWithStorage(null, 'seenPremiumProm
export const cloudConnectionsStore = writable({});
export const promoWidgetPreview = writable(null);
export const DEFAULT_OBJECT_SEARCH_SETTINGS = {
pureName: true,
schemaName: false,
@@ -225,6 +228,12 @@ currentTheme.subscribe(value => {
});
export const getCurrentTheme = () => currentThemeValue;
let extensionsValue: ExtensionsDirectory = null;
extensions.subscribe(value => {
extensionsValue = value;
});
export const getExtensions = () => extensionsValue;
export const currentThemeDefinition = derived(
[currentTheme, extensions, systemThemeStore],
([$currentTheme, $extensions, $systemTheme]) => {
@@ -236,7 +245,9 @@ currentThemeDefinition.subscribe(value => {
if (value?.themeType && getCurrentTheme()) {
localStorage.setItem('currentThemeType', value?.themeType);
} else {
localStorage.removeItem('currentThemeType');
if (extensionsValue?.themes?.length > 0) {
localStorage.removeItem('currentThemeType');
}
}
});
export const openedConnectionsWithTemporary = derived(
@@ -307,17 +318,40 @@ openedTabs.subscribe(value => {
});
export const getOpenedTabs = () => openedTabsValue;
let openedModalsValue = [];
openedModals.subscribe(value => {
openedModalsValue = value;
tick().then(() => {
dispatchUpdateCommands();
});
});
export const getOpenedModals = () => openedModalsValue;
let commandsValue = null;
commands.subscribe(value => {
commandsValue = value;
const electron = getElectron();
if (electron) {
electron.send('update-commands', JSON.stringify(value));
}
tick().then(() => {
dispatchUpdateCommands();
});
});
export const getCommands = () => commandsValue;
function dispatchUpdateCommands() {
const electron = getElectron();
if (electron) {
electron.send(
'update-commands',
JSON.stringify({
isModalOpened: openedModalsValue?.length > 0,
commands: commandsValue,
dbgatePage: window['dbgate_page'],
})
);
}
}
let activeTabValue = null;
activeTab.subscribe(value => {
activeTabValue = value;
@@ -363,12 +397,6 @@ export const getCurrentDatabase = () => currentDatabaseValue;
let currentSettingsValue = null;
export const getCurrentSettings = () => currentSettingsValue || {};
let extensionsValue: ExtensionsDirectory = null;
extensions.subscribe(value => {
extensionsValue = value;
});
export const getExtensions = () => extensionsValue;
let openedConnectionsValue = null;
openedConnections.subscribe(value => {
openedConnectionsValue = value;
@@ -415,12 +443,6 @@ selectedDatabaseObjectAppObject.subscribe(value => {
});
export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue;
let openedModalsValue = [];
openedModals.subscribe(value => {
openedModalsValue = value;
});
export const getOpenedModals = () => openedModalsValue;
let focusedConnectionOrDatabaseValue = null;
focusedConnectionOrDatabase.subscribe(value => {
focusedConnectionOrDatabaseValue = value;

View File

@@ -27,41 +27,41 @@
<FormProvider initialValues={fillEditorColumnInfo(columnInfo || {}, tableInfo)}>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header"
>{columnInfo ? 'Edit column' : `Add column ${(tableInfo?.columns || []).length + 1}`}</svelte:fragment
>{columnInfo ? _t('columnEditor.editColumn', { defaultMessage: 'Edit column' }) : _t('columnEditor.addColumn', { defaultMessage: 'Add column {columnNumber}', values: { columnNumber: (tableInfo?.columns || []).length + 1 } })}</svelte:fragment
>
<FormTextField name="columnName" label="Column name" focused disabled={isReadOnly} />
<FormTextField name="columnName" label={_t('columnEditor.columnName', { defaultMessage: 'Column name' })} focused disabled={isReadOnly} />
<DataTypeEditor dialect={driver?.dialect} disabled={isReadOnly} />
{#if !driver?.dialect?.specificNullabilityImplementation}
<FormCheckboxField name="notNull" label="NOT NULL" disabled={isReadOnly} />
{/if}
<FormCheckboxField name="isPrimaryKey" label="Is Primary Key" disabled={isReadOnly} />
<FormCheckboxField name="isPrimaryKey" label={_t('columnEditor.isPrimaryKey', { defaultMessage: 'Is Primary Key' })} disabled={isReadOnly} />
{#if !driver?.dialect?.disableAutoIncrement}
<FormCheckboxField name="autoIncrement" label="Is Autoincrement" disabled={isReadOnly} />
<FormCheckboxField name="autoIncrement" label={_t('columnEditor.autoIncrement', { defaultMessage: 'Is Autoincrement' })} disabled={isReadOnly} />
{/if}
<FormTextField
name="defaultValue"
label="Default value. Please use valid SQL expression, eg. 'Hello World' for string value, '' for empty string"
label={_t('columnEditor.defaultValue', { defaultMessage: "Default value. Please use valid SQL expression, eg. 'Hello World' for string value, '' for empty string" })}
disabled={!setTableInfo}
/>
<FormTextField name="computedExpression" label="Computed expression" disabled={isReadOnly} />
<FormTextField name="computedExpression" label={_t('columnEditor.computedExpression', { defaultMessage: 'Computed expression' })} disabled={isReadOnly} />
{#if driver?.dialect?.columnProperties?.isUnsigned}
<FormCheckboxField name="isUnsigned" label="Unsigned" disabled={isReadOnly} />
<FormCheckboxField name="isUnsigned" label={_t('columnEditor.isUnsigned', { defaultMessage: 'Unsigned' })} disabled={isReadOnly} />
{/if}
{#if driver?.dialect?.columnProperties?.isZerofill}
<FormCheckboxField name="isZerofill" label="Zero fill" disabled={isReadOnly} />
<FormCheckboxField name="isZerofill" label={_t('columnEditor.isZerofill', { defaultMessage: 'Zero fill' })} disabled={isReadOnly} />
{/if}
{#if driver?.dialect?.columnProperties?.columnComment}
<FormTextField name="columnComment" label="Comment" disabled={isReadOnly} />
<FormTextField name="columnComment" label={_t('columnEditor.columnComment', { defaultMessage: 'Comment' })} disabled={isReadOnly} />
{/if}
{#if driver?.dialect?.columnProperties?.isSparse}
<FormCheckboxField name="isSparse" label="Sparse" disabled={isReadOnly} />
<FormCheckboxField name="isSparse" label={_t('columnEditor.isSparse', { defaultMessage: 'Sparse' })} disabled={isReadOnly} />
{/if}
<svelte:fragment slot="footer">
<FormSubmit
value={columnInfo ? 'Save' : 'Save and next'}
value={columnInfo ? _t('common.save', { defaultMessage: 'Save' }) : _t('common.saveAndNext', { defaultMessage: 'Save and next' })}
disabled={isReadOnly}
on:click={e => {
closeCurrentModal();
@@ -85,11 +85,11 @@
/>
{/if}
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
{#if columnInfo}
<FormStyledButton
type="button"
value="Remove"
value={_t('common.remove', { defaultMessage: 'Remove' })}
on:click={() => {
closeCurrentModal();
setTableInfo(tbl => editorDeleteColumn(tbl, columnInfo, addDataCommand));

View File

@@ -9,13 +9,15 @@
import { editorAddConstraint, editorDeleteConstraint, editorModifyConstraint } from 'dbgate-tools';
import TextField from '../forms/TextField.svelte';
import SelectField from '../forms/SelectField.svelte';
import { _t, __t } from '../translations';
import _ from 'lodash';
export let constraintInfo;
export let setTableInfo;
export let tableInfo;
export let constraintLabel;
export let constraintType;
export let constraintNameLabel = 'Constraint name';
export let constraintNameLabel = _t('tableEditor.constraintName', { defaultMessage: 'Constraint name' });
export let getExtractConstraintProps;
export let hideConstraintName = false;
@@ -41,7 +43,7 @@
<FormProvider>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header"
>{constraintInfo ? `Edit ${constraintLabel}` : `Add ${constraintLabel}`}</svelte:fragment
>{constraintInfo ? _t('tableEdit.editConstraintLabel', { defaultMessage: 'Edit {constraintLabel}', values: { constraintLabel } }) : _t('tableEdit.addConstraintLabel', { defaultMessage: 'Add {constraintLabel}', values: { constraintLabel } })}</svelte:fragment
>
<div class="largeFormMarker">
@@ -65,7 +67,7 @@
{#each columns as column, index}
<div class="row">
<div class="label col-3">Column {index + 1}</div>
<div class="label col-3">{_t('common.column', { defaultMessage: 'Column ' })}{index + 1}</div>
<div class={$$slots.column ? 'col-3' : 'col-6'}>
{#key column.columnName}
<SelectField
@@ -91,7 +93,7 @@
{/if}
<div class="col-3 button">
<FormStyledButton
value="Delete"
value={_t('common.delete', { defaultMessage: 'Delete' })}
disabled={isReadOnly}
on:click={e => {
const x = [...columns];
@@ -104,11 +106,11 @@
{/each}
<div class="row">
<div class="label col-3">Add new column</div>
<div class="label col-3">{_t('columnsConstraintEditor.addNewColumn', { defaultMessage: 'Add new column' })}</div>
<div class="col-9">
{#key columns.length}
<SelectField
placeholder="Select column"
placeholder={_t('columnsConstraintEditor.selectColumn', { defaultMessage: 'Select column' })}
disabled={isReadOnly}
value={''}
on:change={e => {
@@ -123,7 +125,7 @@
isNative
options={[
{
label: 'Choose column',
label: _t('columnsConstraintEditor.chooseColumn', { defaultMessage: 'Choose column' }) ,
value: '',
},
...(tableInfo?.columns?.map(col => ({
@@ -139,7 +141,7 @@
<svelte:fragment slot="footer">
<FormSubmit
value={'Save'}
value={_t('common.save', { defaultMessage: 'Save' })}
disabled={isReadOnly}
on:click={() => {
closeCurrentModal();
@@ -151,11 +153,11 @@
}}
/>
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
{#if constraintInfo}
<FormStyledButton
type="button"
value="Remove"
value={_t('common.remove', { defaultMessage: 'Remove' })}
disabled={isReadOnly}
on:click={() => {
closeCurrentModal();

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import FormDropDownTextField from '../forms/FormDropDownTextField.svelte';
import { getFormContext } from '../forms/FormProviderCore.svelte';
import { _t } from '../translations';
const { values, setFieldValue } = getFormContext();
@@ -17,4 +18,4 @@
export let disabled = false;
</script>
<FormDropDownTextField name="dataType" label="Data type" menu={createDataTypesMenu} {disabled} />
<FormDropDownTextField name="dataType" label="{_t('tableEditor.dataType', { defaultMessage: 'Data type' })}" menu={createDataTypesMenu} {disabled} />

View File

@@ -60,11 +60,11 @@
<FormProvider>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">{constraintInfo ? `Edit foreign key` : `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">
<div class="label col-3">Constraint name</div>
<div class="label col-3">{_t('tableEditor.constraintName', { defaultMessage: 'Constraint name' })}</div>
<div class="col-9">
<TextField
value={constraintName}
@@ -76,7 +76,7 @@
</div>
<div class="row">
<div class="label col-3">Referenced table</div>
<div class="label col-3">{_t('foreignKeyEditor.referencedTable', { defaultMessage: 'Referenced table' })}</div>
<div class="col-9">
<SelectField
value={fullNameToString({ pureName: refTableName, schemaName: refSchemaName })}
@@ -99,7 +99,7 @@
</div>
<div class="row">
<div class="label col-3">On update action</div>
<div class="label col-3">{_t('foreignKeyEditor.onUpdateAction', { defaultMessage: 'On update action' })}</div>
<div class="col-9">
<SelectField
value={updateAction}
@@ -115,7 +115,7 @@
</div>
<div class="row">
<div class="label col-3">On delete action</div>
<div class="label col-3">{_t('foreignKeyEditor.onDeleteAction', { defaultMessage: 'On delete action' })}</div>
<div class="col-9">
<SelectField
value={deleteAction}
@@ -132,10 +132,10 @@
<div class="row">
<div class="col-5 mr-1">
Base column - {tableInfo.pureName}
{_t('foreignKeyEditor.baseColumn', { defaultMessage: 'Base column - ' })}{tableInfo.pureName}
</div>
<div class="col-5 ml-1">
Ref column - {refTableName || '(table not set)'}
{_t('foreignKeyEditor.refColumn', { defaultMessage: 'Ref column - ' })}{refTableName || _t('foreignKeyEditor.tableNotSet', { defaultMessage: '(table not set)' })}
</div>
</div>
@@ -195,7 +195,7 @@
<FormStyledButton
type="button"
value="Add column"
value={_t('foreignKeyEditor.addColumn', { defaultMessage: 'Add column' })}
disabled={isReadOnly}
on:click={() => {
columns = [...columns, {}];
@@ -217,12 +217,12 @@
}}
/>
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
{#if constraintInfo}
<FormStyledButton
type="button"
disabled={isReadOnly}
value="Remove"
value={_t('common.remove', { defaultMessage: 'Remove' })}
on:click={() => {
closeCurrentModal();
setTableInfo(tbl => editorDeleteConstraint(tbl, constraintInfo));

View File

@@ -3,6 +3,7 @@
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import SelectField from '../forms/SelectField.svelte';
import TextField from '../forms/TextField.svelte';
import { _t } from '../translations';
import ColumnsConstraintEditorModal from './ColumnsConstraintEditorModal.svelte';
@@ -29,7 +30,7 @@
{...$$restProps}
constraintLabel="index"
constraintType="index"
constraintNameLabel="Index name"
constraintNameLabel={_t('indexEditor.indexName', { defaultMessage: 'Index name' })}
{constraintInfo}
{setTableInfo}
{tableInfo}
@@ -61,15 +62,14 @@
<svelte:fragment slot="constraintProps">
<div class="largeFormMarker">
<div class="row">
<CheckboxField checked={isUnique} on:change={e => (isUnique = e.target.checked)} disabled={isReadOnly} /> Is unique
index
<CheckboxField checked={isUnique} on:change={e => (isUnique = e.target.checked)} disabled={isReadOnly} /> {_t('indexEditor.isUnique', { defaultMessage: 'Is unique index' })}
</div>
</div>
<div class="largeFormMarker">
{#if driver?.dialect?.filteredIndexes}
<div class="row">
<div class="label col-3">Filtered index condition</div>
<div class="label col-3">{_t('indexEditor.filteredIndexCondition', { defaultMessage: 'Filtered index condition' })}</div>
<div class="col-9">
<TextField
value={filterDefinition}

View File

@@ -1,12 +1,13 @@
<script lang="ts">
import ColumnsConstraintEditorModal from './ColumnsConstraintEditorModal.svelte';
import { _t } from '../translations';
export let constraintInfo;
export let setTableInfo;
export let tableInfo;
export let driver;
export let constraintLabel = 'primary key';
export let constraintLabel = _t('tableEditor.primaryKey', { defaultMessage: 'primary key' });
export let constraintType = 'primaryKey';
</script>

View File

@@ -9,13 +9,14 @@
import { showModal } from '../modals/modalTools';
import PrimaryKeyEditorModal from './PrimaryKeyEditorModal.svelte';
import { _t } from '../translations';
export let tableInfo;
export let setTableInfo;
export let isWritable;
export let driver;
export let constraintLabel = 'primary key';
export let constraintLabel = _t('tableEditor.primaryKey', { defaultMessage: 'primary key' });
export let constraintType = 'primaryKey';
$: columns = tableInfo?.columns;
@@ -35,7 +36,12 @@
<ObjectListControl
collection={_.compact([keyConstraint])}
title={_.startCase(constraintLabel)}
emptyMessage={isWritable ? `No ${constraintLabel} defined` : null}
emptyMessage={isWritable
? _t('tableEditor.noConstraintDefined', {
defaultMessage: 'No {constraintLabel} defined',
values: { constraintLabel },
})
: null}
onAddNew={isWritable && !keyConstraint && columns?.length > 0 ? addKeyConstraint : null}
hideDisplayName={driver?.dialect?.anonymousPrimaryKey}
clickable
@@ -51,7 +57,7 @@
columns={[
{
fieldName: 'columns',
header: 'Columns',
header: _t('tableEditor.columns', { defaultMessage: 'Columns' }),
slot: 0,
sortable: true,
},
@@ -70,7 +76,7 @@
onClick={e => {
e.stopPropagation();
setTableInfo(tbl => editorDeleteConstraint(tbl, row));
}}>Remove</Link
}}>{_t('common.remove', { defaultMessage: 'Remove' })}</Link
></svelte:fragment
>
</ObjectListControl>

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'tableEditor.addColumn',
category: 'Table editor',
name: '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: 'Table editor',
name: '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: 'Table editor',
name: '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: 'Table editor',
name: '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: 'Table editor',
name: 'Add unique',
category: __t('tableEditor', { defaultMessage: 'Table editor'}),
name: __t('tableEditor.addUnique', { defaultMessage: 'Add unique'}),
icon: 'icon add-key',
toolbar: true,
isRelatedToTab: true,
@@ -83,6 +83,7 @@
import UniqueEditorModal from './UniqueEditorModal.svelte';
import ObjectFieldsEditor from '../elements/ObjectFieldsEditor.svelte';
import PrimaryKeyLikeListControl from './PrimaryKeyLikeListControl.svelte';
import { __t, _t } from '../translations';
export const activator = createActivator('TableEditor', true);
@@ -171,9 +172,9 @@
{#if tableInfo && (tableFormOptions || isCreateTable)}
{#key resetCounter}
<ObjectFieldsEditor
title="Table properties"
title={_t('tableEditor.tableproperties', { defaultMessage: 'Table properties' })}
fieldDefinitions={tableFormOptions ?? []}
pureNameTitle={isCreateTable ? 'Table name' : null}
pureNameTitle={isCreateTable ? _t('tableEditor.tablename', { defaultMessage: 'Table name' }) : null}
schemaList={isCreateTable && schemaList?.length >= 0 ? schemaList : null}
values={_.pick(tableInfo, ['schemaName', 'pureName', ...(tableFormOptions ?? []).map(x => x.name)])}
onChangeValues={vals => {
@@ -187,15 +188,15 @@
<ObjectListControl
collection={columns?.map((x, index) => ({ ...x, ordinal: index + 1 }))}
title={`Columns (${columns?.length || 0})`}
emptyMessage="No columns defined"
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 })}
onAddNew={isWritable ? addColumn : null}
displayNameFieldName="columnName"
multipleItemsActions={[
{
text: 'Remove',
text: _t('tableEditor.remove', { defaultMessage: 'Remove' }),
icon: 'icon delete',
onClick: selected => {
setTableInfo(tbl => {
@@ -205,7 +206,7 @@
},
},
{
text: 'Copy names',
text: _t('tableEditor.copynames', { defaultMessage: 'Copy names' }),
icon: 'icon copy',
onClick: selected => {
const names = selected.map(x => x.columnName).join('\n');
@@ -213,7 +214,7 @@
},
},
{
text: 'Copy definitions',
text: _t('tableEditor.copydefinitions', { defaultMessage: 'Copy definitions' }),
icon: 'icon copy',
onClick: selected => {
const names = selected
@@ -226,55 +227,55 @@
columns={[
!driver?.dialect?.specificNullabilityImplementation && {
fieldName: 'notNull',
header: 'Nullability',
header: _t('tableEditor.nullability', { defaultMessage: 'Nullability' }),
sortable: true,
slot: 0,
},
{
fieldName: 'dataType',
header: 'Data Type',
header: _t('tableEditor.dataType', { defaultMessage: 'Data type' }),
sortable: true,
filterable: true,
},
{
fieldName: 'defaultValue',
header: 'Default value',
header: _t('tableEditor.defaultValue', { defaultMessage: 'Default value' }),
sortable: true,
filterable: true,
},
driver?.dialect?.columnProperties?.isSparse && {
fieldName: 'isSparse',
header: 'Is Sparse',
header: _t('tableEditor.isSparse', { defaultMessage: 'Is Sparse' }),
sortable: true,
slot: 1,
},
{
fieldName: 'computedExpression',
header: 'Computed Expression',
header: _t('tableEditor.computedExpression', { defaultMessage: 'Computed Expression' }),
sortable: true,
filterable: true,
},
driver?.dialect?.columnProperties?.isPersisted && {
fieldName: 'isPersisted',
header: 'Is Persisted',
header: _t('tableEditor.isPersisted', { defaultMessage: 'Is Persisted' }),
sortable: true,
slot: 2,
},
driver?.dialect?.columnProperties?.isUnsigned && {
fieldName: 'isUnsigned',
header: 'Unsigned',
header: _t('tableEditor.isUnsigned', { defaultMessage: 'Unsigned' }),
sortable: true,
slot: 4,
},
driver?.dialect?.columnProperties?.isZerofill && {
fieldName: 'isZerofill',
header: 'Zero fill',
header: _t('tableEditor.isZeroFill', { defaultMessage: 'Zero fill' }),
sortable: true,
slot: 5,
},
driver?.dialect?.columnProperties?.columnComment && {
fieldName: 'columnComment',
header: 'Comment',
header: _t('tableEditor.columnComment', { defaultMessage: 'Comment' }),
sortable: true,
filterable: true,
},
@@ -287,19 +288,19 @@
: null,
]}
>
<svelte:fragment slot="0" let:row>{row?.notNull ? 'NOT NULL' : 'NULL'}</svelte:fragment>
<svelte:fragment slot="1" let:row>{row?.isSparse ? 'YES' : 'NO'}</svelte:fragment>
<svelte:fragment slot="2" let:row>{row?.isPersisted ? 'YES' : '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 => {
e.stopPropagation();
setTableInfo(tbl => editorDeleteColumn(tbl, row));
}}>Remove</Link
}}>{_t('tableEditor.remove', { defaultMessage: 'Remove' })}</Link
></svelte:fragment
>
<svelte:fragment slot="4" let:row>{row?.isUnsigned ? 'YES' : 'NO'}</svelte:fragment>
<svelte:fragment slot="5" let:row>{row?.isZerofill ? 'YES' : '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>
@@ -320,20 +321,20 @@
<ObjectListControl
collection={indexes}
onAddNew={isWritable && columns?.length > 0 ? addIndex : null}
title={`Indexes (${indexes?.length || 0})`}
emptyMessage={isWritable ? 'No index defined' : null}
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 })}
columns={[
{
fieldName: 'columns',
header: 'Columns',
header: _t('tableEditor.columns', { defaultMessage: 'Columns' }),
slot: 0,
sortable: true,
},
{
fieldName: 'unique',
header: 'Unique',
header: _t('tableEditor.unique', { defaultMessage: 'Unique' }),
slot: 1,
sortable: true,
},
@@ -347,13 +348,13 @@
>
<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 ? 'YES' : '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 => {
e.stopPropagation();
setTableInfo(tbl => editorDeleteConstraint(tbl, row));
}}>Remove</Link
}}>{_t('common.remove', { defaultMessage: 'Remove' })}</Link
></svelte:fragment
>
</ObjectListControl>
@@ -363,14 +364,14 @@
<ObjectListControl
collection={uniques}
onAddNew={isWritable && columns?.length > 0 ? addUnique : null}
title={`Unique constraints (${uniques?.length || 0})`}
emptyMessage={isWritable ? 'No unique defined' : null}
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 })}
columns={[
{
fieldName: 'columns',
header: 'Columns',
header: _t('tableEditor.columns', { defaultMessage: 'Columns' }),
slot: 0,
sortable: true,
},
@@ -390,7 +391,7 @@
onClick={e => {
e.stopPropagation();
setTableInfo(tbl => editorDeleteConstraint(tbl, row));
}}>Remove</Link
}}>{_t('common.remove', { defaultMessage: 'Remove' })}</Link
></svelte:fragment
>
</ObjectListControl>
@@ -400,13 +401,13 @@
<ForeignKeyObjectListControl
collection={foreignKeys}
onAddNew={isWritable && columns?.length > 0 ? addForeignKey : null}
title={`Foreign keys (${foreignKeys?.length || 0})`}
emptyMessage={isWritable ? '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="Dependencies" />
<ForeignKeyObjectListControl collection={dependencies} title={_t('tableEditor.dependencies', { defaultMessage: 'Dependencies' })} />
{/if}
</div>

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import ColumnsConstraintEditorModal from './ColumnsConstraintEditorModal.svelte';
import { _t } from '../translations';
export let constraintInfo;
export let setTableInfo;
@@ -9,7 +10,7 @@
<ColumnsConstraintEditorModal
{...$$restProps}
constraintLabel="unique"
constraintLabel={_t('tableEdit.unique', { defaultMessage: "unique" })}
constraintType="unique"
{constraintInfo}
{setTableInfo}

View File

@@ -239,8 +239,8 @@
registerCommand({
id: 'tabs.nextTab',
category: 'Tabs',
name: _t('command.tabs.nextTab', { defaultMessage: 'Next tab' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.nextTab', { defaultMessage: 'Next tab' }),
keyText: 'Ctrl+Tab',
testEnabled: () => getOpenedTabs().filter(x => !x.closedTime).length >= 2,
onClick: () => switchTabByOrder(false),
@@ -248,8 +248,8 @@
registerCommand({
id: 'tabs.previousTab',
category: 'Tabs',
name: _t('command.tabs.previousTab', { defaultMessage: 'Previous tab' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.previousTab', { defaultMessage: 'Previous tab' }),
keyText: 'Ctrl+Shift+Tab',
testEnabled: () => getOpenedTabs().filter(x => !x.closedTime).length >= 2,
onClick: () => switchTabByOrder(true),
@@ -257,16 +257,16 @@
registerCommand({
id: 'tabs.closeAll',
category: 'Tabs',
name: _t('command.tabs.closeAll', { defaultMessage: 'Close all tabs' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.closeAll', { defaultMessage: 'Close all tabs' }),
testEnabled: () => getOpenedTabs().filter(x => !x.closedTime).length >= 1,
onClick: closeAll,
});
registerCommand({
id: 'tabs.closeTab',
category: 'Tabs',
name: _t('command.tabs.closeTab', { defaultMessage: 'Close tab' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.closeTab', { defaultMessage: 'Close tab' }),
keyText: isElectronAvailable() ? 'CtrlOrCommand+W' : 'Alt+W',
testEnabled: () => {
const hasAnyOtherTab = getOpenedTabs().filter(x => !x.closedTime).length >= 1;
@@ -279,24 +279,24 @@
registerCommand({
id: 'tabs.closeTabsWithCurrentDb',
category: 'Tabs',
name: _t('command.tabs.closeTabsWithCurrentDb', { defaultMessage: 'Close tabs with current DB' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.closeTabsWithCurrentDb', { defaultMessage: 'Close tabs with current DB' }),
testEnabled: () => getOpenedTabs().filter(x => !x.closedTime).length >= 1 && !!getCurrentDatabase(),
onClick: closeTabsWithCurrentDb,
});
registerCommand({
id: 'tabs.closeTabsButCurrentDb',
category: 'Tabs',
name: _t('command.tabs.closeTabsButCurrentDb', { defaultMessage: 'Close tabs but current DB' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.closeTabsButCurrentDb', { defaultMessage: 'Close tabs but current DB' }),
testEnabled: () => getOpenedTabs().filter(x => !x.closedTime).length >= 1 && !!getCurrentDatabase(),
onClick: closeTabsButCurrentDb,
});
registerCommand({
id: 'tabs.reopenClosedTab',
category: 'Tabs',
name: _t('command.tabs.reopenClosedTab', { defaultMessage: 'Reopen closed tab' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.reopenClosedTab', { defaultMessage: 'Reopen closed tab' }),
keyText: 'CtrlOrCommand+Shift+T',
testEnabled: () => getOpenedTabs().filter(x => x.closedTime).length >= 1,
onClick: reopenClosedTab,
@@ -304,8 +304,8 @@
registerCommand({
id: 'tabs.addToFavorites',
category: 'Tabs',
name: _t('command.tabs.addToFavorites', { defaultMessage: 'Add current tab to favorites' }),
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.addToFavorites', { defaultMessage: 'Add current tab to favorites' }),
// icon: 'icon favorite',
// toolbar: true,
testEnabled: () =>
@@ -358,6 +358,9 @@
import { handleAfterTabClick } from '../utility/changeCurrentDbByTab';
import { getBoolSettingsValue } from '../settings/settingsTools';
import NewObjectModal from '../modals/NewObjectModal.svelte';
import { isProApp } from '../utility/proTools';
import { openWebLink } from '../utility/simpleTools';
import { __t } from '../translations';
export let multiTabIndex;
export let shownTab;
@@ -583,7 +586,13 @@
</script>
<div class="root">
<div class="tabs" class:can-split={allowSplitTab} on:wheel={handleTabsWheel} bind:this={domTabs}>
<div
class="tabs"
class:can-split={allowSplitTab && isProApp()}
class:tabs-upgrade-button={!isProApp()}
on:wheel={handleTabsWheel}
bind:this={domTabs}
>
{#each groupedTabs as tabGroup}
<div class="db-wrapper">
{#if !$lockedDatabaseMode}
@@ -713,7 +722,7 @@
{/each}
</div>
<div class="icons-wrapper">
{#if allowSplitTab}
{#if allowSplitTab && isProApp()}
<div
class="icon-button"
on:click={() => splitTab(multiTabIndex)}
@@ -723,6 +732,22 @@
<FontIcon icon="icon split" />
</div>
{/if}
{#if !isProApp()}
<div
class="upgrade-button"
on:click={() => {
openWebLink(
`https://www.dbgate.io/purchase/${isElectronAvailable() ? 'premium' : 'team-premium'}/?utm_campaign=premiumUpgradeButton`
);
}}
title="Upgrade to Premium"
data-testid="TabsPanel_buttonUpgrade"
>
<FontIcon icon="icon premium" padRight /> Upgrade
</div>
{/if}
<div
class="icon-button"
on:click={() => showModal(NewObjectModal, { multiTabIndex })}
@@ -756,6 +781,18 @@
color: var(--theme-font-2);
cursor: pointer;
}
.upgrade-button {
background: linear-gradient(135deg, #1686c8, #8a25b1);
border: 1px solid var(--theme-border);
border-radius: 10px;
color: white;
cursor: pointer;
font-size: 10pt;
padding: 5px;
}
.upgrade-button:hover {
background: linear-gradient(135deg, #0f5a85, #5c1870);
}
.icon-button:hover {
color: var(--theme-font-1);
}
@@ -769,6 +806,10 @@
right: 35px;
bottom: 0;
}
.tabs-upgrade-button {
right: 120px;
}
.tabs.can-split {
right: 60px;
}

View File

@@ -6,8 +6,8 @@
registerCommand({
id: 'archiveFile.save',
group: 'save',
category: 'Archive file',
name: 'Save',
category: __t('command.archiveFile', { defaultMessage: 'Archive file' }),
name: __t('command.archiveFile.save', { defaultMessage: 'Save' }),
toolbar: true,
isRelatedToTab: true,
icon: 'icon save',
@@ -17,8 +17,8 @@
registerCommand({
id: 'archiveFile.saveAs',
category: 'Archive file',
name: 'Save as',
category: __t('command.archiveFile', { defaultMessage: 'Archive file' }),
name: __t('command.archiveFile.saveAs', { defaultMessage: 'Save as' }),
icon: 'icon save',
isRelatedToTab: true,
testEnabled: () => getCurrentEditor() != null,
@@ -49,6 +49,7 @@
import { changeTab, markTabSaved, markTabUnsaved, sleep } from '../utility/common';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createUndoReducer from '../utility/createUndoReducer';
import { __t } from '../translations';
export const activator = createActivator('ArchiveFileTab', true);

View File

@@ -8,8 +8,8 @@
registerCommand({
id: 'collectionTable.save',
group: 'save',
category: 'Collection data',
name: 'Save',
category: __t('command.collectionData', { defaultMessage: 'Collection data' }),
name: __t('command.collectionData.save', { defaultMessage: 'Save' }),
// keyText: 'CtrlOrCommand+S',
toolbar: true,
isRelatedToTab: true,
@@ -56,6 +56,7 @@
import useEditorData from '../query/useEditorData';
import { markTabSaved, markTabUnsaved } from '../utility/common';
import { getNumberIcon } from '../icons/FontIcon.svelte';
import { __t } from '../translations';
export let tabid;
export let conid;

View File

@@ -300,7 +300,7 @@
contentTestId="ConnectionTab_tabControlContent"
tabs={[
{
label: 'General',
label: _t('common.general', { defaultMessage: 'General' }),
component: ConnectionDriverFields,
props: { getDatabaseList, currentConnection },
testid: 'ConnectionTab_tabGeneral',
@@ -316,7 +316,7 @@
testid: 'ConnectionTab_tabSsl',
},
{
label: 'Advanced',
label: _t('common.advanced', { defaultMessage: 'Advanced' }),
component: ConnectionAdvancedDriverFields,
testid: 'ConnectionTab_tabAdvanced',
},
@@ -383,7 +383,7 @@
{/if}
{#if isTesting}
<div>
<FontIcon icon="icon loading" /> Testing connection
<FontIcon icon="icon loading" /> {_t('common.testingConnection', { defaultMessage: 'Testing connection' })}
</div>
{/if}
</div>

View File

@@ -3,7 +3,7 @@
registerFileCommands({
idPrefix: 'diagram',
category: 'Diagram',
category: __t('command.diagram', { defaultMessage: 'Diagram' }),
getCurrentEditor,
folder: 'diagrams',
format: 'json',
@@ -32,6 +32,7 @@
import DiagramSettings from '../designer/DiagramSettings.svelte';
import { derived } from 'svelte/store';
import { isProApp } from '../utility/proTools';
import { __t } from '../translations';
export let tabid;
export let conid;

View File

@@ -3,7 +3,7 @@
registerFileCommands({
idPrefix: 'favoriteJsonEditor',
category: 'Favorite JSON editor',
category: __t('command.favoriteJsonEditor', { defaultMessage: 'Favorite JSON editor' }),
getCurrentEditor,
folder: null,
format: null,
@@ -15,15 +15,15 @@
registerCommand({
id: 'favoriteJsonEditor.save',
group: 'save',
name: 'Save',
category: 'Favorite JSON editor',
name: __t('command.favoriteJsonEditor.save', { defaultMessage: 'Save' }),
category: __t('command.favoriteJsonEditor', { defaultMessage: 'Favorite JSON editor' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().save(),
});
registerCommand({
id: 'favoriteJsonEditor.preview',
name: 'Preview',
category: 'Favorite JSON editor',
name: __t('command.favoriteJsonEditor.preview', { defaultMessage: 'Preview' }),
category: __t('command.favoriteJsonEditor', { defaultMessage: 'Favorite JSON editor' }),
keyText: 'F5 | CtrlOrCommand+Enter',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().preview(),
@@ -43,6 +43,7 @@
import { openFavorite } from '../appobj/FavoriteFileAppObject.svelte';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import { apiCall } from '../utility/api';
import { __t } from '../translations';
export let tabid;
export let savedFile;

View File

@@ -17,7 +17,7 @@
id: 'jsonl.save',
group: 'save',
category: 'JSON Lines editor',
name: 'Save',
name: __t('command.jsonl.save', { defaultMessage: 'Save' }),
toolbar: true,
isRelatedToTab: true,
icon: 'icon save',
@@ -28,7 +28,7 @@
registerCommand({
id: 'jsonl.preview',
category: 'JSON Lines editor',
name: 'Preview',
name: __t('command.jsonl.preview', { defaultMessage: 'Preview' }),
icon: 'icon preview',
keyText: 'F5',
testEnabled: () => getCurrentEditor() != null,
@@ -38,7 +38,7 @@
registerCommand({
id: 'jsonl.previewNewTab',
category: 'JSON Lines editor',
name: 'Preview in new tab',
name: __t('command.jsonl.previewNewTab', { defaultMessage: 'Preview in new tab' }),
icon: 'icon preview',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().previewMewTab(),
@@ -47,7 +47,7 @@
registerCommand({
id: 'jsonl.closePreview',
category: 'JSON Lines editor',
name: 'Close preview',
name: __t('command.jsonl.closePreview', { defaultMessage: 'Close preview' }),
icon: 'icon close',
testEnabled: () => getCurrentEditor()?.isPreview(),
onClick: () => getCurrentEditor().closePreview(),
@@ -74,6 +74,7 @@
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
import JslDataGrid from '../datagrid/JslDataGrid.svelte';
import ToolStripCommandSplitButton from '../buttons/ToolStripCommandSplitButton.svelte';
import { __t } from '../translations';
export let tabid;
export let archiveFolder;

View File

@@ -16,7 +16,7 @@
registerCommand({
id: 'markdown.preview',
category: 'Markdown',
name: 'Preview',
name: __t('command.markdown.preview', { defaultMessage: 'Preview' }),
icon: 'icon run',
toolbar: true,
isRelatedToTab: true,
@@ -38,6 +38,7 @@
import openNewTab from '../utility/openNewTab';
import { setSelectedTab } from '../utility/common';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import { __t } from '../translations';
export let tabid;

View File

@@ -5,8 +5,8 @@
registerCommand({
id: 'queryData.stopLoading',
category: 'Query data',
name: 'Stop loading',
category: __t('command.queryData', { defaultMessage: 'Query data' }),
name: __t('command.queryData.stopLoading', { defaultMessage: 'Stop loading' }),
icon: 'icon stop',
testEnabled: () => getCurrentEditor()?.isLoading(),
onClick: () => getCurrentEditor().stopLoading(),
@@ -32,6 +32,7 @@
import yaml from 'js-yaml';
import JslChart from '../charts/JslChart.svelte';
import ToolStripButton from '../buttons/ToolStripButton.svelte';
import { __t } from '../translations';
export const activator = createActivator('QueryDataTab', true);

View File

@@ -2,21 +2,22 @@
import registerCommand from '../commands/registerCommand';
import { copyTextToClipboard } from '../utility/clipboard';
import yaml from 'js-yaml';
import { __t, _t } from '../translations';
const getCurrentEditor = () => getActiveComponent('QueryTab');
registerCommand({
id: 'query.formatCode',
category: 'Query',
name: 'Format code',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.formatCode', { defaultMessage: 'Format code' }),
keyText: 'Shift+Alt+F',
testEnabled: () => getCurrentEditor()?.isSqlEditor(),
onClick: () => getCurrentEditor().formatCode(),
});
registerCommand({
id: 'query.switchAiAssistant',
category: 'Query',
name: 'AI Assistant',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.AiAssistant', { defaultMessage: 'AI Assistant' }),
keyText: 'Shift+Alt+A',
icon: 'icon ai',
testEnabled: () => isProApp(),
@@ -24,23 +25,23 @@
});
registerCommand({
id: 'query.insertSqlJoin',
category: 'Query',
name: 'Insert SQL Join',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.insertSqlJoin', { defaultMessage: 'Insert SQL Join' }),
keyText: 'CtrlOrCommand+J',
testEnabled: () => getCurrentEditor()?.isSqlEditor(),
onClick: () => getCurrentEditor().insertSqlJoin(),
});
registerCommand({
id: 'query.toggleVisibleResultTabs',
category: 'Query',
name: 'Toggle visible result tabs',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.toggleVisibleResultTabs', { defaultMessage: 'Toggle visible result tabs' }),
keyText: 'CtrlOrCommand+Shift+R',
testEnabled: () => !!getCurrentEditor(),
onClick: () => getCurrentEditor().toggleVisibleResultTabs(),
});
registerFileCommands({
idPrefix: 'query',
category: 'Query',
category: __t('command.query', { defaultMessage: 'Query' }),
getCurrentEditor,
folder: 'sql',
format: 'text',
@@ -54,8 +55,8 @@
});
registerCommand({
id: 'query.executeCurrent',
category: 'Query',
name: 'Execute current',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.executeCurrent', { defaultMessage: 'Execute current' }),
keyText: 'CtrlOrCommand+Shift+Enter',
testEnabled: () =>
getCurrentEditor() != null && !getCurrentEditor()?.isBusy() && getCurrentEditor()?.hasConnection(),
@@ -63,56 +64,56 @@
});
registerCommand({
id: 'query.toggleAutoExecute',
category: 'Query',
name: 'Toggle auto execute',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.toggleAutoExecute', { defaultMessage: 'Toggle auto execute' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().toggleAutoExecute(),
});
registerCommand({
id: 'query.toggleFixedConnection',
category: 'Query',
name: 'Toggle fixed connection',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.toggleFixedConnection', { defaultMessage: 'Toggle fixed connection' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().toggleFixedConnection(),
});
registerCommand({
id: 'query.beginTransaction',
category: 'Query',
name: 'Begin transaction',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.beginTransaction', { defaultMessage: 'Begin transaction' }),
icon: 'icon transaction',
testEnabled: () => getCurrentEditor()?.beginTransactionEnabled(),
onClick: () => getCurrentEditor().beginTransaction(),
});
registerCommand({
id: 'query.autocommitOffSwitch',
category: 'Query',
name: 'Auto commit: OFF',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.autocommitOffSwitch', { defaultMessage: 'Auto commit: OFF' }),
icon: 'icon autocommit-off',
testEnabled: () => getCurrentEditor()?.autocommitOffSwitchEnabled(),
onClick: () => getCurrentEditor().autocommitOffSwitch(),
});
registerCommand({
id: 'query.autocommitOnSwitch',
category: 'Query',
name: 'Auto commit: ON',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.autocommitOnSwitch', { defaultMessage: 'Auto commit: ON' }),
icon: 'icon autocommit-on',
testEnabled: () => getCurrentEditor()?.autocommitOnSwitchEnabled(),
onClick: () => getCurrentEditor().autocommitOnSwitch(),
});
registerCommand({
id: 'query.commitTransaction',
category: 'Query',
name: 'Commit transaction',
toolbarName: 'Commit',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.commitTransaction', { defaultMessage: 'Commit transaction' }),
toolbarName: __t('command.query.commitTransactionToolbar', { defaultMessage: 'Commit' }),
icon: 'icon commit',
testEnabled: () => getCurrentEditor()?.endTransactionEnabled(),
onClick: () => getCurrentEditor().commitTransaction(),
});
registerCommand({
id: 'query.rollbackTransaction',
category: 'Query',
name: 'Rollback transaction',
toolbarName: 'Rollback',
category: __t('command.query', { defaultMessage: 'Query' }),
name: __t('command.query.rollbackTransaction', { defaultMessage: 'Rollback transaction' }),
toolbarName: __t('command.query.rollbackTransactionToolbar', { defaultMessage: 'Rollback' }),
icon: 'icon rollback',
testEnabled: () => getCurrentEditor()?.endTransactionEnabled(),
onClick: () => getCurrentEditor().rollbackTransaction(),
@@ -177,27 +178,27 @@
const QUERY_PARAMETER_STYLES = [
{
value: '',
text: '(no parameters)',
text: _t('query.noParameters', { defaultMessage: '(no parameters)' }),
},
{
value: '?',
text: '? (positional)',
text: _t('query.positional', { defaultMessage: '? (positional)' }),
},
{
value: '@',
text: '@variable',
text: _t('query.variable', { defaultMessage: '@variable' }),
},
{
value: ':',
text: ':variable',
text: _t('query.named', { defaultMessage: ':variable' }),
},
{
value: '$',
text: '$variable',
text: _t('query.variable', { defaultMessage: '$variable' }),
},
{
value: '#',
text: '#variable',
text: _t('query.variable', { defaultMessage: '#variable' }),
},
];
@@ -265,9 +266,11 @@
if (sid) {
apiOn(`session-done-${sid}`, handleSessionDone);
apiOn(`session-closed-${sid}`, handleSessionClosed);
apiOn(`session-changedb-${sid}`, handleChangedDatabase);
return () => {
apiOff(`session-done-${sid}`, handleSessionDone);
apiOff(`session-closed-${sid}`, handleSessionClosed);
apiOff(`session-changedb-${sid}`, handleChangedDatabase);
};
}
return () => {};
@@ -566,6 +569,17 @@
handleSessionDone();
};
const handleChangedDatabase = async props => {
changeTab(tabid, tab => ({
...tab,
props: {
...tab.props,
conid,
database: props.database,
},
}));
};
const { editorState, editorValue, setEditorData } = useEditorData({
tabid,
loadFromArgs:
@@ -757,12 +771,12 @@
<SocketMessageView
eventName={sessionId ? `session-info-${sessionId}` : null}
onMessageClick={handleMesageClick}
{executeNumber}
startLine={executeStartLine}
showProcedure
showLine
onChangeErrors={handleChangeErrors}
onExplainError={isProApp() ? handleExplainError : null}
engine={$connection && $connection.engine}
/>
</svelte:fragment>
</ResultTabs>
@@ -818,11 +832,11 @@
},
})}
>
{queryRowsLimit ? `Limit ${queryRowsLimit} rows` : 'Unlimited rows'}</ToolStripButton
{queryRowsLimit ? _t('query.limitRows', { defaultMessage: 'Limit {queryRowsLimit} rows', values: { queryRowsLimit } }) : _t('query.unlimitedRows', { defaultMessage: 'Unlimited rows' })}</ToolStripButton
>
{/if}
{#if resultCount == 1}
<ToolStripExportButton command="jslTableGrid.export" {quickExportHandlerRef} label="Export result" />
<ToolStripExportButton command="jslTableGrid.export" {quickExportHandlerRef} label={_t('export.result', { defaultMessage: 'Export result' })} />
{/if}
<ToolStripDropDownButton
menu={() =>
@@ -872,7 +886,7 @@
domResultTabs?.openCurrentChart();
}}
>
Open chart</ToolStripButton
{_t('chart.open', { defaultMessage: 'Open chart' })}</ToolStripButton
>
{/if}
{#if isProApp() && !visibleResultTabs && hasPermission('dbops/charts')}
@@ -883,7 +897,7 @@
autoDetectCharts = !autoDetectCharts;
}}
>
Detect chart<FontIcon
{_t('chart.detect', { defaultMessage: 'Detect chart' })}<FontIcon
icon={autoDetectCharts ? 'icon checkbox-marked' : 'icon checkbox-blank'}
padLeft
/></ToolStripButton

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'serverSummary.refresh',
category: 'Server sumnmary',
name: _t('common.refresh', { defaultMessage: 'Refresh' }),
category: __t('command.serverSummary', { defaultMessage: 'Server summary' }),
name: __t('common.refresh', { defaultMessage: 'Refresh' }),
keyText: 'F5 | CtrlOrCommand+R',
toolbar: true,
isRelatedToTab: true,
@@ -21,7 +21,7 @@
import LoadingInfo from '../elements/LoadingInfo.svelte';
import TabControl from '../elements/TabControl.svelte';
import { _t } from '../translations';
import { _t, __t } from '../translations';
import { apiCall } from '../utility/api';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import openNewTab from '../utility/openNewTab';

View File

@@ -18,7 +18,7 @@
registerCommand({
id: 'shell.copyNodeScript',
category: 'Shell',
name: 'Copy nodejs script',
name: __t('command.shell.copyNodeScript', { defaultMessage: 'Copy nodejs script' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().copyNodeScript(),
});
@@ -49,6 +49,7 @@
import { showSnackbarError } from '../utility/snackbar';
import useEffect from '../utility/useEffect';
import useTimerLabel from '../utility/useTimerLabel';
import { __t } from '../translations';
export let tabid;

View File

@@ -3,8 +3,8 @@
registerCommand({
id: 'sqlObject.find',
category: 'SQL Object',
name: 'Find',
category: __t('command.sqlObject', { defaultMessage: 'SQL Object' }),
name: __t('command.sqlObject.find', { defaultMessage: 'Find' }),
keyText: 'CtrlOrCommand+F',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().find(),
@@ -31,6 +31,7 @@
import ToolStripButton from '../buttons/ToolStripButton.svelte';
import openNewTab from '../utility/openNewTab';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { __t } from '../translations';
export let tabid;
export let appObjectData;

View File

@@ -1,12 +1,35 @@
<script lang="ts" context="module">
const getCurrentEditor = () => getActiveComponent('TableDataTab');
const INTERVALS = [5, 10, 15, 13, 60];
const INTERVALS = [5, 10, 15, 30, 60];
const INTERVAL_COMMANDS = [
{
time: 5,
name: __t('command.datagrid.setAutoRefresh.5', { defaultMessage: 'Refresh every 5 seconds' }),
},
{
time: 10,
name: __t('command.datagrid.setAutoRefresh.10', { defaultMessage: 'Refresh every 10 seconds' }),
},
{
time: 15,
name: __t('command.datagrid.setAutoRefresh.15', { defaultMessage: 'Refresh every 15 seconds' }),
},
{
time: 30,
name: __t('command.datagrid.setAutoRefresh.30', { defaultMessage: 'Refresh every 30 seconds' }),
},
{
time: 60,
name: __t('command.datagrid.setAutoRefresh.60', { defaultMessage: 'Refresh every 60 seconds' }),
},
]
registerCommand({
id: 'tableData.save',
group: 'save',
category: 'Table data',
name: 'Save',
category: __t('command.tableData', { defaultMessage: 'Table data' }),
name: __t('command.tableData.save', { defaultMessage: 'Save' }),
// keyText: 'CtrlOrCommand+S',
toolbar: true,
isRelatedToTab: true,
@@ -17,28 +40,28 @@
registerCommand({
id: 'tableData.setAutoRefresh.1',
category: 'Data grid',
name: 'Refresh every 1 second',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.setAutoRefresh.1', { defaultMessage: 'Refresh every 1 second' }),
isRelatedToTab: true,
testEnabled: () => !!getCurrentEditor(),
onClick: () => getCurrentEditor().setAutoRefresh(1),
});
for (const seconds of INTERVALS) {
for (const { time, name } of INTERVAL_COMMANDS) {
registerCommand({
id: `tableData.setAutoRefresh.${seconds}`,
category: 'Data grid',
name: `Refresh every ${seconds} seconds`,
id: `tableData.setAutoRefresh.${time}`,
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name,
isRelatedToTab: true,
testEnabled: () => !!getCurrentEditor(),
onClick: () => getCurrentEditor().setAutoRefresh(seconds),
onClick: () => getCurrentEditor().setAutoRefresh(time),
});
}
registerCommand({
id: 'tableData.stopAutoRefresh',
category: 'Data grid',
name: 'Stop auto refresh',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.stopAutoRefresh', { defaultMessage: 'Stop auto refresh' }),
isRelatedToTab: true,
keyText: 'CtrlOrCommand+Shift+R',
testEnabled: () => getCurrentEditor()?.isAutoRefresh() === true,
@@ -47,8 +70,8 @@
registerCommand({
id: 'tableData.startAutoRefresh',
category: 'Data grid',
name: 'Start auto refresh',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.startAutoRefresh', { defaultMessage: 'Start auto refresh' }),
isRelatedToTab: true,
keyText: 'CtrlOrCommand+Shift+R',
testEnabled: () => getCurrentEditor()?.isAutoRefresh() === false,
@@ -101,6 +124,7 @@
import { markTabSaved, markTabUnsaved } from '../utility/common';
import ToolStripButton from '../buttons/ToolStripButton.svelte';
import { getNumberIcon } from '../icons/FontIcon.svelte';
import { __t, _t } from '../translations';
export let tabid;
export let conid;
@@ -260,7 +284,7 @@
{ command: 'tableData.stopAutoRefresh', hideDisabled: true },
{ command: 'tableData.startAutoRefresh', hideDisabled: true },
'tableData.setAutoRefresh.1',
...INTERVALS.map(seconds => ({ command: `tableData.setAutoRefresh.${seconds}`, text: `...${seconds} seconds` })),
...INTERVALS.map(seconds => ({ command: `tableData.setAutoRefresh.${seconds}`, text: `...${seconds}` + ' ' + _t('command.datagrid.autoRefresh.seconds', { defaultMessage: 'seconds' }) })),
];
}
</script>
@@ -304,7 +328,7 @@
defaultActionId: 'openStructure',
},
});
}}>Structure</ToolStripButton
}}>{_t('datagrid.structure', { defaultMessage: 'Structure' })}</ToolStripButton
>
<ToolStripButton
@@ -378,7 +402,7 @@
<ToolStripButton
icon={$collapsedLeftColumnStore ? 'icon columns-outline' : 'icon columns'}
on:click={() => collapsedLeftColumnStore.update(x => !x)}>View columns</ToolStripButton
on:click={() => collapsedLeftColumnStore.update(x => !x)}>{_t('tableData.viewColumns', { defaultMessage: 'View columns' })}</ToolStripButton
>
</svelte:fragment>
</ToolStripContainer>

View File

@@ -6,8 +6,8 @@
registerCommand({
id: 'tableStructure.save',
group: 'save',
category: 'Table editor',
name: 'Save',
category: __t('command.tableEditor', { defaultMessage: 'Table editor' }),
name: __t('command.tableEditor.save', { defaultMessage: 'Save' }),
toolbar: true,
isRelatedToTab: true,
icon: 'icon save',
@@ -17,8 +17,8 @@
registerCommand({
id: 'tableStructure.reset',
category: 'Table editor',
name: 'Reset changes',
category: __t('command.tableEditor', { defaultMessage: 'Table editor' }),
name: __t('command.tableEditor.reset', { defaultMessage: 'Reset changes' }),
toolbar: true,
isRelatedToTab: true,
icon: 'icon close',
@@ -57,6 +57,7 @@
import hasPermission from '../utility/hasPermission';
import { changeTab, markTabSaved, markTabUnsaved } from '../utility/common';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { _t, __t } from '../translations';
export let tabid;
export let conid;
@@ -197,7 +198,7 @@
defaultActionId: 'openTable',
},
});
}}>Data</ToolStripButton
}}>{_t('common.data', { defaultMessage: 'Data' })}</ToolStripButton
>
<ToolStripButton
@@ -230,7 +231,7 @@
<ToolStripCommandButton
command="tableStructure.save"
buttonLabel={$editorValue?.base ? 'Alter table' : 'Create table'}
buttonLabel={$editorValue?.base ? _t('tableStructure.alter', { defaultMessage: 'Alter table' }) : _t('tableStructure.create', { defaultMessage: 'Create table' })}
/>
<ToolStripCommandButton command="tableStructure.reset" />
<ToolStripCommandButton command="tableEditor.addColumn" />

View File

@@ -1,4 +1,5 @@
import cs from '../../../translations/cs.json';
import sk from '../../../translations/sk.json';
import MessageFormat, { MessageFunction } from '@messageformat/core';
import { getStringSettingsValue } from './settings/settingsTools';
@@ -6,6 +7,7 @@ import { getStringSettingsValue } from './settings/settingsTools';
const translations = {
en: {},
cs,
sk,
};
const supportedLanguages = Object.keys(translations);
@@ -13,15 +15,22 @@ const compiledMessages: Partial<Record<string, Record<string, MessageFunction<'s
const defaultLanguage = 'en';
let selectedLanguageCache: string | null = null;
export function getSelectedLanguage(): string {
const borwserLanguage = getBrowserLanguage();
const selectedLanguage = getStringSettingsValue('localization.language', borwserLanguage);
if (selectedLanguageCache) return selectedLanguageCache;
const browserLanguage = getBrowserLanguage();
const selectedLanguage = getStringSettingsValue('localization.language', browserLanguage);
if (!supportedLanguages.includes(selectedLanguage)) return defaultLanguage;
return selectedLanguage;
}
export function saveSelectedLanguageToCache() {
selectedLanguageCache = getSelectedLanguage();
}
export function getBrowserLanguage(): string {
return 'en';
// if (typeof window !== 'undefined') {
@@ -68,3 +77,11 @@ export function _t(key: string, options: TranslateOptions): string {
return compliledTranslation(values ?? {});
}
export function __t(key: string, options: TranslateOptions): () => string {
return () => _t(key, options);
}
export function _val<T>(x: T | (() => T)): T {
return typeof x === 'function' ? (x as () => T)() : x;
}

View File

@@ -2,6 +2,7 @@ import _ from 'lodash';
import { arrayToHexString, stringifyCellValue } from 'dbgate-tools';
import yaml from 'js-yaml';
import { DataEditorTypesBehaviour } from 'dbgate-types';
import { __t, _t } from '../translations'
export function copyTextToClipboard(text) {
const oldFocus = document.activeElement;
@@ -157,53 +158,53 @@ export function copyRowsToClipboard(format, columns, rows, options) {
export const copyRowsFormatDefs = {
textWithHeaders: {
label: 'Copy with headers',
name: 'With headers',
label: __t('clipboard.copyWithHeaders', { defaultMessage : 'Copy with headers' }),
name: __t('clipboard.withHeaders', { defaultMessage: 'With headers' }),
formatter: clipboardTextFormatter('\t', true),
},
textWithoutHeaders: {
label: 'Copy without headers',
name: 'Without headers',
label: __t('clipboard.copyWithoutHeaders', { defaultMessage : 'Copy without headers' }),
name: __t('clipboard.withoutHeaders', { defaultMessage: 'Without headers' }),
formatter: clipboardTextFormatter('\t', false),
},
headers: {
label: 'Copy only headers',
name: 'Only Headers',
label: __t('clipboard.copyOnlyHeadres', { defaultMessage : 'Copy only headers'}),
name: __t('clipboard.onlyHeaders', { defaultMessage : 'Only Headers' }),
formatter: clipboardHeadersFormatter('\t'),
},
csv: {
label: 'Copy as CSV',
label: __t('clipboard.copyCSV', { defaultMessage : 'Copy as CSV'}),
name: 'CSV',
formatter: clipboardTextFormatter(',', true),
},
json: {
label: 'Copy as JSON',
label: __t('clipboard.copyJSON', { defaultMessage: 'Copy as JSON'}),
name: 'JSON',
formatter: clipboardJsonFormatter(),
},
jsonLines: {
label: 'Copy as JSON lines/NDJSON',
label: __t('clipboard.copyJSONLines', { defaultMessage : 'Copy as JSON lines/NDJSON' }),
name: 'JSON lines/NDJSON',
formatter: clipboardJsonLinesFormatter(),
},
yaml: {
label: 'Copy as YAML',
label: __t('clipboard.copyYAML', { defaultMessage : 'Copy as YAML'}),
name: 'YAML',
formatter: clipboardYamlFormatter(),
},
inserts: {
label: 'Copy as SQL INSERTs',
name: 'SQL INSERTs',
label: __t('clipboard.copySQLInsert', { defaultMessage : 'Copy as SQL INSERTs'}),
name: __t('clipboard.SQLInsert', { defaultMessage : 'SQL INSERTs' }),
formatter: clipboardInsertsFormatter(),
},
updates: {
label: 'Copy as SQL UPDATEs',
name: 'SQL UPDATEs',
label: __t('clipboard.copySQLUpdate', { defaultMessage : 'Copy as SQL UPDATEs'}),
name: __t('clipboard.SQLUpdate', { defaultMessage : 'SQL UPDATEs' }),
formatter: clipboardUpdatesFormatter(),
},
mongoInsert: {
label: 'Copy as Mongo INSERTs',
name: 'Mongo INSERTs',
label: __t('clipboard.copyMongoInsert', { defaultMessage : 'Copy as Mongo INSERTs' }),
name: __t('clipboard.mongoInsert', { defaultMessage : 'Mongo INSERTs' }),
formatter: clipboardMongoInsertFormatter(),
},
};

View File

@@ -3,6 +3,7 @@ import { currentDatabase, getExtensions, getOpenedTabs, loadingSchemaLists, open
import _ from 'lodash';
import { getSchemaList } from './metadataLoaders';
import { showSnackbarError } from './snackbar';
import { _t } from '../translations';
export class LoadingToken {
isCanceled = false;
@@ -57,8 +58,14 @@ export function setSelectedTab(tabid) {
}
export function getObjectTypeFieldLabel(objectTypeField, driver?) {
if (objectTypeField == 'matviews') return 'Materialized Views';
if (objectTypeField == 'collections') return _.startCase(driver?.collectionPluralLabel) ?? 'Collections/Containers';
if (objectTypeField == 'tables') return _t('dbObject.tables', { defaultMessage: 'Tables' });
if (objectTypeField == 'views') return _t('dbObject.views', { defaultMessage: 'Views' });
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 == 'matviews') return _t('dbObject.matviews', { defaultMessage: 'Materialized Views' });
if (objectTypeField == 'collections') return _t('dbObject.collections', { defaultMessage: 'Collections/Containers' });
return _.startCase(objectTypeField);
}

View File

@@ -4,6 +4,7 @@ import invalidateCommands from '../commands/invalidateCommands';
import { runGroupCommand } from '../commands/runCommand';
import { currentDropDownMenu, visibleCommandPalette } from '../stores';
import getAsArray from './getAsArray';
import { _val } from '../translations';
let isContextMenuSupressed = false;
@@ -112,8 +113,9 @@ function mapItem(item, commands) {
if (item.command) {
const command = commands[item.command];
if (command) {
const commandText = item.text || command.menuName || command.toolbarName || command.name;
return {
text: item.text || command.menuName || command.toolbarName || command.name,
text: _val(commandText),
keyText: command.keyText || command.keyTextFromGroup || command.disableHandleKeyText,
onClick: () => {
if (command.isGroupCommand) {

View File

@@ -1,12 +1,14 @@
import type { QuickExportDefinition } from 'dbgate-types';
import { currentArchive, getCurrentArchive, getExtensions } from '../stores';
import hasPermission from './hasPermission';
import { _t } from '../translations'
import { isProApp } from './proTools';
export function createQuickExportMenuItems(handler: (fmt: QuickExportDefinition) => Function, advancedExportMenuItem) {
const extensions = getExtensions();
return [
{
text: 'Export advanced...',
isProApp() && {
text: _t('export.exportAdvanced', { defaultMessage : 'Export advanced...'}),
...advancedExportMenuItem,
},
{ divider: true },
@@ -15,11 +17,11 @@ export function createQuickExportMenuItems(handler: (fmt: QuickExportDefinition)
onClick: handler(fmt),
})),
{ divider: true },
{
text: 'Current archive',
isProApp() && {
text: _t('export.currentArchive', { defaultMessage : 'Current archive'}),
onClick: handler({
extension: 'jsonl',
label: 'Current archive',
label: _t('export.currentArchive', { defaultMessage : 'Current archive'}),
noFilenameDependency: true,
createWriter: (fileName, dataName) => ({
functionName: 'archiveWriter',

View File

@@ -1,14 +1,17 @@
<script lang="ts">
import JsonUiContentRenderer from '../jsonui/JsonUiContentRenderer.svelte';
import { promoWidgetPreview } from '../stores';
import { usePromoWidget } from '../utility/metadataLoaders';
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
const promoWidget = usePromoWidget({});
$: promoWidgetData = $promoWidgetPreview || $promoWidget;
</script>
<WidgetsInnerContainer>
{#if $promoWidget?.state == 'data'}
<JsonUiContentRenderer blocks={$promoWidget?.blocks} />
{#if promoWidgetData?.state == 'data'}
<JsonUiContentRenderer blocks={promoWidgetData?.blocks} passProps={{ validTo: promoWidgetData?.validTo }} />
{/if}
</WidgetsInnerContainer>

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