feat(mongodb): rename collections from sidebar
This commit is contained in:
1 parent
809500fd52
commit
9a83b46f00
26 files changed
+1105
-93
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { computed, type ShallowRef } from "vue";
|
||||
import { computed, watch, type ShallowRef } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
@@ -6,6 +6,8 @@ import type { TreeNode } from "@/types/database";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
import { findSidebarActionTarget } from "@/lib/sidebar/sidebarActionTarget";
|
||||
import { isRenamableMongoCollection, mongoCollectionKindFromNode, mongoDropAllIndexesPreview, mongoDropCollectionPreview, mongoDropDatabasePreview, mongoDropIndexPreview, mongoRenameCollectionPreview } from "@/lib/sidebar/mongoCollectionMutation";
|
||||
import { runMongoSidebarMutation } from "@/lib/sidebar/runMongoSidebarMutation";
|
||||
import {
|
||||
sidebarDangerTarget,
|
||||
sidebarFormTarget,
|
||||
@@ -24,7 +26,14 @@ import {
|
||||
dropMongoIndexLoading,
|
||||
showDropAllMongoIndexesConfirm,
|
||||
dropAllMongoIndexesLoading,
|
||||
showDropDatabaseConfirm,
|
||||
dropDatabaseLoading,
|
||||
showFlushRedisDbConfirm,
|
||||
showRenameMongoCollectionDialog,
|
||||
renameMongoCollectionName,
|
||||
renameMongoCollectionError,
|
||||
renameMongoCollectionPreview,
|
||||
renameMongoCollectionLoading,
|
||||
} from "@/components/sidebar/sidebarTreeDialogState";
|
||||
|
||||
interface SidebarDatabaseSpecificMutationRuntimeOptions {
|
||||
@@ -32,6 +41,13 @@ interface SidebarDatabaseSpecificMutationRuntimeOptions {
|
||||
connectionStore: ReturnType<typeof useConnectionStore>;
|
||||
}
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
if (error && typeof error === "object" && "message" in error) {
|
||||
return String((error as { message?: unknown }).message || error);
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDatabaseSpecificMutationRuntimeOptions) {
|
||||
const { t } = useI18n();
|
||||
const { toast } = useToast();
|
||||
@@ -42,11 +58,77 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
|
||||
return activeNode.value.type === "mongo-db" && !!activeNode.value.database && config?.driver_profile !== "mongodb-legacy";
|
||||
});
|
||||
|
||||
const canDropMongoCollection = computed(() => {
|
||||
const config = activeNode.value.connectionId ? connectionStore.getConfig(activeNode.value.connectionId) : undefined;
|
||||
return activeNode.value.type === "mongo-collection" && !!activeNode.value.database && config?.driver_profile !== "mongodb-legacy";
|
||||
function canMutateMongoCollectionNode(node: TreeNode): boolean {
|
||||
if (node.type !== "mongo-collection" || !node.connectionId || !node.database) return false;
|
||||
const config = connectionStore.getConfig(node.connectionId);
|
||||
return config?.db_type === "mongodb" && config.driver_profile !== "mongodb-legacy";
|
||||
}
|
||||
|
||||
function canRenameMongoCollectionNode(node: TreeNode): boolean {
|
||||
return canMutateMongoCollectionNode(node) && isRenamableMongoCollection(node.label, mongoCollectionKindFromNode(node));
|
||||
}
|
||||
|
||||
const canDropMongoCollection = computed(() => canMutateMongoCollectionNode(activeNode.value));
|
||||
const canRenameMongoCollection = computed(() => canRenameMongoCollectionNode(activeNode.value));
|
||||
|
||||
function toastMutationError(error: unknown) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: errorMessage(error) }), 5000);
|
||||
}
|
||||
|
||||
function prepareRenameMongoCollectionDialog() {
|
||||
renameMongoCollectionName.value = activeNode.value.label;
|
||||
renameMongoCollectionError.value = "";
|
||||
renameMongoCollectionPreview.value = "";
|
||||
renameMongoCollectionLoading.value = false;
|
||||
showRenameMongoCollectionDialog.value = true;
|
||||
}
|
||||
|
||||
function refreshRenameMongoCollectionPreview() {
|
||||
const node = sidebarFormTarget.value ?? activeNode.value;
|
||||
// Preserve identifier whitespace exactly as entered; only reject empty names.
|
||||
const newName = renameMongoCollectionName.value;
|
||||
if (!showRenameMongoCollectionDialog.value || !canRenameMongoCollectionNode(node) || !node.database || !newName || newName === node.label) {
|
||||
renameMongoCollectionPreview.value = "";
|
||||
return;
|
||||
}
|
||||
renameMongoCollectionPreview.value = mongoRenameCollectionPreview(node.database, node.label, newName);
|
||||
}
|
||||
|
||||
watch([showRenameMongoCollectionDialog, renameMongoCollectionName, () => activeNode.value.label, () => activeNode.value.database], () => {
|
||||
refreshRenameMongoCollectionPreview();
|
||||
});
|
||||
|
||||
async function confirmRenameMongoCollection() {
|
||||
const node = sidebarFormTarget.value ?? activeNode.value;
|
||||
const connectionId = node.connectionId;
|
||||
const database = node.database;
|
||||
const newName = renameMongoCollectionName.value;
|
||||
if (!canRenameMongoCollectionNode(node) || !connectionId || !database || !newName || newName === node.label) {
|
||||
return;
|
||||
}
|
||||
const oldName = node.label;
|
||||
renameMongoCollectionError.value = "";
|
||||
await runMongoSidebarMutation({
|
||||
connection: connectionStore.getConfig(connectionId),
|
||||
database,
|
||||
reviewText: mongoRenameCollectionPreview(database, oldName, newName),
|
||||
source: t("production.sourceSidebar"),
|
||||
loading: renameMongoCollectionLoading,
|
||||
beforeExecute: () => connectionStore.ensureConnected(connectionId),
|
||||
execute: async () => {
|
||||
await api.mongoRenameCollection(connectionId, database, oldName, newName);
|
||||
await connectionStore.loadMongoCollections(connectionId, database);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast(t("contextMenu.renameObjectSuccess", { oldName, newName }), 3000);
|
||||
showRenameMongoCollectionDialog.value = false;
|
||||
},
|
||||
onError: (error) => {
|
||||
renameMongoCollectionError.value = translateBackendError(t, errorMessage(error));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function mongoIndexNameForNode(node: TreeNode): string {
|
||||
if (node.type !== "index") return "";
|
||||
return node.meta && "name" in node.meta ? node.meta.name : node.label.replace(/\s+\(.+\)$/, "");
|
||||
@@ -60,17 +142,14 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
|
||||
|
||||
const canDropMongoIndex = computed(() => canDropMongoIndexNode(activeNode.value));
|
||||
|
||||
function mongoIndexDropPreview(node: Pick<TreeNode, "tableName">, indexName: string): string {
|
||||
return `db.getCollection(${JSON.stringify(node.tableName || "")}).dropIndex(${JSON.stringify(indexName)})`;
|
||||
function mongoIndexDropPreview(node: Pick<TreeNode, "database" | "tableName">, indexName: string): string {
|
||||
return mongoDropIndexPreview(node.database || "", node.tableName || "", indexName);
|
||||
}
|
||||
|
||||
const canDropAllMongoIndexes = computed(() => {
|
||||
const config = activeNode.value.connectionId ? connectionStore.getConfig(activeNode.value.connectionId) : undefined;
|
||||
return activeNode.value.type === "mongo-collection" && !!activeNode.value.database && config?.db_type === "mongodb" && config.driver_profile !== "mongodb-legacy";
|
||||
});
|
||||
const canDropAllMongoIndexes = computed(() => canMutateMongoCollectionNode(activeNode.value));
|
||||
|
||||
function mongoDropAllIndexesPreview(node: Pick<TreeNode, "label">): string {
|
||||
return `db.getCollection(${JSON.stringify(node.label)}).dropIndexes()`;
|
||||
function mongoDropAllIndexesPreviewForNode(node: Pick<TreeNode, "database" | "label">): string {
|
||||
return mongoDropAllIndexesPreview(node.database || "", node.label);
|
||||
}
|
||||
|
||||
function openCreateNacosNamespaceDialog() {
|
||||
@@ -168,21 +247,53 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmDropMongoDatabase() {
|
||||
const node = sidebarDangerTarget.value ?? activeNode.value;
|
||||
const connectionId = node.connectionId;
|
||||
const database = node.database;
|
||||
if (node.type !== "mongo-db" || !connectionId || !database) return;
|
||||
await runMongoSidebarMutation({
|
||||
connection: connectionStore.getConfig(connectionId),
|
||||
database,
|
||||
reviewText: mongoDropDatabasePreview(database),
|
||||
source: t("production.sourceSidebar"),
|
||||
loading: dropDatabaseLoading,
|
||||
beforeExecute: () => connectionStore.ensureConnected(connectionId),
|
||||
execute: async () => {
|
||||
await api.mongoDropDatabase(connectionId, database);
|
||||
await connectionStore.loadMongoDatabases(connectionId);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast(t("contextMenu.dropDatabaseSuccess", { name: node.label }), 3000);
|
||||
showDropDatabaseConfirm.value = false;
|
||||
},
|
||||
onError: toastMutationError,
|
||||
});
|
||||
}
|
||||
|
||||
async function confirmDropMongoCollection() {
|
||||
const node = sidebarDangerTarget.value ?? activeNode.value;
|
||||
if (node.type !== "mongo-collection" || !node.connectionId || !node.database || dropMongoCollectionLoading.value) return;
|
||||
dropMongoCollectionLoading.value = true;
|
||||
try {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
await api.mongoDropCollection(node.connectionId, node.database, node.label);
|
||||
toast(t("contextMenu.dropCollectionSuccess", { name: node.label }), 3000);
|
||||
await connectionStore.loadMongoCollections(node.connectionId, node.database);
|
||||
showDropMongoCollectionConfirm.value = false;
|
||||
} catch (error: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: error?.message || String(error) }), 5000);
|
||||
} finally {
|
||||
dropMongoCollectionLoading.value = false;
|
||||
}
|
||||
const connectionId = node.connectionId;
|
||||
const database = node.database;
|
||||
if (!canMutateMongoCollectionNode(node) || !connectionId || !database) return;
|
||||
const collectionName = node.label;
|
||||
await runMongoSidebarMutation({
|
||||
connection: connectionStore.getConfig(connectionId),
|
||||
database,
|
||||
reviewText: mongoDropCollectionPreview(database, collectionName),
|
||||
source: t("production.sourceSidebar"),
|
||||
loading: dropMongoCollectionLoading,
|
||||
beforeExecute: () => connectionStore.ensureConnected(connectionId),
|
||||
execute: async () => {
|
||||
await api.mongoDropCollection(connectionId, database, collectionName);
|
||||
await connectionStore.loadMongoCollections(connectionId, database);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast(t("contextMenu.dropCollectionSuccess", { name: collectionName }), 3000);
|
||||
showDropMongoCollectionConfirm.value = false;
|
||||
},
|
||||
onError: toastMutationError,
|
||||
});
|
||||
}
|
||||
|
||||
function mongoIndexesGroupNodeId(node: Pick<TreeNode, "connectionId" | "database" | "schema" | "tableName" | "label">): string | null {
|
||||
@@ -199,48 +310,73 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
|
||||
|
||||
async function confirmDropMongoIndex() {
|
||||
const node = sidebarDangerTarget.value ?? activeNode.value;
|
||||
if (!canDropMongoIndexNode(node) || !node.connectionId || !node.database || !node.tableName || dropMongoIndexLoading.value) return;
|
||||
dropMongoIndexLoading.value = true;
|
||||
try {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
const indexName = mongoIndexNameForNode(node);
|
||||
await api.mongoDropIndexes(node.connectionId, node.database, node.tableName, JSON.stringify(indexName), true);
|
||||
toast(t("contextMenu.dropTableChildObjectSuccess", { name: indexName }), 3000);
|
||||
showDropMongoIndexConfirm.value = false;
|
||||
await refreshMongoIndexTree(node);
|
||||
} catch (error: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: error?.message || String(error) }), 5000);
|
||||
} finally {
|
||||
dropMongoIndexLoading.value = false;
|
||||
}
|
||||
const connectionId = node.connectionId;
|
||||
const database = node.database;
|
||||
const tableName = node.tableName;
|
||||
if (!canDropMongoIndexNode(node) || !connectionId || !database || !tableName) return;
|
||||
const indexName = mongoIndexNameForNode(node);
|
||||
await runMongoSidebarMutation({
|
||||
connection: connectionStore.getConfig(connectionId),
|
||||
database,
|
||||
reviewText: mongoDropIndexPreview(database, tableName, indexName),
|
||||
source: t("production.sourceSidebar"),
|
||||
loading: dropMongoIndexLoading,
|
||||
beforeExecute: () => connectionStore.ensureConnected(connectionId),
|
||||
execute: async () => {
|
||||
await api.mongoDropIndexes(connectionId, database, tableName, JSON.stringify(indexName), true);
|
||||
await refreshMongoIndexTree(node);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast(t("contextMenu.dropTableChildObjectSuccess", { name: indexName }), 3000);
|
||||
showDropMongoIndexConfirm.value = false;
|
||||
},
|
||||
onError: toastMutationError,
|
||||
});
|
||||
}
|
||||
|
||||
async function confirmDropAllMongoIndexes() {
|
||||
const node = sidebarDangerTarget.value ?? activeNode.value;
|
||||
if (node.type !== "mongo-collection" || !node.connectionId || !node.database || dropAllMongoIndexesLoading.value) return;
|
||||
dropAllMongoIndexesLoading.value = true;
|
||||
try {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
const result = await api.mongoDropIndexes(node.connectionId, node.database, node.label, undefined, false);
|
||||
toast(t("contextMenu.dropAllIndexesSuccess", { count: result.dropped_names.length, name: node.label }), 3000);
|
||||
showDropAllMongoIndexesConfirm.value = false;
|
||||
await refreshMongoIndexTree(node);
|
||||
} catch (error: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: error?.message || String(error) }), 5000);
|
||||
} finally {
|
||||
dropAllMongoIndexesLoading.value = false;
|
||||
}
|
||||
const connectionId = node.connectionId;
|
||||
const database = node.database;
|
||||
if (!canMutateMongoCollectionNode(node) || !connectionId || !database) return;
|
||||
const collectionName = node.label;
|
||||
await runMongoSidebarMutation({
|
||||
connection: connectionStore.getConfig(connectionId),
|
||||
database,
|
||||
reviewText: mongoDropAllIndexesPreview(database, collectionName),
|
||||
source: t("production.sourceSidebar"),
|
||||
loading: dropAllMongoIndexesLoading,
|
||||
beforeExecute: () => connectionStore.ensureConnected(connectionId),
|
||||
execute: async () => {
|
||||
const result = await api.mongoDropIndexes(connectionId, database, collectionName, undefined, false);
|
||||
await refreshMongoIndexTree(node);
|
||||
return result;
|
||||
},
|
||||
onSuccess: (result) => {
|
||||
toast(t("contextMenu.dropAllIndexesSuccess", { count: result.dropped_names.length, name: collectionName }), 3000);
|
||||
showDropAllMongoIndexesConfirm.value = false;
|
||||
},
|
||||
onError: toastMutationError,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
canDropMongoDatabase,
|
||||
canDropMongoCollection,
|
||||
canRenameMongoCollection,
|
||||
prepareRenameMongoCollectionDialog,
|
||||
confirmRenameMongoCollection,
|
||||
showRenameMongoCollectionDialog,
|
||||
renameMongoCollectionName,
|
||||
renameMongoCollectionError,
|
||||
renameMongoCollectionPreview,
|
||||
renameMongoCollectionLoading,
|
||||
mongoIndexNameForNode,
|
||||
canDropMongoIndexNode,
|
||||
canDropMongoIndex,
|
||||
mongoIndexDropPreview,
|
||||
canDropAllMongoIndexes,
|
||||
mongoDropAllIndexesPreview,
|
||||
mongoDropAllIndexesPreview: mongoDropAllIndexesPreviewForNode,
|
||||
openCreateNacosNamespaceDialog,
|
||||
confirmCreateNacosNamespace,
|
||||
openEditNacosNamespaceDialog,
|
||||
@@ -250,6 +386,7 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
|
||||
dropAllMongoIndexes,
|
||||
flushRedisDb,
|
||||
confirmFlushRedisDb,
|
||||
confirmDropMongoDatabase,
|
||||
confirmDropMongoCollection,
|
||||
confirmDropMongoIndex,
|
||||
confirmDropAllMongoIndexes,
|
||||
|
||||
Reference in new issue
Block a user