You've already forked agentic-coding-workflow
前端优化
This commit is contained in:
@@ -34,11 +34,13 @@ export async function request<T>(path: string, opts: RequestOptions = {}): Promi
|
||||
|
||||
const controller = new AbortController()
|
||||
const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS)
|
||||
let onAbort: (() => void) | undefined
|
||||
if (opts.signal) {
|
||||
if (opts.signal.aborted) {
|
||||
controller.abort()
|
||||
} else {
|
||||
opts.signal.addEventListener('abort', () => controller.abort(), { once: true })
|
||||
onAbort = () => controller.abort()
|
||||
opts.signal.addEventListener('abort', onAbort, { once: true })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +80,9 @@ export async function request<T>(path: string, opts: RequestOptions = {}): Promi
|
||||
return data as T
|
||||
} finally {
|
||||
clearTimeout(timer)
|
||||
if (opts.signal && onAbort) {
|
||||
opts.signal.removeEventListener('abort', onAbort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,11 +57,12 @@ const allowlistText = computed({
|
||||
})
|
||||
|
||||
interface EnvRow {
|
||||
id: string
|
||||
k: string
|
||||
v: string
|
||||
}
|
||||
const envEntries = ref<EnvRow[]>(
|
||||
Object.entries(local.value.env).map(([k, v]) => ({ k, v })),
|
||||
Object.entries(local.value.env).map(([k, v]) => ({ id: crypto.randomUUID(), k, v })),
|
||||
)
|
||||
|
||||
watch(
|
||||
@@ -77,7 +78,7 @@ watch(
|
||||
)
|
||||
|
||||
function addEnv() {
|
||||
envEntries.value.push({ k: '', v: '' })
|
||||
envEntries.value.push({ id: crypto.randomUUID(), k: '', v: '' })
|
||||
}
|
||||
function removeEnv(idx: number) {
|
||||
envEntries.value.splice(idx, 1)
|
||||
@@ -94,6 +95,7 @@ const mcpTypeOptions = [
|
||||
]
|
||||
|
||||
interface McpRow {
|
||||
id: string
|
||||
name: string
|
||||
type: 'stdio' | 'http' | 'sse'
|
||||
command: string
|
||||
@@ -123,6 +125,7 @@ function parseKV(s: string): Record<string, string> | undefined {
|
||||
|
||||
function specsToRows(specs: McpServerSpec[]): McpRow[] {
|
||||
return specs.map((s) => ({
|
||||
id: crypto.randomUUID(),
|
||||
name: s.name,
|
||||
type: s.type,
|
||||
command: s.command ?? '',
|
||||
@@ -173,6 +176,7 @@ watch(
|
||||
|
||||
function addMcpServer() {
|
||||
mcpRows.value.push({
|
||||
id: crypto.randomUUID(),
|
||||
name: '',
|
||||
type: 'http',
|
||||
command: '',
|
||||
@@ -258,7 +262,7 @@ function removeMcpServer(idx: number) {
|
||||
</p>
|
||||
<div
|
||||
v-for="(e, idx) in envEntries"
|
||||
:key="idx"
|
||||
:key="e.id"
|
||||
class="flex gap-2 mb-2"
|
||||
>
|
||||
<NInput
|
||||
@@ -305,7 +309,7 @@ function removeMcpServer(idx: number) {
|
||||
</label>
|
||||
<div
|
||||
v-for="(m, idx) in mcpRows"
|
||||
:key="idx"
|
||||
:key="m.id"
|
||||
class="border rounded p-3 mb-2 space-y-2"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
export const md = new MarkdownIt({ html: false, breaks: true, linkify: true })
|
||||
@@ -94,6 +94,7 @@
|
||||
<MessageBubble
|
||||
v-for="m in chat.messages"
|
||||
:key="m.id"
|
||||
v-memo="[m.id, m.content, m.status]"
|
||||
:message="m"
|
||||
@retry="onRetry"
|
||||
/>
|
||||
|
||||
@@ -93,13 +93,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { NCollapse, NCollapseItem, NButton } from 'naive-ui'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
import type { ChatMessage } from '@/api/chat'
|
||||
import { md } from '@/utils/markdown'
|
||||
import { parseInteractiveMessage, type InteractiveQuestionAnswer } from '@/utils/interactiveMessage'
|
||||
import QuestionCard from './QuestionCard.vue'
|
||||
|
||||
const md = new MarkdownIt({ html: false, breaks: true, linkify: true })
|
||||
// savable:仅需求阶段对话面板传 true,对成功的 assistant 回复显示「保存为产物」。
|
||||
const props = defineProps<{ message: ChatMessage; savable?: boolean; answerDisabled?: boolean }>()
|
||||
const emit = defineEmits<{
|
||||
|
||||
@@ -112,9 +112,8 @@ import {
|
||||
NTag,
|
||||
NThing,
|
||||
} from 'naive-ui'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
import type { Artifact, ArtifactPhase } from '@/api/projects'
|
||||
import { md } from '@/utils/markdown'
|
||||
import { useRequirementsStore } from '@/stores/requirements'
|
||||
|
||||
const PHASE_TITLE: Record<ArtifactPhase, string> = {
|
||||
@@ -131,7 +130,6 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const store = useRequirementsStore()
|
||||
const md = new MarkdownIt({ html: false, breaks: true, linkify: true })
|
||||
|
||||
const artifacts = ref<Artifact[]>([])
|
||||
const selectedVersion = ref<number | null>(null)
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
<MessageBubble
|
||||
v-for="m in session.messages.value"
|
||||
:key="m.id"
|
||||
v-memo="[m.id, m.content, m.status]"
|
||||
:message="m"
|
||||
:savable="!readonly"
|
||||
:answer-disabled="readonly || session.isStreaming.value"
|
||||
|
||||
@@ -201,11 +201,11 @@ import {
|
||||
NTag,
|
||||
NThing,
|
||||
} from 'naive-ui'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
import { chatApi, type Conversation } from '@/api/chat'
|
||||
import { acpApi, type AcpSession } from '@/api/acp'
|
||||
import type { Artifact, ArtifactPhase, Phase } from '@/api/projects'
|
||||
import { md } from '@/utils/markdown'
|
||||
import { useRequirementsStore } from '@/stores/requirements'
|
||||
import SessionStatusBadge from '@/components/acp/SessionStatusBadge.vue'
|
||||
|
||||
@@ -227,7 +227,6 @@ const props = defineProps<{
|
||||
|
||||
const router = useRouter()
|
||||
const store = useRequirementsStore()
|
||||
const md = new MarkdownIt({ html: false, breaks: true, linkify: true })
|
||||
|
||||
const loading = ref(false)
|
||||
const artifacts = ref<Artifact[]>([])
|
||||
|
||||
@@ -68,9 +68,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { NCard, NDivider, NEmpty, NList, NListItem, NSpin, NTag, NThing } from 'naive-ui'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
import type { Artifact, ArtifactPhase } from '@/api/projects'
|
||||
import { md } from '@/utils/markdown'
|
||||
import { useRequirementsStore } from '@/stores/requirements'
|
||||
|
||||
const PHASE_TITLE: Record<ArtifactPhase, string> = {
|
||||
@@ -86,7 +85,6 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const store = useRequirementsStore()
|
||||
const md = new MarkdownIt({ html: false, breaks: true, linkify: true })
|
||||
|
||||
const artifacts = ref<Artifact[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@@ -54,10 +54,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { NButton, NInput, NModal, NTabPane, NTabs, useMessage } from 'naive-ui'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
import type { ArtifactPhase } from '@/api/projects'
|
||||
import type { ChatMessage } from '@/api/chat'
|
||||
import { md } from '@/utils/markdown'
|
||||
import { useRequirementsStore } from '@/stores/requirements'
|
||||
|
||||
const PHASE_TITLE: Record<ArtifactPhase, string> = {
|
||||
@@ -78,7 +78,6 @@ const emit = defineEmits<{ 'update:show': [v: boolean]; saved: [] }>()
|
||||
|
||||
const store = useRequirementsStore()
|
||||
const message = useMessage()
|
||||
const md = new MarkdownIt({ html: false, breaks: true, linkify: true })
|
||||
|
||||
const content = ref('')
|
||||
const note = ref('')
|
||||
|
||||
Reference in New Issue
Block a user