Refresh tunnel actions promptly and clarify Feishu OIDC setup
This commit is contained in:
1 parent
41fb9d5631
commit
6a1bace3e9
10 files changed
+136
-32
No files matched your search
@@ -75,24 +75,24 @@
|
||||
<el-table-column :label="$t('tunnels.node')" width="110">
|
||||
<template #default="{ row }">{{ row.node?.name || $t('tunnels.localNode') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('common.operation')" width="285" fixed="right">
|
||||
<el-table-column :label="$t('common.operation')" width="205" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="stateOf(row) !== 'running'" type="success" size="small" plain @click="start(row)">{{ $t('tunnels.start') }}</el-button>
|
||||
<el-button v-else type="warning" size="small" plain @click="stop(row)">{{ $t('tunnels.stop') }}</el-button>
|
||||
<el-button size="small" link @click="showDetail(row)">{{ $t('tunnels.detail') }}</el-button>
|
||||
<el-button v-if="stateOf(row) !== 'running'" type="success" size="small" plain :loading="changingIds.has(row.id)" :disabled="changingIds.has(row.id)" @click="changeState(row, 'start')">{{ $t('tunnels.start') }}</el-button>
|
||||
<el-button v-else type="warning" size="small" plain :loading="changingIds.has(row.id)" :disabled="changingIds.has(row.id)" @click="changeState(row, 'stop')">{{ $t('tunnels.stop') }}</el-button>
|
||||
<el-button size="small" link @click="$router.push(`/tunnels/${row.id}/edit`)">{{ $t('common.edit') }}</el-button>
|
||||
<el-dropdown trigger="click" @command="cmd => onMoreCommand(cmd, row)" style="margin-left:8px">
|
||||
<el-button size="small" link>{{ $t('tunnels.more') }}<el-icon class="el-icon--right"><ArrowDown /></el-icon></el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="detail">{{ $t('tunnels.detail') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="logs">{{ $t('tunnels.viewLogs') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="download">{{ $t('tunnels.downloadConfig') }}</el-dropdown-item>
|
||||
<el-dropdown-item v-if="row.protocol === 'wireguard'" command="qrcode">{{ $t('tunnels.showQrCode') }}</el-dropdown-item>
|
||||
<el-dropdown-item v-if="row.protocol === 'ipsec'" command="ipsec-peer">{{ $t('tunnels.ipsecTest') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="delete" divided>{{ $t('common.delete') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button type="danger" size="small" link @click="remove(row)">{{ $t('common.delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
@@ -251,6 +251,8 @@ const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const list = ref([])
|
||||
const loading = ref(false)
|
||||
const changingIds = ref(new Set())
|
||||
let loadRevision = 0
|
||||
const keyword = ref('')
|
||||
const protocolFilter = ref('')
|
||||
const stateFilter = ref('')
|
||||
@@ -330,6 +332,7 @@ function peerOnline(row) {
|
||||
}
|
||||
|
||||
async function load() {
|
||||
const revision = ++loadRevision
|
||||
loading.value = true
|
||||
try {
|
||||
const { data } = await api.get('/tunnels', { params: { keyword: keyword.value, protocol: protocolFilter.value } })
|
||||
@@ -337,13 +340,15 @@ async function load() {
|
||||
if (stateFilter.value) {
|
||||
result = result.filter(r => stateOf(r) === stateFilter.value)
|
||||
}
|
||||
list.value = result
|
||||
} finally { loading.value = false }
|
||||
if (revision === loadRevision) list.value = result
|
||||
} finally { if (revision === loadRevision) loading.value = false }
|
||||
}
|
||||
|
||||
// 更多操作下拉命令分发
|
||||
function onMoreCommand(cmd, row) {
|
||||
if (cmd === 'download') download(row)
|
||||
if (cmd === 'detail') showDetail(row)
|
||||
else if (cmd === 'delete') remove(row)
|
||||
else if (cmd === 'download') download(row)
|
||||
else if (cmd === 'qrcode') showQr(row)
|
||||
else if (cmd === 'ipsec-peer') router.push('/ipsec-peer')
|
||||
else if (cmd === 'logs') openLogStream(row)
|
||||
@@ -446,23 +451,27 @@ async function savePolicy(tunnelId) {
|
||||
} finally { policySaving.value = false }
|
||||
}
|
||||
|
||||
async function start(row) {
|
||||
async function changeState(row, action) {
|
||||
if (changingIds.value.has(row.id)) return
|
||||
changingIds.value = new Set([...changingIds.value, row.id])
|
||||
++loadRevision // discard a poll started before this operation
|
||||
try {
|
||||
await api.post(`/tunnels/${row.id}/start`)
|
||||
ElMessage.success(t('tunnels.started'))
|
||||
const { data } = await api.post(`/tunnels/${row.id}/${action}`)
|
||||
row.state = data.state
|
||||
row.runtime = null // discard the monitor's older snapshot immediately
|
||||
if (stateFilter.value && stateFilter.value !== data.state) {
|
||||
list.value = list.value.filter(item => item.id !== row.id)
|
||||
}
|
||||
ElMessage.success(t(action === 'start' ? 'tunnels.started' : 'tunnels.stopped'))
|
||||
} catch (e) {
|
||||
ElMessage.error(e.response?.data?.error || t('tunnels.startFailed'))
|
||||
ElMessage.error(e.response?.data?.error || t(action === 'start' ? 'tunnels.startFailed' : 'tunnels.stopFailed'))
|
||||
} finally {
|
||||
try { await load() } finally {
|
||||
const next = new Set(changingIds.value)
|
||||
next.delete(row.id)
|
||||
changingIds.value = next
|
||||
}
|
||||
}
|
||||
load()
|
||||
}
|
||||
async function stop(row) {
|
||||
try {
|
||||
await api.post(`/tunnels/${row.id}/stop`)
|
||||
ElMessage.success(t('tunnels.stopped'))
|
||||
} catch (e) {
|
||||
ElMessage.error(e.response?.data?.error || t('tunnels.stopFailed'))
|
||||
}
|
||||
load()
|
||||
}
|
||||
async function remove(row) {
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user