mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-19 18:56:00 +00:00
Merge branch 'master' into feature/postgresql-export-bytea
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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) : [];
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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' }),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>',
|
||||
}
|
||||
|
||||
@@ -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 [];
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 ...' }) }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
87
packages/web/src/jsonui/JsonUiCountdown.svelte
Normal file
87
packages/web/src/jsonui/JsonUiCountdown.svelte
Normal 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>
|
||||
35
packages/web/src/jsonui/JsonUiHighlight.svelte
Normal file
35
packages/web/src/jsonui/JsonUiHighlight.svelte
Normal 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>
|
||||
@@ -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">
|
||||
|
||||
21
packages/web/src/jsonui/JsonUiLinkButtonBlock.svelte
Normal file
21
packages/web/src/jsonui/JsonUiLinkButtonBlock.svelte
Normal 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>
|
||||
15
packages/web/src/jsonui/JsonUiMarkdown.svelte
Normal file
15
packages/web/src/jsonui/JsonUiMarkdown.svelte
Normal 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>
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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))}
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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' },
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'}) }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
59
packages/web/src/modals/ShowSqlModal.svelte
Normal file
59
packages/web/src/modals/ShowSqlModal.svelte
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user