feat(versioning-ui): 优化版本不一致提示与回溯限制
This commit is contained in:
parent
6379f8c729
commit
55feb36091
@ -396,6 +396,7 @@
|
|||||||
:detail-loading="versioningDetailLoading"
|
:detail-loading="versioningDetailLoading"
|
||||||
:restoring="versioningRestoring"
|
:restoring="versioningRestoring"
|
||||||
:restore-mode="versioningRestoreMode"
|
:restore-mode="versioningRestoreMode"
|
||||||
|
:workspace-matched="versioningWorkspaceMatched"
|
||||||
@close="versioningDialogOpen = false"
|
@close="versioningDialogOpen = false"
|
||||||
@refresh="refreshVersioningDialog"
|
@refresh="refreshVersioningDialog"
|
||||||
@toggle-enabled="toggleConversationVersioning"
|
@toggle-enabled="toggleConversationVersioning"
|
||||||
|
|||||||
@ -21,6 +21,7 @@ export const versioningMethods = {
|
|||||||
this.versioningMode = 'overwrite';
|
this.versioningMode = 'overwrite';
|
||||||
this.versioningRestoreMode = 'overwrite';
|
this.versioningRestoreMode = 'overwrite';
|
||||||
this.versioningMismatch = !!payload.mismatch;
|
this.versioningMismatch = !!payload.mismatch;
|
||||||
|
this.versioningWorkspaceMatched = payload.workspace_matched !== false;
|
||||||
return payload;
|
return payload;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
@ -66,6 +67,7 @@ export const versioningMethods = {
|
|||||||
async openVersioningDialog() {
|
async openVersioningDialog() {
|
||||||
if (!this.currentConversationId) {
|
if (!this.currentConversationId) {
|
||||||
this.versioningEnabled = !!this.newConversationVersioningEnabled;
|
this.versioningEnabled = !!this.newConversationVersioningEnabled;
|
||||||
|
this.versioningWorkspaceMatched = true;
|
||||||
this.versioningCheckpoints = [];
|
this.versioningCheckpoints = [];
|
||||||
this.versioningSelectedSeq = null;
|
this.versioningSelectedSeq = null;
|
||||||
this.versioningSelectedDetail = null;
|
this.versioningSelectedDetail = null;
|
||||||
@ -224,7 +226,11 @@ export const versioningMethods = {
|
|||||||
title: '版本状态不一致',
|
title: '版本状态不一致',
|
||||||
message: '当前工作区与该对话最新版本不一致,是否恢复到最新一次提交?',
|
message: '当前工作区与该对话最新版本不一致,是否恢复到最新一次提交?',
|
||||||
confirmText: '恢复',
|
confirmText: '恢复',
|
||||||
cancelText: '保持当前'
|
cancelText: '保持当前',
|
||||||
|
warningText: '警告:恢复操作会导致当前工作区内容被重置为当前对话的最新一次提交备份。',
|
||||||
|
closeOnBackdrop: false,
|
||||||
|
confirmVariant: 'danger',
|
||||||
|
confirmOnLeft: true
|
||||||
});
|
});
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -86,6 +86,7 @@ export function dataState() {
|
|||||||
newConversationVersioningEnabled: false,
|
newConversationVersioningEnabled: false,
|
||||||
versioningMode: 'overwrite',
|
versioningMode: 'overwrite',
|
||||||
versioningMismatch: false,
|
versioningMismatch: false,
|
||||||
|
versioningWorkspaceMatched: true,
|
||||||
versioningDialogOpen: false,
|
versioningDialogOpen: false,
|
||||||
versioningLoading: false,
|
versioningLoading: false,
|
||||||
versioningCheckpoints: [],
|
versioningCheckpoints: [],
|
||||||
|
|||||||
@ -84,11 +84,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="versioning-footer">
|
<footer class="versioning-footer">
|
||||||
|
<div v-if="workspaceMatched === false" class="workspace-mismatch-tip">
|
||||||
|
当前对话所属工作区与当前工作区不一致,无法执行回溯。
|
||||||
|
</div>
|
||||||
<label>回溯模式:覆盖当前对话</label>
|
<label>回溯模式:覆盖当前对话</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="confirm-btn"
|
class="confirm-btn"
|
||||||
:disabled="!enabled || selectedSeq === null || selectedSeq === undefined || restoring"
|
:disabled="!enabled || selectedSeq === null || selectedSeq === undefined || restoring || workspaceMatched === false"
|
||||||
@click="$emit('confirm')"
|
@click="$emit('confirm')"
|
||||||
>
|
>
|
||||||
{{ restoring ? '回溯中...' : '确认回溯' }}
|
{{ restoring ? '回溯中...' : '确认回溯' }}
|
||||||
@ -111,6 +114,7 @@ const props = defineProps<{
|
|||||||
detailLoading: boolean;
|
detailLoading: boolean;
|
||||||
restoring: boolean;
|
restoring: boolean;
|
||||||
restoreMode: string;
|
restoreMode: string;
|
||||||
|
workspaceMatched?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineEmits([
|
defineEmits([
|
||||||
@ -187,6 +191,7 @@ const formatTime = (value: string) => {
|
|||||||
.delta { display: inline-flex; gap: 8px; }
|
.delta { display: inline-flex; gap: 8px; }
|
||||||
.loading, .empty { color: var(--claude-text-secondary); font-size: 13px; padding: 12px 4px; }
|
.loading, .empty { color: var(--claude-text-secondary); font-size: 13px; padding: 12px 4px; }
|
||||||
.versioning-footer { padding: 12px 18px; display: flex; align-items: center; gap: 10px; justify-content: flex-end; }
|
.versioning-footer { padding: 12px 18px; display: flex; align-items: center; gap: 10px; justify-content: flex-end; }
|
||||||
|
.workspace-mismatch-tip { margin-right: auto; color: #dc2626; font-size: 13px; font-weight: 600; }
|
||||||
.versioning-footer select { border: 1px solid var(--theme-control-border); border-radius: 8px; padding: 6px 10px; background: var(--theme-surface-soft); color: var(--claude-text); }
|
.versioning-footer select { border: 1px solid var(--theme-control-border); border-radius: 8px; padding: 6px 10px; background: var(--theme-surface-soft); color: var(--claude-text); }
|
||||||
.confirm-btn { border: 0; background: var(--claude-accent); color: #fff; border-radius: 8px; padding: 8px 14px; cursor: pointer; }
|
.confirm-btn { border: 0; background: var(--claude-accent); color: #fff; border-radius: 8px; padding: 8px 14px; cursor: pointer; }
|
||||||
.confirm-btn:disabled { opacity: .5; cursor: not-allowed; }
|
.confirm-btn:disabled { opacity: .5; cursor: not-allowed; }
|
||||||
|
|||||||
@ -1,16 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="confirm-dialog-fade">
|
<transition name="confirm-dialog-fade">
|
||||||
<div class="confirm-overlay" v-if="dialog?.visible" @click.self="resolve(false)">
|
<div
|
||||||
|
class="confirm-overlay"
|
||||||
|
v-if="dialog?.visible"
|
||||||
|
@click.self="dialog?.closeOnBackdrop !== false && resolve(false)"
|
||||||
|
>
|
||||||
<div class="confirm-modal">
|
<div class="confirm-modal">
|
||||||
<div class="confirm-title">{{ dialog.title || '确认操作' }}</div>
|
<div class="confirm-title">{{ dialog.title || '确认操作' }}</div>
|
||||||
<div class="confirm-message">{{ dialog.message }}</div>
|
<div class="confirm-message">{{ dialog.message }}</div>
|
||||||
<div class="confirm-actions">
|
<div v-if="dialog.warningText" class="confirm-warning">{{ dialog.warningText }}</div>
|
||||||
<button type="button" class="confirm-button" @click="resolve(false)">
|
<div
|
||||||
|
class="confirm-actions"
|
||||||
|
:class="{ 'confirm-actions--confirm-left': dialog.confirmOnLeft }"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="confirm-button confirm-button--cancel"
|
||||||
|
@click="resolve(false)"
|
||||||
|
>
|
||||||
{{ dialog.cancelText || '取消' }}
|
{{ dialog.cancelText || '取消' }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="confirm-button confirm-button--primary"
|
class="confirm-button confirm-button--confirm"
|
||||||
|
:class="
|
||||||
|
dialog.confirmVariant === 'danger'
|
||||||
|
? 'confirm-button--danger'
|
||||||
|
: 'confirm-button--primary'
|
||||||
|
"
|
||||||
@click="resolve(true)"
|
@click="resolve(true)"
|
||||||
>
|
>
|
||||||
{{ dialog.confirmText || '确认' }}
|
{{ dialog.confirmText || '确认' }}
|
||||||
|
|||||||
@ -31,6 +31,10 @@ interface ConfirmDialogOptions {
|
|||||||
message?: string;
|
message?: string;
|
||||||
confirmText?: string;
|
confirmText?: string;
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
|
warningText?: string;
|
||||||
|
closeOnBackdrop?: boolean;
|
||||||
|
confirmVariant?: 'primary' | 'danger';
|
||||||
|
confirmOnLeft?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfirmDialogState extends ConfirmDialogOptions {
|
interface ConfirmDialogState extends ConfirmDialogOptions {
|
||||||
@ -258,7 +262,11 @@ export const useUiStore = defineStore('ui', {
|
|||||||
title: options.title || '确认操作',
|
title: options.title || '确认操作',
|
||||||
message: options.message || '请确认本次操作',
|
message: options.message || '请确认本次操作',
|
||||||
confirmText: options.confirmText || '确认',
|
confirmText: options.confirmText || '确认',
|
||||||
cancelText: options.cancelText || '取消'
|
cancelText: options.cancelText || '取消',
|
||||||
|
warningText: options.warningText || '',
|
||||||
|
closeOnBackdrop: options.closeOnBackdrop !== false,
|
||||||
|
confirmVariant: options.confirmVariant === 'danger' ? 'danger' : 'primary',
|
||||||
|
confirmOnLeft: options.confirmOnLeft === true
|
||||||
};
|
};
|
||||||
this.pendingConfirmResolver = resolve;
|
this.pendingConfirmResolver = resolve;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1898,6 +1898,14 @@
|
|||||||
color: var(--claude-text-secondary);
|
color: var(--claude-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirm-warning {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #ef4444;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
.confirm-actions {
|
.confirm-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -1905,6 +1913,14 @@
|
|||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirm-actions--confirm-left .confirm-button--confirm {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-actions--confirm-left .confirm-button--cancel {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.confirm-button {
|
.confirm-button {
|
||||||
border: 1px solid var(--theme-control-border-strong);
|
border: 1px solid var(--theme-control-border-strong);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -1921,6 +1937,12 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirm-button--danger {
|
||||||
|
background: #dc2626;
|
||||||
|
border-color: #b91c1c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.subagent-activity-overlay {
|
.subagent-activity-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user