new collection modal refactor

This commit is contained in:
Jan Prochazka
2024-08-22 09:43:33 +02:00
parent 869e837ee5
commit 77b42e6a04
11 changed files with 67 additions and 25 deletions

View File

@@ -2,7 +2,7 @@ import stream from 'stream';
import { QueryResult } from './query'; import { QueryResult } from './query';
import { SqlDialect } from './dialect'; import { SqlDialect } from './dialect';
import { SqlDumper } from './dumper'; 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'; import { FilterBehaviour } from './filter-type';
export interface StreamOptions { export interface StreamOptions {
@@ -115,6 +115,8 @@ export interface EngineDriver extends FilterBehaviourProvider {
profilerChartAggregateFunction?: string; profilerChartAggregateFunction?: string;
profilerChartMeasures?: { label: string; field: string }[]; profilerChartMeasures?: { label: string; field: string }[];
isElectronOnly?: boolean; isElectronOnly?: boolean;
collectionSingularLabel?: string;
collectionPluralLabel?: string;
supportedCreateDatabase?: boolean; supportedCreateDatabase?: boolean;
showConnectionField?: ( showConnectionField?: (
field: string, field: string,
@@ -163,7 +165,7 @@ export interface EngineDriver extends FilterBehaviourProvider {
getAuthTypes(): EngineAuthType[]; getAuthTypes(): EngineAuthType[];
readCollection(pool: any, options: ReadCollectionOptions): Promise<any>; readCollection(pool: any, options: ReadCollectionOptions): Promise<any>;
updateCollection(pool: any, changeSet: any): Promise<any>; updateCollection(pool: any, changeSet: any): Promise<any>;
getCollectionUpdateScript(changeSet: any): string; getCollectionUpdateScript(changeSet: any, collectionInfo: CollectionInfo): string;
createDatabase(pool: any, name: string): Promise; createDatabase(pool: any, name: string): Promise;
dropDatabase(pool: any, name: string): Promise; dropDatabase(pool: any, name: string): Promise;
getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor'): any; getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor'): any;

View File

@@ -91,16 +91,14 @@
}; };
const handleNewCollection = () => { const handleNewCollection = () => {
showModal(InputTextModal, { showModal(NewCollectionModal, {
value: '', driver,
label: 'New collection/container name', onConfirm: async values => {
header: 'Create collection/container',
onConfirm: async newCollection => {
runOperationOnDatabase( runOperationOnDatabase(
{ conid: connection._id, database: name }, { conid: connection._id, database: name },
{ {
type: 'createCollection', type: 'createCollection',
collection: newCollection, collection: values,
} }
); );
@@ -294,7 +292,10 @@
return [ return [
{ onClick: handleNewQuery, text: 'New query', isNewQuery: true }, { onClick: handleNewQuery, text: 'New query', isNewQuery: true },
driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewTable, text: 'New table' }, 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: handleQueryDesigner, text: 'Design query' },
driver?.databaseEngineTypes?.includes('sql') && { driver?.databaseEngineTypes?.includes('sql') && {
onClick: handleNewPerspective, onClick: handleNewPerspective,
@@ -386,6 +387,7 @@
import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte'; import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte';
import ConfirmModal from '../modals/ConfirmModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte';
import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte'; import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte';
import NewCollectionModal from '../modals/NewCollectionModal.svelte';
export let data; export let data;
export let passProps; export let passProps;

View File

@@ -525,8 +525,8 @@
copyTextToClipboard(data.pureName); copyTextToClipboard(data.pureName);
} else if (menu.isRenameCollection) { } else if (menu.isRenameCollection) {
showModal(InputTextModal, { showModal(InputTextModal, {
label: 'New collection/container name', label: `New collection/container name`,
header: 'Rename collection/container', header: `Rename collection/container`,
value: data.pureName, value: data.pureName,
onConfirm: async newName => { onConfirm: async newName => {
const dbid = _.pick(data, ['conid', 'database']); const dbid = _.pick(data, ['conid', 'database']);

View File

@@ -40,6 +40,7 @@ import { doLogout, internalRedirectTo } from '../clientAuth';
import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte'; import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte';
import UploadErrorModal from '../modals/UploadErrorModal.svelte'; import UploadErrorModal from '../modals/UploadErrorModal.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import NewCollectionModal from '../modals/NewCollectionModal.svelte';
// function themeCommand(theme: ThemeDefinition) { // function themeCommand(theme: ThemeDefinition) {
// return { // return {
@@ -287,20 +288,19 @@ registerCommand({
const $currentDatabase = get(currentDatabase); const $currentDatabase = get(currentDatabase);
const connection = _.get($currentDatabase, 'connection') || {}; const connection = _.get($currentDatabase, 'connection') || {};
const database = _.get($currentDatabase, 'name'); const database = _.get($currentDatabase, 'name');
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
const dbid = { conid: connection._id, database }; const dbid = { conid: connection._id, database };
showModal(InputTextModal, { showModal(NewCollectionModal, {
value: '', driver,
label: 'New collection/container name', onConfirm: async values => {
header: 'Create collection/container',
onConfirm: async newCollection => {
// await apiCall('database-connections/run-script', { ...dbid, sql: `db.createCollection('${newCollection}')` }); // await apiCall('database-connections/run-script', { ...dbid, sql: `db.createCollection('${newCollection}')` });
const resp = await apiCall('database-connections/run-operation', { const resp = await apiCall('database-connections/run-operation', {
...dbid, ...dbid,
operation: { operation: {
type: 'createCollection', type: 'createCollection',
collection: newCollection, collection: values,
}, },
}); });

View File

@@ -0,0 +1,32 @@
<script lang="ts">
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
export let onConfirm;
export let driver;
const handleSubmit = async values => {
closeCurrentModal();
onConfirm(values);
};
</script>
<FormProvider initialValues={{ name: '' }}>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">
Create {driver?.collectionSingularLabel ?? 'collection/container'}
</svelte:fragment>
<FormTextField label={`New ${driver?.collectionSingularLabel ?? 'collection/container'} name`} name="name" focused />
<svelte:fragment slot="footer">
<FormSubmit value="OK" on:click={e => handleSubmit(e.detail)} />
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} />
</svelte:fragment>
</ModalBase>
</FormProvider>

View File

@@ -139,7 +139,7 @@
export function save() { export function save() {
const json = $changeSetStore?.value; const json = $changeSetStore?.value;
const driver = findEngineDriver($connection, $extensions); 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 (script) {
if (getBoolSettingsValue('skipConfirm.collectionDataSave', false)) { if (getBoolSettingsValue('skipConfirm.collectionDataSave', false)) {
handleConfirmChange(json); handleConfirmChange(json);

View File

@@ -38,9 +38,9 @@ export function setSelectedTab(tabid) {
openedTabs.update(tabs => setSelectedTabFunc(tabs, tabid)); openedTabs.update(tabs => setSelectedTabFunc(tabs, tabid));
} }
export function getObjectTypeFieldLabel(objectTypeField) { export function getObjectTypeFieldLabel(objectTypeField, driver?) {
if (objectTypeField == 'matviews') return 'Materialized Views'; if (objectTypeField == 'matviews') return 'Materialized Views';
if (objectTypeField == 'collections') return 'Collections/Containers'; if (objectTypeField == 'collections') return _.startCase(driver?.collectionPluralLabel) ?? 'Collections/Containers';
return _.startCase(objectTypeField); return _.startCase(objectTypeField);
} }

View File

@@ -47,7 +47,9 @@
</WidgetColumnBarItem> </WidgetColumnBarItem>
<WidgetColumnBarItem <WidgetColumnBarItem
title={driver?.databaseEngineTypes?.includes('document') ? 'Collections/containers' : 'Tables, views, functions'} title={driver?.databaseEngineTypes?.includes('document')
? driver?.collectionPluralLabel ?? 'Collections/containers'
: 'Tables, views, functions'}
name="dbObjects" name="dbObjects"
storageName="dbObjectsWidget" storageName="dbObjectsWidget"
skip={!( skip={!(

View File

@@ -120,7 +120,9 @@
{/if} {/if}
{#if driver?.databaseEngineTypes?.includes('document')} {#if driver?.databaseEngineTypes?.includes('document')}
<div class="m-1" /> <div class="m-1" />
<InlineButton on:click={() => runCommand('new.collection')}>New collection/container</InlineButton> <InlineButton on:click={() => runCommand('new.collection')}
>New {driver?.collectionSingularLabel ?? 'collection/container'}</InlineButton
>
{/if} {/if}
</WidgetsInnerContainer> </WidgetsInnerContainer>
{:else} {:else}
@@ -139,7 +141,7 @@
<AppObjectList <AppObjectList
list={objectList.map(x => ({ ...x, conid, database }))} list={objectList.map(x => ({ ...x, conid, database }))}
module={databaseObjectAppObject} module={databaseObjectAppObject}
groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField)} groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)}
subItemsComponent={SubColumnParamList} subItemsComponent={SubColumnParamList}
isExpandable={data => isExpandable={data =>
data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'} data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'}

View File

@@ -109,7 +109,7 @@ const driver = {
const { type } = operation; const { type } = operation;
switch (type) { switch (type) {
case 'createCollection': case 'createCollection':
await this.script(pool, `db.createCollection('${operation.collection}')`); await this.script(pool, `db.createCollection('${operation.collection.name}')`);
case 'dropOperation': case 'dropOperation':
await this.script(pool, `db.dropCollection('${operation.collection}')`); await this.script(pool, `db.dropCollection('${operation.collection}')`);
default: default:

View File

@@ -44,6 +44,8 @@ const driver = {
{ label: 'Max duration', field: 'maxDuration' }, { label: 'Max duration', field: 'maxDuration' },
], ],
databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname', databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname',
collectionSingularLabel: 'collection',
collectionPluralLabel: 'collections',
getQuerySplitterOptions: () => mongoSplitterOptions, getQuerySplitterOptions: () => mongoSplitterOptions,
@@ -65,7 +67,7 @@ const driver = {
}, },
], ],
getCollectionUpdateScript(changeSet) { getCollectionUpdateScript(changeSet, collectionInfo) {
let res = ''; let res = '';
for (const insert of changeSet.inserts) { for (const insert of changeSet.inserts) {
res += `db.${insert.pureName}.insertOne(${jsonStringifyWithObjectId({ res += `db.${insert.pureName}.insertOne(${jsonStringifyWithObjectId({