4b6de351bd
- Add GatewayManager for multi-profile gateway lifecycle management - Auto-detect running gateways on startup via PID + health check - Port conflict detection: check managed gateways, allocated ports, and system-level port availability (TCP bind test) - Two-phase startup: sequential port resolution, parallel process launch - Use `gateway start/restart` on normal systems, `gateway run --replace` on WSL/Docker - Wait for health check before returning start/stop responses - Add Gateways page with card-based layout showing profile status - Reorganize sidebar navigation into collapsible groups - Hide API server settings (now auto-managed by GatewayManager) - Profile switch reloads page; Ctrl+C no longer stops gateways - Remove redundant ensureApiServerConfig from index.ts and profiles.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
68 lines
1.5 KiB
Vue
68 lines
1.5 KiB
Vue
<script setup lang="ts">
|
|
import { computed, onMounted } from 'vue'
|
|
import { NSelect, useMessage } from 'naive-ui'
|
|
import { useProfilesStore } from '@/stores/hermes/profiles'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
const { t } = useI18n()
|
|
const message = useMessage()
|
|
const profilesStore = useProfilesStore()
|
|
|
|
const options = computed(() =>
|
|
profilesStore.profiles.map(p => ({
|
|
label: p.name,
|
|
value: p.name,
|
|
})),
|
|
)
|
|
|
|
const activeName = computed(() => profilesStore.activeProfile?.name ?? '')
|
|
|
|
function handleChange(value: string | number | Array<string | number>) {
|
|
if (typeof value === 'string' && value !== activeName.value) {
|
|
profilesStore.switchProfile(value).then(ok => {
|
|
if (ok) {
|
|
message.success(t('profiles.switchSuccess', { name: value }))
|
|
window.location.reload()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
if (profilesStore.profiles.length === 0) {
|
|
profilesStore.fetchProfiles()
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="profile-selector">
|
|
<div class="selector-label">{{ t('sidebar.profiles') }}</div>
|
|
<NSelect
|
|
:value="activeName"
|
|
:options="options"
|
|
:loading="profilesStore.switching"
|
|
size="small"
|
|
@update:value="handleChange"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
@use '@/styles/variables' as *;
|
|
|
|
.profile-selector {
|
|
padding: 0 12px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.selector-label {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
color: $text-muted;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
margin-bottom: 6px;
|
|
}
|
|
</style>
|