🐛 fix(connection-package): 导出/导入连接包携带 Redis DB 别名

- 连接包 payload 与导出选项支持 redisDbAliases(连接 ID → db 序号 → 别名)
- 导入返回 ConnectionPackageImportResult,一并恢复别名映射
- 前端导出时注入 appearance.redisDbAliases,导入后 merge 回 appearance
- 补充别名往返测试与 mergeRedisDbAliases 单元测试
This commit is contained in:
Syngnat
2026-07-09 13:57:32 +08:00
parent 097826508a
commit 901b436107
12 changed files with 400 additions and 68 deletions

View File

@@ -4,6 +4,7 @@ import {
MAX_REDIS_DB_ALIAS_LENGTH,
buildRedisDbNodeLabel,
getRedisDbAlias,
mergeRedisDbAliases,
sanitizeRedisDbAlias,
sanitizeRedisDbAliases,
setRedisDbAlias,
@@ -76,4 +77,20 @@ describe('redisDbAlias helpers', () => {
it('does not append key counts to the sidebar label', () => {
expect(buildRedisDbNodeLabel(0, '12')).toBe('db0 12');
});
it('merges imported aliases over local ones without dropping unrelated labels', () => {
const current = {
'conn-a': { '0': 'local-cache', '1': 'local-queue' },
'conn-b': { '0': 'sessions' },
};
const incoming = {
'conn-a': { '0': 'imported-cache' },
'conn-c': { '2': 'metrics' },
};
expect(mergeRedisDbAliases(current, incoming)).toEqual({
'conn-a': { '0': 'imported-cache', '1': 'local-queue' },
'conn-b': { '0': 'sessions' },
'conn-c': { '2': 'metrics' },
});
});
});

View File

@@ -126,6 +126,26 @@ export const setRedisDbAlias = (
return next;
};
/**
* Merge imported Redis DB aliases into the local map. Imported labels win for
* the same connection + DB index; unrelated local aliases are preserved.
*/
export const mergeRedisDbAliases = (
current: RedisDbAliasMap | undefined,
incoming: RedisDbAliasMap | undefined,
): RedisDbAliasMap => {
const base = sanitizeRedisDbAliases(current);
const imported = sanitizeRedisDbAliases(incoming);
const next: RedisDbAliasMap = { ...base };
Object.entries(imported).forEach(([connectionId, aliases]) => {
next[connectionId] = {
...(base[connectionId] || {}),
...aliases,
};
});
return next;
};
/**
* Build the sidebar label for a Redis DB node. Returns `dbN` when there is no
* alias, and `dbN alias` when one is set. Key counts are intentionally not