SYNC: Merge pull request #9 from dbgate/feature/apps

This commit is contained in:
Jan Prochazka
2025-09-11 13:10:36 +02:00
committed by Diflow
parent ef15f299d2
commit 11a4f0ef32
40 changed files with 1770 additions and 754 deletions

View File

@@ -36,6 +36,7 @@
export let filter = null;
export let disableHover = false;
export let divProps = {};
export let additionalIcons = null;
$: isChecked =
checkedObjectsStore && $checkedObjectsStore.find(x => module?.extractKey(data) == module?.extractKey(x));
@@ -160,6 +161,11 @@
/>
</span>
{/if}
{#if additionalIcons}
{#each additionalIcons as ic}
<FontIcon icon={ic.icon} title={ic.title} colorClass={ic.colorClass} />
{/each}
{/if}
{#if extInfo}
<span class="ext-info">
<TokenizedFilteredText text={extInfo} {filter} />

View File

@@ -130,7 +130,7 @@
import openNewTab from '../utility/openNewTab';
import { getDatabaseMenuItems } from './DatabaseAppObject.svelte';
import getElectron from '../utility/getElectron';
import { getDatabaseList, useUsedApps } from '../utility/metadataLoaders';
import { getDatabaseList, useAllApps } from '../utility/metadataLoaders';
import { getLocalStorage } from '../utility/storageCache';
import { apiCall, removeVolatileMapping } from '../utility/api';
import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte';
@@ -383,7 +383,7 @@
$currentDatabase,
$apps,
$openedSingleDatabaseConnections,
data.databasePermissionRole,
data.databasePermissionRole
),
],
@@ -427,7 +427,7 @@
}
}
$: apps = useUsedApps();
$: apps = useAllApps();
</script>
<AppObjectCore

View File

@@ -405,9 +405,25 @@ await dbgateApi.executeQuery(${JSON.stringify(
});
};
const handleCreateNewApp = () => {
showModal(InputTextModal, {
header: 'New application',
label: 'Application name',
value: _.startCase(name),
onConfirm: async appName => {
const newAppId = await apiCall('apps/create-app-from-db', {
appName,
server: connection?.server,
database: name,
});
openApplicationEditor(newAppId);
},
});
};
const driver = findEngineDriver(connection, getExtensions());
const commands = _.flatten((apps || []).map(x => x.commands || []));
const commands = _.flatten((apps || []).map(x => Object.values(x.files || {}).filter(x => x.type == 'command')));
const isSqlOrDoc =
driver?.databaseEngineTypes?.includes('sql') || driver?.databaseEngineTypes?.includes('document');
@@ -564,11 +580,26 @@ await dbgateApi.executeQuery(${JSON.stringify(
text: _t('database.dataDeployer', { defaultMessage: 'Data deployer' }),
},
isProApp() &&
hasPermission(`files/apps/write`) && {
onClick: handleCreateNewApp,
text: _t('database.createNewApplication', { defaultMessage: 'Create new application' }),
},
isProApp() &&
apps?.length > 0 && {
text: _t('database.editApplications', { defaultMessage: 'Edit application' }),
submenu: apps.map((app: any) => ({
text: app.applicationName,
onClick: () => openApplicationEditor(app.appid),
})),
},
{ divider: true },
commands.length > 0 && [
commands.map((cmd: any) => ({
text: cmd.name,
text: cmd.label,
onClick: () => {
showModal(ConfirmSqlModal, {
sql: cmd.sql,
@@ -618,12 +649,12 @@ await dbgateApi.executeQuery(${JSON.stringify(
getConnectionLabel,
} from 'dbgate-tools';
import InputTextModal from '../modals/InputTextModal.svelte';
import { getDatabaseInfo, useUsedApps } from '../utility/metadataLoaders';
import { getDatabaseInfo, useAllApps, useDatabaseInfoPeek } from '../utility/metadataLoaders';
import { openJsonDocument } from '../tabs/JsonTab.svelte';
import { apiCall } from '../utility/api';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import ConfirmSqlModal, { runOperationOnDatabase, saveScriptToDatabase } from '../modals/ConfirmSqlModal.svelte';
import { filterAppsForDatabase } from '../utility/appTools';
import { filterAppsForDatabase, openApplicationEditor } from '../utility/appTools';
import newQuery from '../query/newQuery';
import ConfirmModal from '../modals/ConfirmModal.svelte';
import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte';
@@ -639,7 +670,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
import { getNumberIcon } from '../icons/FontIcon.svelte';
import { getDatabaseClickActionSetting } from '../settings/settingsTools';
import { _t } from '../translations';
import { dataGridRowHeight } from '../datagrid/DataGridRowHeightMeter.svelte';
import { tick } from 'svelte';
export let data;
export let passProps;
@@ -657,8 +688,13 @@ await dbgateApi.executeQuery(${JSON.stringify(
}
$: isPinned = !!$pinnedDatabases.find(x => x?.name == data.name && x?.connection?._id == data.connection?._id);
$: apps = useUsedApps();
$: apps = useAllApps();
$: isLoadingSchemas = $loadingSchemaLists[`${data?.connection?._id}::${data?.name}`];
$: dbInfo = useDatabaseInfoPeek({ conid: data?.connection?._id, database: data?.name });
$: appsForDb = filterAppsForDatabase(data?.connection, data?.name, $apps, $dbInfo);
// $: console.log('AppsForDB:', data?.name, appsForDb);
</script>
<AppObjectCore
@@ -681,6 +717,13 @@ await dbgateApi.executeQuery(${JSON.stringify(
switchCurrentDatabase(data);
}
}}
additionalIcons={appsForDb?.length > 0
? appsForDb.map(ic => ({
icon: ic.applicationIcon || 'img app',
title: ic.applicationName,
colorClass: ic.applicationColor ? `color-icon-${ic.applicationColor}` : undefined,
}))
: null}
on:mousedown={() => {
$focusedConnectionOrDatabase = { conid: data.connection?._id, database: data.name, connection: data.connection };
}}

View File

@@ -45,16 +45,16 @@
schedulerEvents: 'icon scheduler-event',
};
const defaultTabs = {
tables: 'TableDataTab',
collections: 'CollectionDataTab',
views: 'ViewDataTab',
matviews: 'ViewDataTab',
queries: 'QueryDataTab',
procedures: 'SqlObjectTab',
functions: 'SqlObjectTab',
triggers: 'SqlObjectTab',
};
// const defaultTabs = {
// tables: 'TableDataTab',
// collections: 'CollectionDataTab',
// views: 'ViewDataTab',
// matviews: 'ViewDataTab',
// queries: 'QueryDataTab',
// procedures: 'SqlObjectTab',
// functions: 'SqlObjectTab',
// triggers: 'SqlObjectTab',
// };
function createScriptTemplatesSubmenu(objectTypeField) {
return {
@@ -724,7 +724,7 @@
});
const filteredNoEmptySubmenus = filteredSumenus.filter(x => !x.submenu || x.submenu.length > 0);
return filteredNoEmptySubmenus;
}
@@ -741,7 +741,7 @@
export async function openDatabaseObjectDetail(
tabComponent,
scriptTemplate,
{ schemaName, pureName, conid, database, objectTypeField, defaultActionId, isRawMode },
{ schemaName, pureName, conid, database, objectTypeField, defaultActionId, isRawMode, sql },
forceNewTab?,
initialData?,
icon?,
@@ -776,6 +776,7 @@
initialArgs: scriptTemplate ? { scriptTemplate } : null,
defaultActionId,
isRawMode,
sql,
},
},
initialData,
@@ -797,7 +798,7 @@
data,
{ forceNewTab = false, tabPreviewMode = false, focusTab = false } = {}
) {
const { schemaName, pureName, conid, database, objectTypeField } = data;
const { schemaName, pureName, conid, database, objectTypeField, sql } = data;
const driver = findEngineDriver(data, getExtensions());
const activeTab = getActiveTab();
@@ -843,6 +844,7 @@
objectTypeField,
defaultActionId: prefferedAction.defaultActionId,
isRawMode: prefferedAction?.isRawMode ?? false,
sql,
},
forceNewTab,
prefferedAction?.initialData,

View File

@@ -142,6 +142,18 @@
label: 'Model transform file',
};
const apps: FileTypeHandler = isProApp()
? {
icon: 'img app',
format: 'json',
tabComponent: 'AppEditorTab',
folder: 'apps',
currentConnection: false,
extension: 'json',
label: 'Application file',
}
: undefined;
export const SAVED_FILE_HANDLERS = {
sql,
shell,
@@ -154,6 +166,7 @@
modtrans,
datadeploy,
dbcompare,
apps,
};
export const extractKey = data => data.file;

View File

@@ -100,4 +100,12 @@ export const defaultDatabaseObjectAppObjectActions = {
icon: 'img sql-file',
},
],
queries: [
{
label: 'Show query',
tab: 'QueryDataTab',
defaultActionId: 'showAppQuery',
icon: 'img app-query',
},
],
};