Phase 007: migrate every remaining view from naive-ui to Arco Design Vue
The project now has exactly one UI library. Every naive-ui component in
packages/client/src is replaced by its Arco equivalent across 24 views and
roughly 80 components, and naive-ui is dropped from package.json along with
its transitive vueuc / @css-render / vdirs / seemly dependencies.
The migration is rendering-layer only. No store logic, no API contract, and
no /chat-run payload was touched.
Three classes of leftover were invisible to `grep naive-ui` and are now
covered by tests/client/no-naive-ui.test.ts, which asserts all three:
- dead .n-* class names in style blocks
- dead --n-* custom properties
- naive-ui in package.json
Notable behavioural traps handled along the way, recorded in
docs/arco-migration-rules.md:
- a-input-password defaults to masked; passing default-visibility="false"
would have exposed API keys in clear text
- a-upload fires a real XHR unless auto-upload is false
- nested Trigger components fight over the first element child, so the
group-chat settings dropdown was flattened
- Arco renders tooltip default-slot text inline, which was silently
collapsing the chat and group-chat toolbars
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { NButton, NCheckbox, NCheckboxGroup, NModal, NInput, NSelect } from 'naive-ui'
|
||||
import { useMessage } from '@/composables/useMessage'
|
||||
import { useDialog } from '@/composables/useDialog'
|
||||
import type { AvailableModelGroup } from '@/api/hermes/system'
|
||||
@@ -260,16 +259,16 @@ async function handleDelete() {
|
||||
</div>
|
||||
<div class="default-model-row">
|
||||
<span class="info-label">{{ t('models.defaultModel') }}</span>
|
||||
<NSelect
|
||||
<a-select
|
||||
class="default-model-select"
|
||||
size="tiny"
|
||||
filterable
|
||||
:value="defaultModelSelectValue"
|
||||
size="mini"
|
||||
allow-search
|
||||
:model-value="defaultModelSelectValue ?? undefined"
|
||||
:options="defaultModelOptions"
|
||||
:placeholder="t('models.selectModel')"
|
||||
:disabled="provider.models.length === 0"
|
||||
:loading="defaultingModel !== null"
|
||||
@update:value="handleSetDefaultModel"
|
||||
@change="handleSetDefaultModel($event as string | null)"
|
||||
/>
|
||||
</div>
|
||||
<div class="models-list">
|
||||
@@ -293,25 +292,25 @@ async function handleDelete() {
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<NButton
|
||||
size="tiny"
|
||||
quaternary
|
||||
<a-button
|
||||
size="mini"
|
||||
type="text"
|
||||
:disabled="isDefaultProvider"
|
||||
:loading="defaultingProvider"
|
||||
@click="handleSetDefaultProvider"
|
||||
>
|
||||
{{ isDefaultProvider ? t('models.currentDefault') : t('models.setDefaultProvider') }}
|
||||
</NButton>
|
||||
<NButton size="tiny" quaternary @click="showAliasListModal = true">{{ t('models.aliasManage') }}</NButton>
|
||||
<NButton size="tiny" quaternary @click="openVisibilityModal">{{ t('models.manageVisibleModels') }}</NButton>
|
||||
<NButton size="tiny" quaternary type="error" :loading="deleting" @click="handleDelete">{{ destructiveActionLabel }}</NButton>
|
||||
</a-button>
|
||||
<a-button size="mini" type="text" @click="showAliasListModal = true">{{ t('models.aliasManage') }}</a-button>
|
||||
<a-button size="mini" type="text" @click="openVisibilityModal">{{ t('models.manageVisibleModels') }}</a-button>
|
||||
<a-button size="mini" type="text" status="danger" :loading="deleting" @click="handleDelete">{{ destructiveActionLabel }}</a-button>
|
||||
</div>
|
||||
|
||||
<NModal
|
||||
v-model:show="showAliasListModal"
|
||||
preset="card"
|
||||
<a-modal
|
||||
v-model:visible="showAliasListModal"
|
||||
:footer="false"
|
||||
:title="t('models.aliasManageFor', { provider: displayName })"
|
||||
:style="{ width: 'min(560px, calc(100vw - 32px))' }"
|
||||
width="min(560px, calc(100vw - 32px))"
|
||||
:mask-closable="true"
|
||||
>
|
||||
<div class="alias-list-hint">{{ t('models.aliasHint') }}</div>
|
||||
@@ -322,22 +321,21 @@ async function handleDelete() {
|
||||
<span v-if="isDefaultModel(model)" class="alias-row-default">{{ t('models.defaultShort') }}</span>
|
||||
<code class="alias-row-id">{{ model }}</code>
|
||||
</div>
|
||||
<NButton size="tiny" quaternary @click="openAliasEditor(model)">{{ t('models.aliasEdit') }}</NButton>
|
||||
<a-button size="mini" type="text" @click="openAliasEditor(model)">{{ t('models.aliasEdit') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</NModal>
|
||||
</a-modal>
|
||||
|
||||
<NModal
|
||||
v-model:show="showAliasModal"
|
||||
preset="card"
|
||||
<a-modal
|
||||
v-model:visible="showAliasModal"
|
||||
:title="aliasModel ? t('models.aliasTitleFor', { model: aliasModel }) : t('models.aliasTitle')"
|
||||
:style="{ width: 'min(420px, calc(100vw - 32px))' }"
|
||||
width="min(420px, calc(100vw - 32px))"
|
||||
:mask-closable="true"
|
||||
>
|
||||
<NInput
|
||||
v-model:value="aliasInput"
|
||||
<a-input
|
||||
v-model="aliasInput"
|
||||
:placeholder="t('models.aliasPlaceholder')"
|
||||
clearable
|
||||
allow-clear
|
||||
@keydown.enter="saveAlias"
|
||||
/>
|
||||
<div v-if="aliasModel" class="model-alias-canonical">
|
||||
@@ -346,21 +344,21 @@ async function handleDelete() {
|
||||
<div class="model-alias-hint">{{ t('models.aliasHint') }}</div>
|
||||
<template #footer>
|
||||
<div class="model-alias-actions">
|
||||
<NButton quaternary :disabled="!appStore.getModelAlias(aliasModel, aliasProvider)" @click="clearAlias">
|
||||
<a-button type="text" :disabled="!appStore.getModelAlias(aliasModel, aliasProvider)" @click="clearAlias">
|
||||
{{ t('models.aliasUseOriginal') }}
|
||||
</NButton>
|
||||
</a-button>
|
||||
<div class="model-alias-spacer" />
|
||||
<NButton @click="showAliasModal = false">{{ t('common.cancel') }}</NButton>
|
||||
<NButton type="primary" @click="saveAlias">{{ t('common.save') }}</NButton>
|
||||
<a-button @click="showAliasModal = false">{{ t('common.cancel') }}</a-button>
|
||||
<a-button type="primary" @click="saveAlias">{{ t('common.save') }}</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
</a-modal>
|
||||
|
||||
<NModal
|
||||
v-model:show="showVisibilityModal"
|
||||
preset="card"
|
||||
<a-modal
|
||||
v-model:visible="showVisibilityModal"
|
||||
:footer="false"
|
||||
:title="t('models.manageVisibleModelsFor', { name: displayName })"
|
||||
:style="{ width: 'min(560px, calc(100vw - 32px))' }"
|
||||
width="min(560px, calc(100vw - 32px))"
|
||||
:mask-closable="!visibilitySaving"
|
||||
>
|
||||
<p class="visibility-hint">{{ t('models.visibilityHint') }}</p>
|
||||
@@ -368,8 +366,8 @@ async function handleDelete() {
|
||||
{{ selectedVisibleModels.length }}/{{ allModels.length }} {{ t('models.count') }}
|
||||
</div>
|
||||
<div class="visibility-list">
|
||||
<NCheckboxGroup v-model:value="selectedVisibleModels">
|
||||
<NCheckbox
|
||||
<a-checkbox-group v-model="selectedVisibleModels">
|
||||
<a-checkbox
|
||||
v-for="model in allModels"
|
||||
:key="model"
|
||||
:value="model"
|
||||
@@ -377,25 +375,25 @@ async function handleDelete() {
|
||||
>
|
||||
<code>{{ modelDisplayName(model) }}</code>
|
||||
<code v-if="modelAlias(model)" class="visibility-model-id">{{ model }}</code>
|
||||
</NCheckbox>
|
||||
</NCheckboxGroup>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="visibility-actions">
|
||||
<NButton size="small" quaternary :disabled="visibilitySaving" @click="resetVisibility">
|
||||
<a-button size="small" type="text" :disabled="visibilitySaving" @click="resetVisibility">
|
||||
{{ t('models.showAllModels') }}
|
||||
</NButton>
|
||||
<NButton size="small" quaternary :disabled="visibilitySaving" @click="clearVisibility">
|
||||
</a-button>
|
||||
<a-button size="small" type="text" :disabled="visibilitySaving" @click="clearVisibility">
|
||||
{{ t('models.clearVisibleModels') }}
|
||||
</NButton>
|
||||
</a-button>
|
||||
<div class="visibility-action-spacer" />
|
||||
<NButton size="small" :disabled="visibilitySaving" @click="showVisibilityModal = false">
|
||||
<a-button size="small" :disabled="visibilitySaving" @click="showVisibilityModal = false">
|
||||
{{ t('common.cancel') }}
|
||||
</NButton>
|
||||
<NButton size="small" type="primary" :loading="visibilitySaving" @click="handleVisibilitySave">
|
||||
</a-button>
|
||||
<a-button size="small" type="primary" :loading="visibilitySaving" @click="handleVisibilitySave">
|
||||
{{ t('common.save') }}
|
||||
</NButton>
|
||||
</a-button>
|
||||
</div>
|
||||
</NModal>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user