feat: 目的地中文显示名(labels 映射)+ 改名自动同步默认目的地 + 保存校验提示可用目的地
This commit is contained in:
@@ -3,7 +3,7 @@ window.__ModuleLoader__.load({
|
||||
factory(require) {
|
||||
const React = require('react')
|
||||
const h = React.createElement
|
||||
const { useCallback, useEffect, useMemo, useState } = React
|
||||
const { useCallback, useEffect, useState } = React
|
||||
|
||||
const NS = 'abap-adt-ui'
|
||||
const API = '/abap-adt'
|
||||
@@ -19,7 +19,9 @@ window.__ModuleLoader__.load({
|
||||
destinations: '目的地',
|
||||
empty: '还没有配置目的地。内置 demo 模拟系统始终可用。',
|
||||
add: '新增目的地',
|
||||
name: '名称',
|
||||
name: '标识(工具调用用)',
|
||||
displayName: '显示名(中文)',
|
||||
displayNameHint: '只用于界面展示;工具调用仍用「标识」',
|
||||
url: 'URL',
|
||||
client: '客户端',
|
||||
language: '语言',
|
||||
@@ -80,7 +82,9 @@ window.__ModuleLoader__.load({
|
||||
destinations: 'Destinations',
|
||||
empty: 'No destinations configured yet. The built-in demo mock system is always available.',
|
||||
add: 'Add destination',
|
||||
name: 'Name',
|
||||
name: 'Identifier (for tool calls)',
|
||||
displayName: 'Display name',
|
||||
displayNameHint: 'Shown in the UI only; tool calls still use the identifier',
|
||||
url: 'URL',
|
||||
client: 'Client',
|
||||
language: 'Language',
|
||||
@@ -191,7 +195,7 @@ window.__ModuleLoader__.load({
|
||||
}
|
||||
|
||||
function blankDestination() {
|
||||
return { name: '', url: '', client: '100', language: 'EN', username: '', passwordEnv: '', strictSSL: false, profile: 'dev', description: '' }
|
||||
return { name: '', label: '', url: '', client: '100', language: 'EN', username: '', passwordEnv: '', strictSSL: false, profile: 'dev', description: '' }
|
||||
}
|
||||
|
||||
function Field({ label, hint, children }) {
|
||||
@@ -273,13 +277,12 @@ window.__ModuleLoader__.load({
|
||||
load()
|
||||
}, [load])
|
||||
|
||||
const destinationNames = useMemo(
|
||||
() => destinations.map((dest) => dest.name).filter((value) => value && value.trim()),
|
||||
[destinations],
|
||||
)
|
||||
|
||||
const updateDestination = (index, key, value) => {
|
||||
setDestinations((rows) => rows.map((row, rowIndex) => (rowIndex === index ? { ...row, [key]: value } : row)))
|
||||
const row = destinations[index]
|
||||
// Renaming the identifier keeps the default destination in sync, so a
|
||||
// rename cannot leave defaultDestination pointing at a gone name.
|
||||
if (key === 'name' && row && defaultDestination === row.name) setDefaultDestination(value)
|
||||
setDestinations((rows) => rows.map((item, itemIndex) => (itemIndex === index ? { ...item, [key]: value } : item)))
|
||||
}
|
||||
|
||||
const addDestination = () => {
|
||||
@@ -288,6 +291,8 @@ window.__ModuleLoader__.load({
|
||||
}
|
||||
|
||||
const removeDestination = (index) => {
|
||||
const removed = destinations[index]
|
||||
if (removed && removed.name && removed.name === defaultDestination) setDefaultDestination('')
|
||||
setDestinations((rows) => rows.filter((_, rowIndex) => rowIndex !== index))
|
||||
setMessage('')
|
||||
}
|
||||
@@ -309,9 +314,16 @@ window.__ModuleLoader__.load({
|
||||
strictSSL: dest.strictSSL,
|
||||
profile: dest.profile,
|
||||
}))
|
||||
// Display labels are UI-only and keyed by the stable identifier.
|
||||
const labels = {}
|
||||
for (const dest of destinations) {
|
||||
const name = String(dest.name || '').trim()
|
||||
const label = String(dest.label || '').trim()
|
||||
if (name && label) labels[name] = label
|
||||
}
|
||||
const payload = await api('/save', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ workspace, defaultDestination, destinations: payloadDestinations }),
|
||||
body: JSON.stringify({ workspace, defaultDestination, destinations: payloadDestinations, labels }),
|
||||
})
|
||||
setMessage(`${DICTS.zh.saved}: ${payload.path}`)
|
||||
setMessageTone('ok')
|
||||
@@ -473,7 +485,8 @@ window.__ModuleLoader__.load({
|
||||
},
|
||||
h(
|
||||
'div',
|
||||
{ style: { display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 10 } },
|
||||
{ style: { display: 'grid', gridTemplateColumns: '1.2fr 1fr 1.6fr 0.55fr 0.55fr', gap: 10 } },
|
||||
h(Field, { label: DICTS.zh.displayName, hint: DICTS.zh.displayNameHint }, h('input', { style: inputStyle, value: dest.label || '', onChange: (e) => updateDestination(index, 'label', e.target.value), placeholder: '广东开发' })),
|
||||
h(Field, { label: DICTS.zh.name }, h('input', { style: inputStyle, value: dest.name || '', onChange: (e) => updateDestination(index, 'name', e.target.value), placeholder: 'dev' })),
|
||||
h(Field, { label: DICTS.zh.url }, h('input', { style: inputStyle, value: dest.url || '', onChange: (e) => updateDestination(index, 'url', e.target.value), placeholder: 'https://sap.example.com:44300' })),
|
||||
h(Field, { label: DICTS.zh.client }, h('input', { style: inputStyle, value: dest.client || '', onChange: (e) => updateDestination(index, 'client', e.target.value), placeholder: '100' })),
|
||||
@@ -628,7 +641,11 @@ window.__ModuleLoader__.load({
|
||||
'select',
|
||||
{ style: inputStyle, value: defaultDestination, onChange: (e) => setDefaultDestination(e.target.value) },
|
||||
h('option', { value: '' }, 'demo'),
|
||||
destinationNames.map((value) => h('option', { key: value, value }, value)),
|
||||
destinations
|
||||
.filter((dest) => dest.name)
|
||||
.map((dest) =>
|
||||
h('option', { key: dest.name, value: dest.name }, dest.label ? `${dest.label}(${dest.name})` : dest.name),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -682,7 +699,12 @@ window.__ModuleLoader__.load({
|
||||
const destinations = state.destinations || []
|
||||
const names = destinations.map((dest) => dest.name).filter(Boolean)
|
||||
const selected = state.defaultDestination || 'demo'
|
||||
const options = ['demo', ...names.filter((name) => name !== 'demo')]
|
||||
const options = [
|
||||
{ name: 'demo', label: DICTS.zh.chipDemo },
|
||||
...destinations
|
||||
.filter((dest) => dest.name && dest.name !== 'demo')
|
||||
.map((dest) => ({ name: dest.name, label: dest.label || dest.name })),
|
||||
]
|
||||
const modeText = DICTS.zh.modes[state.mode]
|
||||
const modeBadge = modeText
|
||||
? { text: modeText, tone: state.mode === 'change' ? 'err' : state.mode === 'debug' ? 'brand' : 'warn' }
|
||||
@@ -744,7 +766,13 @@ window.__ModuleLoader__.load({
|
||||
maxWidth: 170,
|
||||
},
|
||||
},
|
||||
options.map((name) => h('option', { key: name, value: name }, name)),
|
||||
options.map((option) =>
|
||||
h(
|
||||
'option',
|
||||
{ key: option.name, value: option.name },
|
||||
option.label && option.label !== option.name ? `${option.label}(${option.name})` : option.name,
|
||||
),
|
||||
),
|
||||
),
|
||||
names.length ? h('span', { style: { fontSize: 11, color: C.muted } }, `${names.length} ${DICTS.zh.chipDest}`) : null,
|
||||
modeBadge ? h(Badge, { tone: modeBadge.tone }, modeBadge.text) : null,
|
||||
|
||||
Reference in New Issue
Block a user