fix(mongodb): offer rename collection on legacy agent connections

This commit is contained in:
Loc Nguyen
2026-09-22 11:05:35 +08:00
committed by GitHub
parent 9fa61d53b6
commit 808317e0e7
5 changed files with 33 additions and 23 deletions
@@ -277,7 +277,8 @@ describe("MongoDB sidebar mutation runtime", () => {
activeNode.value = mongoCollectionNode();
expect(feature.canDropMongoCollection.value).toBe(true);
expect(feature.canDropAllMongoIndexes.value).toBe(false);
expect(feature.canRenameMongoCollection.value).toBe(false);
// The Legacy Agent supports renameCollection (capability-gated in the backend).
expect(feature.canRenameMongoCollection.value).toBe(true);
expect(feature.canCloneMongoCollection.value).toBe(true);
expect(feature.canCreateMongoIndex.value).toBe(false);
activeNode.value = mongoIndexesGroupNode();
@@ -177,6 +177,33 @@ function milvusCollectionNode(): TreeNode {
};
}
describe("MongoDB collection rename availability", () => {
beforeEach(() => {
setActivePinia(createPinia());
vi.clearAllMocks();
});
it("offers rename on both the native driver and the Legacy Agent", () => {
// The Agent has renameCollection (capability-gated in the backend), so the menu no longer
// hides the action on legacy connections; a read-only connection still gets nothing.
for (const driver_profile of [undefined, "mongodb-native", "mongodb-legacy"]) {
mocks.getConfig.mockReturnValue({ id: "conn-1", name: "Mongo", db_type: "mongodb", host: "localhost", port: 27017, username: "op", password: "", driver_profile });
const activeNode = shallowRef(collectionNode());
const { canRenameMongoCollection } = useSidebarDatabaseSpecificMutationRuntime({
activeNode,
connectionStore: { getConfig: mocks.getConfig, ensureConnected: mocks.ensureConnected, loadMongoCollections: mocks.loadMongoCollections, treeNodes: [] } as any,
});
expect(canRenameMongoCollection.value, `driver_profile=${driver_profile}`).toBe(true);
}
mocks.getConfig.mockReturnValue({ id: "conn-1", name: "Mongo", db_type: "mongodb", host: "localhost", port: 27017, username: "op", password: "", driver_profile: "mongodb-legacy", read_only: true });
const { canRenameMongoCollection } = useSidebarDatabaseSpecificMutationRuntime({
activeNode: shallowRef(collectionNode()),
connectionStore: { getConfig: mocks.getConfig, ensureConnected: mocks.ensureConnected, loadMongoCollections: mocks.loadMongoCollections, treeNodes: [] } as any,
});
expect(canRenameMongoCollection.value).toBe(false);
});
});
describe("Milvus collection rename", () => {
beforeEach(() => {
setActivePinia(createPinia());
@@ -33,7 +33,7 @@ import {
type MongoIndexSpecSnapshot,
} from "@/lib/sidebar/mongoCollectionMutation";
import { elasticsearchClearIndexPreview, isElasticsearchProtocolIndex, isPartialElasticsearchClear, notifyElasticsearchIndexCleared } from "@/lib/sidebar/elasticsearchIndexActions";
import { supportsMongoAllDriverMutations, supportsMongoIndexMutations, supportsNativeMongoDriverMutations } from "@/lib/mongo/mongoCapabilities";
import { supportsMongoAllDriverMutations, supportsMongoIndexMutations } from "@/lib/mongo/mongoCapabilities";
import { runMongoSidebarMutation } from "@/lib/sidebar/runMongoSidebarMutation";
import { executeWithProductionContextGuard } from "@/lib/database/productionExecutionGuard";
import { connectionIsEffectivelyReadOnly } from "@/lib/database/readOnlyWriteAccess";
@@ -121,10 +121,6 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
return !!node.connectionId && supportsMongoAllDriverMutations(connectionStore.getConfig(node.connectionId));
}
function usesNativeMongoDriver(node: Pick<TreeNode, "connectionId">): boolean {
return !!node.connectionId && supportsNativeMongoDriverMutations(connectionStore.getConfig(node.connectionId));
}
function canMutateMongoIndexes(node: TreeNode): boolean {
return !!node.connectionId && supportsMongoIndexMutations(connectionStore.getConfig(node.connectionId), mongoCollectionKindFromNode(node));
}
@@ -150,7 +146,7 @@ export function useSidebarDatabaseSpecificMutationRuntime(options: SidebarDataba
}
function canRenameMongoCollectionNode(node: TreeNode): boolean {
return canMutateMilvusCollectionNode(node) || (canMutateMongoCollectionNode(node) && usesNativeMongoDriver(node) && isRenamableMongoCollection(node.label, mongoCollectionKindFromNode(node)));
return canMutateMilvusCollectionNode(node) || (canMutateMongoCollectionNode(node) && isRenamableMongoCollection(node.label, mongoCollectionKindFromNode(node)));
}
function canCloneMongoCollectionNode(node: TreeNode): boolean {
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { isMongoLegacyDriverProfile, mongoCollectionSupportsIndexes, supportsMongoAllDriverMutations, supportsMongoIndexMutations, supportsNativeMongoDriverMutations } from "@/lib/mongo/mongoCapabilities";
import { isMongoLegacyDriverProfile, mongoCollectionSupportsIndexes, supportsMongoAllDriverMutations, supportsMongoIndexMutations } from "@/lib/mongo/mongoCapabilities";
describe("MongoDB driver mutation capabilities", () => {
it("keeps index and drop mutations available through both native and Legacy drivers", () => {
@@ -12,7 +12,6 @@ describe("MongoDB driver mutation capabilities", () => {
expect(supportsMongoAllDriverMutations(readOnly)).toBe(false);
expect(supportsMongoIndexMutations(readOnly, "collection")).toBe(false);
expect(supportsNativeMongoDriverMutations({ ...readOnly, driver_profile: "mongodb" })).toBe(false);
});
it("keeps index metadata visible on read-only collections", () => {
@@ -32,14 +31,6 @@ describe("MongoDB driver mutation capabilities", () => {
expect(supportsMongoIndexMutations(native, " VIEW ")).toBe(false);
});
it("reserves native-only mutations for the native MongoDB driver", () => {
expect(supportsNativeMongoDriverMutations({ db_type: "mongodb", driver_profile: "mongodb" })).toBe(true);
expect(supportsNativeMongoDriverMutations({ db_type: "mongodb", driver_profile: undefined })).toBe(true);
expect(supportsNativeMongoDriverMutations({ db_type: "mongodb", driver_profile: "mongodb-legacy" })).toBe(false);
expect(supportsNativeMongoDriverMutations({ db_type: "mongodb", driver_profile: "legacy" })).toBe(false);
expect(supportsNativeMongoDriverMutations({ db_type: "mongodb", driver_profile: "MongoDB_Legacy" })).toBe(false);
});
it("recognizes historical Legacy profile spellings", () => {
expect(isMongoLegacyDriverProfile("mongodb-legacy")).toBe(true);
expect(isMongoLegacyDriverProfile(" mongodb_legacy ")).toBe(true);
@@ -49,6 +40,6 @@ describe("MongoDB driver mutation capabilities", () => {
it("does not grant MongoDB mutations to another connection type", () => {
expect(supportsMongoAllDriverMutations({ db_type: "postgres", driver_profile: undefined })).toBe(false);
expect(supportsNativeMongoDriverMutations(undefined)).toBe(false);
expect(supportsMongoAllDriverMutations(undefined)).toBe(false);
});
});
@@ -22,8 +22,3 @@ export function mongoCollectionSupportsIndexes(collectionKind?: string): boolean
export function supportsMongoIndexMutations(connection?: MongoConnectionProfile, collectionKind?: string): boolean {
return supportsMongoAllDriverMutations(connection) && mongoCollectionSupportsIndexes(collectionKind);
}
/** Capabilities which require the native Rust MongoDB driver. */
export function supportsNativeMongoDriverMutations(connection?: MongoConnectionProfile): boolean {
return supportsMongoAllDriverMutations(connection) && !isMongoLegacyDriverProfile(connection?.driver_profile);
}