refactor(command): 移除指令重命名时的别名功能
This commit is contained in:
@@ -38,7 +38,6 @@ class CommandDescriptor:
|
||||
is_group: bool = False
|
||||
is_sub_command: bool = False
|
||||
config: CommandConfig | None = None
|
||||
keep_original_alias: bool = False
|
||||
has_conflict: bool = False
|
||||
|
||||
|
||||
@@ -77,7 +76,7 @@ async def toggle_command(handler_full_name: str, enabled: bool) -> CommandDescri
|
||||
else descriptor.current_fragment
|
||||
),
|
||||
enabled=enabled,
|
||||
keep_original_alias=existing_cfg.keep_original_alias if existing_cfg else False,
|
||||
keep_original_alias=False,
|
||||
conflict_key=existing_cfg.conflict_key
|
||||
if existing_cfg and existing_cfg.conflict_key
|
||||
else descriptor.original_command,
|
||||
@@ -94,7 +93,6 @@ async def toggle_command(handler_full_name: str, enabled: bool) -> CommandDescri
|
||||
async def rename_command(
|
||||
handler_full_name: str,
|
||||
new_fragment: str,
|
||||
keep_original_alias: bool = False,
|
||||
) -> CommandDescriptor:
|
||||
descriptor = _build_descriptor_by_full_name(handler_full_name)
|
||||
if not descriptor:
|
||||
@@ -115,7 +113,7 @@ async def rename_command(
|
||||
original_command=descriptor.original_command or descriptor.handler_name,
|
||||
resolved_command=new_fragment,
|
||||
enabled=True if descriptor.enabled else False,
|
||||
keep_original_alias=keep_original_alias,
|
||||
keep_original_alias=False,
|
||||
conflict_key=descriptor.original_command,
|
||||
resolution_strategy="manual_rename",
|
||||
note=None,
|
||||
@@ -304,7 +302,6 @@ def _compose_command(parent_signature: str, fragment: str | None) -> str:
|
||||
|
||||
def _bind_descriptor_with_config(descriptor: CommandDescriptor, config: CommandConfig):
|
||||
descriptor.config = config
|
||||
descriptor.keep_original_alias = config.keep_original_alias
|
||||
descriptor.enabled = config.enabled
|
||||
descriptor.handler.enabled = config.enabled
|
||||
|
||||
@@ -319,20 +316,12 @@ def _bind_descriptor_with_config(descriptor: CommandDescriptor, config: CommandC
|
||||
)
|
||||
|
||||
if descriptor.filter_ref and new_fragment:
|
||||
_set_filter_fragment(
|
||||
descriptor.filter_ref,
|
||||
new_fragment,
|
||||
keep_original=config.keep_original_alias,
|
||||
original_fragment=descriptor.raw_command_name,
|
||||
)
|
||||
_set_filter_fragment(descriptor.filter_ref, new_fragment)
|
||||
|
||||
|
||||
def _set_filter_fragment(
|
||||
filter_ref: CommandFilter | CommandGroupFilter,
|
||||
fragment: str,
|
||||
*,
|
||||
keep_original: bool,
|
||||
original_fragment: str | None,
|
||||
) -> None:
|
||||
attr = (
|
||||
"group_name" if isinstance(filter_ref, CommandGroupFilter) else "command_name"
|
||||
@@ -340,9 +329,6 @@ def _set_filter_fragment(
|
||||
current_value = getattr(filter_ref, attr)
|
||||
if fragment == current_value:
|
||||
return
|
||||
if keep_original and original_fragment:
|
||||
alias_set = getattr(filter_ref, "alias", set())
|
||||
alias_set.add(original_fragment)
|
||||
setattr(filter_ref, attr, fragment)
|
||||
if hasattr(filter_ref, "_cmpl_cmd_names"):
|
||||
filter_ref._cmpl_cmd_names = None
|
||||
@@ -383,5 +369,4 @@ def _descriptor_to_dict(desc: CommandDescriptor) -> dict[str, Any]:
|
||||
"enabled": desc.enabled,
|
||||
"is_group": desc.is_group,
|
||||
"has_conflict": desc.has_conflict,
|
||||
"keep_original_alias": desc.keep_original_alias,
|
||||
}
|
||||
|
||||
@@ -62,13 +62,12 @@ class CommandRoute(Route):
|
||||
data = await request.get_json()
|
||||
handler_full_name = data.get("handler_full_name")
|
||||
new_name = data.get("new_name")
|
||||
keep_original = bool(data.get("keep_original_alias", False))
|
||||
|
||||
if not handler_full_name or not new_name:
|
||||
return Response().error("handler_full_name 与 new_name 均为必填。").__dict__
|
||||
|
||||
try:
|
||||
await rename_command_service(handler_full_name, new_name, keep_original)
|
||||
await rename_command_service(handler_full_name, new_name)
|
||||
except ValueError as exc:
|
||||
return Response().error(str(exc)).__dict__
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"rename": {
|
||||
"title": "Rename Command",
|
||||
"newName": "New command name",
|
||||
"keepAlias": "Keep original name as alias",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm"
|
||||
},
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"rename": {
|
||||
"title": "重命名指令",
|
||||
"newName": "新指令名",
|
||||
"keepAlias": "保留原名作为别名",
|
||||
"cancel": "取消",
|
||||
"confirm": "确认"
|
||||
},
|
||||
|
||||
+126
-137
@@ -20,7 +20,6 @@ interface CommandItem {
|
||||
enabled: boolean;
|
||||
is_group: boolean;
|
||||
has_conflict: boolean;
|
||||
keep_original_alias: boolean;
|
||||
}
|
||||
|
||||
interface CommandSummary {
|
||||
@@ -56,7 +55,6 @@ const renameDialog = reactive({
|
||||
show: false,
|
||||
command: null as CommandItem | null,
|
||||
newName: '',
|
||||
keepAlias: false,
|
||||
loading: false
|
||||
});
|
||||
|
||||
@@ -166,7 +164,6 @@ const toggleCommand = async (cmd: CommandItem) => {
|
||||
const openRenameDialog = (cmd: CommandItem) => {
|
||||
renameDialog.command = cmd;
|
||||
renameDialog.newName = cmd.current_fragment || '';
|
||||
renameDialog.keepAlias = cmd.keep_original_alias;
|
||||
renameDialog.show = true;
|
||||
};
|
||||
|
||||
@@ -178,8 +175,7 @@ const confirmRename = async () => {
|
||||
try {
|
||||
const res = await axios.post('/api/commands/rename', {
|
||||
handler_full_name: renameDialog.command.handler_full_name,
|
||||
new_name: renameDialog.newName.trim(),
|
||||
keep_original_alias: renameDialog.keepAlias
|
||||
new_name: renameDialog.newName.trim()
|
||||
});
|
||||
if (res.data.status === 'ok') {
|
||||
toast(tm('messages.renameSuccess'), 'success');
|
||||
@@ -284,148 +280,148 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<v-row class="mb-3">
|
||||
<v-col cols="12" sm="4" md="3">
|
||||
<v-select
|
||||
v-model="pluginFilter"
|
||||
:items="[{ title: tm('filters.all'), value: 'all' }, ...availablePlugins.map(p => ({ title: p, value: p }))]"
|
||||
:label="tm('filters.byPlugin')"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="4" md="3">
|
||||
<v-select
|
||||
v-model="permissionFilter"
|
||||
:items="[
|
||||
{ title: tm('filters.all'), value: 'all' },
|
||||
{ title: tm('permission.everyone'), value: 'everyone' },
|
||||
{ title: tm('permission.admin'), value: 'admin' },
|
||||
{ title: tm('permission.member'), value: 'member' }
|
||||
]"
|
||||
:label="tm('filters.byPermission')"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="4" md="3">
|
||||
<v-select
|
||||
v-model="statusFilter"
|
||||
:items="[
|
||||
{ title: tm('filters.all'), value: 'all' },
|
||||
{ title: tm('filters.enabled'), value: 'enabled' },
|
||||
<!-- Filters -->
|
||||
<v-row class="mb-3">
|
||||
<v-col cols="12" sm="4" md="3">
|
||||
<v-select
|
||||
v-model="pluginFilter"
|
||||
:items="[{ title: tm('filters.all'), value: 'all' }, ...availablePlugins.map(p => ({ title: p, value: p }))]"
|
||||
:label="tm('filters.byPlugin')"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="4" md="3">
|
||||
<v-select
|
||||
v-model="permissionFilter"
|
||||
:items="[
|
||||
{ title: tm('filters.all'), value: 'all' },
|
||||
{ title: tm('permission.everyone'), value: 'everyone' },
|
||||
{ title: tm('permission.admin'), value: 'admin' },
|
||||
{ title: tm('permission.member'), value: 'member' }
|
||||
]"
|
||||
:label="tm('filters.byPermission')"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="4" md="3">
|
||||
<v-select
|
||||
v-model="statusFilter"
|
||||
:items="[
|
||||
{ title: tm('filters.all'), value: 'all' },
|
||||
{ title: tm('filters.enabled'), value: 'enabled' },
|
||||
{ title: tm('filters.disabled'), value: 'disabled' },
|
||||
{ title: tm('filters.conflict'), value: 'conflict' }
|
||||
]"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
]"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- Commands Table -->
|
||||
<v-card class="rounded-lg overflow-hidden elevation-1">
|
||||
<v-data-table
|
||||
:headers="commandHeaders"
|
||||
:items="filteredCommands"
|
||||
:loading="loading"
|
||||
item-key="handler_full_name"
|
||||
hover
|
||||
>
|
||||
<template v-slot:loader>
|
||||
<v-row class="py-8 d-flex align-center justify-center">
|
||||
<v-progress-circular indeterminate color="primary" />
|
||||
<span class="ml-2">{{ t('core.status.loading') }}</span>
|
||||
</v-row>
|
||||
</template>
|
||||
<!-- Commands Table -->
|
||||
<v-card class="rounded-lg overflow-hidden elevation-1">
|
||||
<v-data-table
|
||||
:headers="commandHeaders"
|
||||
:items="filteredCommands"
|
||||
:loading="loading"
|
||||
item-key="handler_full_name"
|
||||
hover
|
||||
>
|
||||
<template v-slot:loader>
|
||||
<v-row class="py-8 d-flex align-center justify-center">
|
||||
<v-progress-circular indeterminate color="primary" />
|
||||
<span class="ml-2">{{ t('core.status.loading') }}</span>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.effective_command="{ item }">
|
||||
<div class="d-flex align-center py-2">
|
||||
<div>
|
||||
<div class="text-subtitle-1 font-weight-medium">
|
||||
<code>{{ item.effective_command }}</code>
|
||||
</div>
|
||||
<template v-slot:item.effective_command="{ item }">
|
||||
<div class="d-flex align-center py-2">
|
||||
<div>
|
||||
<div class="text-subtitle-1 font-weight-medium">
|
||||
<code>{{ item.effective_command }}</code>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.plugin="{ item }">
|
||||
<div class="text-body-2">{{ item.plugin_display_name || item.plugin }}</div>
|
||||
</template>
|
||||
<template v-slot:item.plugin="{ item }">
|
||||
<div class="text-body-2">{{ item.plugin_display_name || item.plugin }}</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.description="{ item }">
|
||||
<div class="text-body-2 text-medium-emphasis" style="max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
{{ item.description || '-' }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:item.description="{ item }">
|
||||
<div class="text-body-2 text-medium-emphasis" style="max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
{{ item.description || '-' }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.permission="{ item }">
|
||||
<v-chip :color="getPermissionColor(item.permission)" size="small" class="font-weight-medium">
|
||||
{{ getPermissionLabel(item.permission) }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<template v-slot:item.permission="{ item }">
|
||||
<v-chip :color="getPermissionColor(item.permission)" size="small" class="font-weight-medium">
|
||||
{{ getPermissionLabel(item.permission) }}
|
||||
</v-chip>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.enabled="{ item }">
|
||||
<v-chip
|
||||
<template v-slot:item.enabled="{ item }">
|
||||
<v-chip
|
||||
:color="getStatusInfo(item).color"
|
||||
size="small"
|
||||
class="font-weight-medium"
|
||||
size="small"
|
||||
class="font-weight-medium"
|
||||
:variant="getStatusInfo(item).variant"
|
||||
>
|
||||
>
|
||||
{{ getStatusInfo(item).text }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-chip>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<div class="d-flex align-center">
|
||||
<v-btn-group density="comfortable" variant="text" color="primary">
|
||||
<v-btn
|
||||
v-if="!item.enabled"
|
||||
icon
|
||||
size="small"
|
||||
color="success"
|
||||
@click="toggleCommand(item)"
|
||||
>
|
||||
<v-icon>mdi-play</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.enable') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-else
|
||||
icon
|
||||
size="small"
|
||||
color="error"
|
||||
@click="toggleCommand(item)"
|
||||
>
|
||||
<v-icon>mdi-pause</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.disable') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<div class="d-flex align-center">
|
||||
<v-btn-group density="comfortable" variant="text" color="primary">
|
||||
<v-btn
|
||||
v-if="!item.enabled"
|
||||
icon
|
||||
size="small"
|
||||
color="success"
|
||||
@click="toggleCommand(item)"
|
||||
>
|
||||
<v-icon>mdi-play</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.enable') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-else
|
||||
icon
|
||||
size="small"
|
||||
color="error"
|
||||
@click="toggleCommand(item)"
|
||||
>
|
||||
<v-icon>mdi-pause</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.disable') }}</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon size="small" color="warning" @click="openRenameDialog(item)">
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.rename') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="warning" @click="openRenameDialog(item)">
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.rename') }}</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon size="small" @click="openDetailsDialog(item)">
|
||||
<v-icon>mdi-information</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.viewDetails') }}</v-tooltip>
|
||||
</v-btn>
|
||||
</v-btn-group>
|
||||
</div>
|
||||
</template>
|
||||
<v-btn icon size="small" @click="openDetailsDialog(item)">
|
||||
<v-icon>mdi-information</v-icon>
|
||||
<v-tooltip activator="parent" location="top">{{ tm('tooltips.viewDetails') }}</v-tooltip>
|
||||
</v-btn>
|
||||
</v-btn-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:no-data>
|
||||
<div class="text-center pa-8">
|
||||
<v-icon size="64" color="info" class="mb-4">mdi-console-line</v-icon>
|
||||
<div class="text-h5 mb-2">{{ tm('empty.noCommands') }}</div>
|
||||
<div class="text-body-1 mb-4">{{ tm('empty.noCommandsDesc') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-card>
|
||||
<template v-slot:no-data>
|
||||
<div class="text-center pa-8">
|
||||
<v-icon size="64" color="info" class="mb-4">mdi-console-line</v-icon>
|
||||
<div class="text-h5 mb-2">{{ tm('empty.noCommands') }}</div>
|
||||
<div class="text-body-1 mb-4">{{ tm('empty.noCommandsDesc') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-card>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
@@ -441,15 +437,8 @@ onMounted(async () => {
|
||||
:label="tm('dialogs.rename.newName')"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
class="mb-4"
|
||||
autofocus
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="renameDialog.keepAlias"
|
||||
:label="tm('dialogs.rename.keepAlias')"
|
||||
density="compact"
|
||||
hide-details
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
|
||||
Reference in New Issue
Block a user