diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index ba5955874..3c26d2cbb 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -2,7 +2,7 @@ import stream from 'stream'; import { QueryResult } from './query'; import { SqlDialect } from './dialect'; import { SqlDumper } from './dumper'; -import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo } from './dbinfo'; +import { DatabaseInfo, NamedObjectInfo, TableInfo, ViewInfo, ProcedureInfo, FunctionInfo, TriggerInfo, CollectionInfo } from './dbinfo'; import { FilterBehaviour } from './filter-type'; export interface StreamOptions { @@ -115,6 +115,8 @@ export interface EngineDriver extends FilterBehaviourProvider { profilerChartAggregateFunction?: string; profilerChartMeasures?: { label: string; field: string }[]; isElectronOnly?: boolean; + collectionSingularLabel?: string; + collectionPluralLabel?: string; supportedCreateDatabase?: boolean; showConnectionField?: ( field: string, @@ -163,7 +165,7 @@ export interface EngineDriver extends FilterBehaviourProvider { getAuthTypes(): EngineAuthType[]; readCollection(pool: any, options: ReadCollectionOptions): Promise; updateCollection(pool: any, changeSet: any): Promise; - getCollectionUpdateScript(changeSet: any): string; + getCollectionUpdateScript(changeSet: any, collectionInfo: CollectionInfo): string; createDatabase(pool: any, name: string): Promise; dropDatabase(pool: any, name: string): Promise; getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor'): any; diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 57049e89f..d5516f518 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -91,16 +91,14 @@ }; const handleNewCollection = () => { - showModal(InputTextModal, { - value: '', - label: 'New collection/container name', - header: 'Create collection/container', - onConfirm: async newCollection => { + showModal(NewCollectionModal, { + driver, + onConfirm: async values => { runOperationOnDatabase( { conid: connection._id, database: name }, { type: 'createCollection', - collection: newCollection, + collection: values, } ); @@ -294,7 +292,10 @@ return [ { onClick: handleNewQuery, text: 'New query', isNewQuery: true }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewTable, text: 'New table' }, - driver?.databaseEngineTypes?.includes('document') && { onClick: handleNewCollection, text: 'New collection/container' }, + driver?.databaseEngineTypes?.includes('document') && { + onClick: handleNewCollection, + text: `New ${driver?.collectionSingularLabel ?? 'collection/container'}`, + }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleQueryDesigner, text: 'Design query' }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewPerspective, @@ -386,6 +387,7 @@ import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte'; import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte'; + import NewCollectionModal from '../modals/NewCollectionModal.svelte'; export let data; export let passProps; diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 962ae9b32..4100b670c 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -525,8 +525,8 @@ copyTextToClipboard(data.pureName); } else if (menu.isRenameCollection) { showModal(InputTextModal, { - label: 'New collection/container name', - header: 'Rename collection/container', + label: `New collection/container name`, + header: `Rename collection/container`, value: data.pureName, onConfirm: async newName => { const dbid = _.pick(data, ['conid', 'database']); diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index eafc2b225..f48684c6f 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -40,6 +40,7 @@ import { doLogout, internalRedirectTo } from '../clientAuth'; import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte'; import UploadErrorModal from '../modals/UploadErrorModal.svelte'; import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; +import NewCollectionModal from '../modals/NewCollectionModal.svelte'; // function themeCommand(theme: ThemeDefinition) { // return { @@ -287,20 +288,19 @@ registerCommand({ const $currentDatabase = get(currentDatabase); const connection = _.get($currentDatabase, 'connection') || {}; const database = _.get($currentDatabase, 'name'); + const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions()); const dbid = { conid: connection._id, database }; - showModal(InputTextModal, { - value: '', - label: 'New collection/container name', - header: 'Create collection/container', - onConfirm: async newCollection => { + showModal(NewCollectionModal, { + driver, + onConfirm: async values => { // await apiCall('database-connections/run-script', { ...dbid, sql: `db.createCollection('${newCollection}')` }); const resp = await apiCall('database-connections/run-operation', { ...dbid, operation: { type: 'createCollection', - collection: newCollection, + collection: values, }, }); diff --git a/packages/web/src/modals/NewCollectionModal.svelte b/packages/web/src/modals/NewCollectionModal.svelte new file mode 100644 index 000000000..60e5abd8b --- /dev/null +++ b/packages/web/src/modals/NewCollectionModal.svelte @@ -0,0 +1,32 @@ + + + + + + Create {driver?.collectionSingularLabel ?? 'collection/container'} + + + + + + handleSubmit(e.detail)} /> + + + + diff --git a/packages/web/src/tabs/CollectionDataTab.svelte b/packages/web/src/tabs/CollectionDataTab.svelte index 04a9030e8..2dd8fb6d6 100644 --- a/packages/web/src/tabs/CollectionDataTab.svelte +++ b/packages/web/src/tabs/CollectionDataTab.svelte @@ -139,7 +139,7 @@ export function save() { const json = $changeSetStore?.value; const driver = findEngineDriver($connection, $extensions); - const script = driver.getCollectionUpdateScript ? driver.getCollectionUpdateScript(json) : null; + const script = driver.getCollectionUpdateScript ? driver.getCollectionUpdateScript(json, $collectionInfo) : null; if (script) { if (getBoolSettingsValue('skipConfirm.collectionDataSave', false)) { handleConfirmChange(json); diff --git a/packages/web/src/utility/common.ts b/packages/web/src/utility/common.ts index 5c948de71..3951e41df 100644 --- a/packages/web/src/utility/common.ts +++ b/packages/web/src/utility/common.ts @@ -38,9 +38,9 @@ export function setSelectedTab(tabid) { openedTabs.update(tabs => setSelectedTabFunc(tabs, tabid)); } -export function getObjectTypeFieldLabel(objectTypeField) { +export function getObjectTypeFieldLabel(objectTypeField, driver?) { if (objectTypeField == 'matviews') return 'Materialized Views'; - if (objectTypeField == 'collections') return 'Collections/Containers'; + if (objectTypeField == 'collections') return _.startCase(driver?.collectionPluralLabel) ?? 'Collections/Containers'; return _.startCase(objectTypeField); } diff --git a/packages/web/src/widgets/DatabaseWidget.svelte b/packages/web/src/widgets/DatabaseWidget.svelte index 506a20336..cea17cc1c 100644 --- a/packages/web/src/widgets/DatabaseWidget.svelte +++ b/packages/web/src/widgets/DatabaseWidget.svelte @@ -47,7 +47,9 @@ - runCommand('new.collection')}>New collection/container + runCommand('new.collection')} + >New {driver?.collectionSingularLabel ?? 'collection/container'} {/if} {:else} @@ -139,7 +141,7 @@ ({ ...x, conid, database }))} module={databaseObjectAppObject} - groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField)} + groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)} subItemsComponent={SubColumnParamList} isExpandable={data => data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'} diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index 826969511..cb665d064 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -109,7 +109,7 @@ const driver = { const { type } = operation; switch (type) { case 'createCollection': - await this.script(pool, `db.createCollection('${operation.collection}')`); + await this.script(pool, `db.createCollection('${operation.collection.name}')`); case 'dropOperation': await this.script(pool, `db.dropCollection('${operation.collection}')`); default: diff --git a/plugins/dbgate-plugin-mongo/src/frontend/driver.js b/plugins/dbgate-plugin-mongo/src/frontend/driver.js index 6b986950f..1434ac8a3 100644 --- a/plugins/dbgate-plugin-mongo/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/frontend/driver.js @@ -44,6 +44,8 @@ const driver = { { label: 'Max duration', field: 'maxDuration' }, ], databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname', + collectionSingularLabel: 'collection', + collectionPluralLabel: 'collections', getQuerySplitterOptions: () => mongoSplitterOptions, @@ -65,7 +67,7 @@ const driver = { }, ], - getCollectionUpdateScript(changeSet) { + getCollectionUpdateScript(changeSet, collectionInfo) { let res = ''; for (const insert of changeSet.inserts) { res += `db.${insert.pureName}.insertOne(${jsonStringifyWithObjectId({