后台灰度预设补上游戏发布开关
- admin-web:灰度发布配置的固定目标新增「游戏分发 → 游戏发布」(game-distribution:publish),前缀标签与描述说明「未配置或关闭时默认开放,开启后只放行白名单/灰度命中」。 - 默认语义:选中预设后保持 enabled=false,避免误把发布收紧成全关;需要灰度时再显式打开并填白名单/比例。 - 用例:新增「可选择游戏发布开关且默认不收紧」与「保存写入白名单与比例」两条后台用例。 - 文档:开发运维文档说明该键配置前不会出现在已有列表、必须从预设或手填新建一行。
This commit is contained in:
@@ -175,6 +175,86 @@ test('灰度发布页可选择模板库并默认启用零比例灰度', async ()
|
||||
);
|
||||
});
|
||||
|
||||
test('灰度发布页可选择游戏发布开关,默认保持「未开启即开放」语义', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<AdminGrayReleaseConfigPage token="admin-token" onUnauthorized={vi.fn()} />,
|
||||
);
|
||||
|
||||
await screen.findByRole('button', { name: 'editor.new-toolbar' });
|
||||
await user.selectOptions(screen.getByLabelText('Gate Key 前缀'), [
|
||||
'game-distribution',
|
||||
]);
|
||||
|
||||
expect((screen.getByLabelText('Gate Key') as HTMLInputElement).value).toBe(
|
||||
'game-distribution:publish',
|
||||
);
|
||||
expect(
|
||||
(screen.getByLabelText('Gate Key 目标') as HTMLSelectElement).value,
|
||||
).toBe('publish');
|
||||
// 该开关的语义是「未配置/关闭 = 默认开放」,所以选中后不能默认打开收紧。
|
||||
expect((screen.getByLabelText('启用') as HTMLInputElement).checked).toBe(
|
||||
false,
|
||||
);
|
||||
expect((screen.getByLabelText('灰度比例') as HTMLInputElement).value).toBe(
|
||||
'0',
|
||||
);
|
||||
expect(
|
||||
(screen.getByLabelText('描述') as HTMLTextAreaElement).value,
|
||||
).toContain('游戏发布入口灰度');
|
||||
});
|
||||
|
||||
test('灰度发布页保存游戏发布开关时写入白名单与比例', async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(upsertAdminFeatureGateConfig).mockResolvedValueOnce({
|
||||
gates: [
|
||||
...configResponse.gates,
|
||||
{
|
||||
gateKey: 'game-distribution:publish',
|
||||
enabled: true,
|
||||
rolloutPercent: 20,
|
||||
allowUserIds: ['user-internal'],
|
||||
allowUserTags: [],
|
||||
denyUserIds: [],
|
||||
description: '游戏发布入口灰度',
|
||||
updatedAt: '2026-09-22T10:00:00Z',
|
||||
},
|
||||
],
|
||||
});
|
||||
render(
|
||||
<AdminGrayReleaseConfigPage token="admin-token" onUnauthorized={vi.fn()} />,
|
||||
);
|
||||
|
||||
await screen.findByRole('button', { name: 'editor.new-toolbar' });
|
||||
await user.selectOptions(screen.getByLabelText('Gate Key 前缀'), [
|
||||
'game-distribution',
|
||||
]);
|
||||
fireEvent.click(screen.getByLabelText('启用'));
|
||||
fireEvent.change(screen.getByLabelText('灰度比例'), {
|
||||
target: { value: '20' },
|
||||
});
|
||||
fireEvent.change(screen.getByLabelText('允许用户 ID'), {
|
||||
target: { value: 'user-internal' },
|
||||
});
|
||||
fireEvent.change(screen.getByLabelText('描述'), {
|
||||
target: { value: '游戏发布入口灰度' },
|
||||
});
|
||||
await user.click(screen.getByRole('button', { name: '保存配置' }));
|
||||
await user.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(upsertAdminFeatureGateConfig).toHaveBeenCalledWith('admin-token', {
|
||||
gateKey: 'game-distribution:publish',
|
||||
enabled: true,
|
||||
rolloutPercent: 20,
|
||||
allowUserIds: ['user-internal'],
|
||||
allowUserTags: [],
|
||||
denyUserIds: [],
|
||||
description: '游戏发布入口灰度',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('灰度发布页保存时转换数组和百分比', async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(upsertAdminFeatureGateConfig).mockResolvedValueOnce({
|
||||
|
||||
@@ -28,6 +28,7 @@ interface GateTargetOption {
|
||||
const GATE_PREFIX_LABELS: Record<string, string> = {
|
||||
'image-editor': '画布',
|
||||
agc: '客户端',
|
||||
'game-distribution': '游戏分发',
|
||||
};
|
||||
|
||||
const FIXED_GATE_TARGETS: GateTargetOption[] = [
|
||||
@@ -45,6 +46,14 @@ const FIXED_GATE_TARGETS: GateTargetOption[] = [
|
||||
label: 'Agent 侧边栏',
|
||||
description: '画布 Agent 入口灰度',
|
||||
},
|
||||
{
|
||||
prefix: 'game-distribution',
|
||||
suffix: 'publish',
|
||||
key: 'game-distribution:publish',
|
||||
label: '游戏发布',
|
||||
description:
|
||||
'游戏发布入口灰度:未配置或关闭时对已登录作者默认开放,开启后只放行白名单 / 灰度命中',
|
||||
},
|
||||
];
|
||||
|
||||
export function AdminGrayReleaseConfigPage({
|
||||
|
||||
@@ -678,7 +678,7 @@ journalctl -u genarrative-api -o cat | grep 'operation="release_rejected"'
|
||||
|
||||
发布事故或回滚窗口里用 `game-distribution:publish` 灰度开关控制写入,不需要改代码或重启:
|
||||
|
||||
- 开关位置:后台「灰度发布配置」(`GET/PUT /admin/api/feature-gates`),`gateKey = game-distribution:publish`。
|
||||
- 开关位置:后台「灰度发布配置」(`GET/PUT /admin/api/feature-gates`),`gateKey = game-distribution:publish`;后台预设「游戏分发 → 游戏发布」,选中后默认保持 `enabled=false`(即默认开放),需要收紧时再显式打开并填白名单 / 灰度比例。该键在配置前不会出现在已有开关列表里,必须从预设或手填 Gate Key 新建一行。
|
||||
- 语义:没有该 gate 行或 `enabled=false` 表示**默认开放**;`enabled=true` 时只有 `allowUserIds` / `allowUserTags` / `rolloutPercent` 命中的作者能发布,`rolloutPercent=0` 且无白名单即**全部关闭**(等价紧急关闭投稿)。
|
||||
- 关闭范围:创建游戏、创建版本、上传包、送审、撤回、作者下架,以及管理员**批准**(新版本激活)都返回 `503 GAME_DISTRIBUTION_PUBLISH_DISABLED`。
|
||||
- 始终可用:目录、详情、版本回读、发行网关(已公开游戏继续游玩)、`/my-games`、审核队列读取、**拒绝审核**与管理员**安全下架**。
|
||||
|
||||
Reference in New Issue
Block a user