Extract duplicated styles across multiple components into a common CSS file and import it where needed. This improves maintainability by reducing code duplication and centralizing style definitions.
208 lines
6.0 KiB
Vue
208 lines
6.0 KiB
Vue
<template>
|
|
<div class="instance-detail-page">
|
|
<div class="page-header">
|
|
<button class="back-btn" @click="goBack">
|
|
← Back
|
|
</button>
|
|
<h2>{{ instanceName }} - Details</h2>
|
|
</div>
|
|
|
|
<div class="detail-content">
|
|
<div class="section">
|
|
<h3>Configuration</h3>
|
|
<div class="config-list">
|
|
<div class="config-item" v-for="(value, key) in instanceConfig" :key="key">
|
|
<span class="config-key">{{ key }}:</span>
|
|
<span class="config-value">{{ value }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Proxy List</h3>
|
|
<div v-if="proxies.length > 0" class="proxy-list">
|
|
<div v-for="proxy in proxies" :key="proxy.name" class="proxy-item">
|
|
<div class="proxy-header">
|
|
<span class="proxy-name">{{ proxy.name }}</span>
|
|
<span :class="['proxy-status', proxy.status]">
|
|
{{ proxy.status }}
|
|
</span>
|
|
</div>
|
|
<div class="proxy-details">
|
|
<div class="proxy-detail" v-for="(value, key) in proxy.details" :key="key">
|
|
<span class="detail-key">{{ key }}:</span>
|
|
<span class="detail-value">{{ value }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="empty-state">
|
|
<p>No proxies available</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Logs</h3>
|
|
<div class="logs-container">
|
|
<div v-if="logs.length > 0" class="log-list">
|
|
<div v-for="(log, index) in logs" :key="index" class="log-item">
|
|
<span class="log-time">{{ log.time }}</span>
|
|
<span :class="['log-level', log.level]">{{ log.level }}</span>
|
|
<span class="log-message">{{ log.message }}</span>
|
|
</div>
|
|
</div>
|
|
<div v-else class="empty-state">
|
|
<p>No logs available</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, onMounted } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { instanceApi } from '../api/index.js';
|
|
import { showNotification, formatDate } from '../utils/functions.js';
|
|
|
|
export default {
|
|
name: 'InstanceDetail',
|
|
setup() {
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const instanceName = ref(route.params.name);
|
|
const instanceConfig = ref({});
|
|
const proxies = ref([]);
|
|
const logs = ref([]);
|
|
|
|
const loadInstanceConfig = async () => {
|
|
try {
|
|
const result = await instanceApi.listInstances();
|
|
const instance = result.data.find(i => i.name === instanceName.value);
|
|
if (instance) {
|
|
instanceConfig.value = {
|
|
'Server Address': instance.serverAddr,
|
|
'Server Port': instance.serverPort,
|
|
'Auth Method': instance.auth_method,
|
|
'Boot At Start': instance.bootAtStart ? 'Yes' : 'No',
|
|
'Run User': instance.runUser,
|
|
'Config Path': instance.configPath,
|
|
'Created At': formatDate(instance.createdAt)
|
|
};
|
|
}
|
|
} catch (error) {
|
|
showNotification('Load instance configuration failed', 'error');
|
|
}
|
|
};
|
|
|
|
const loadProxies = async () => {
|
|
try {
|
|
const result = await instanceApi.getInstanceProxies(instanceName.value);
|
|
proxies.value = result.data.map(proxy => ({
|
|
name: proxy.name,
|
|
status: proxy.status || 'unknown',
|
|
details: proxy
|
|
}));
|
|
} catch (error) {
|
|
showNotification('Load proxy list failed', 'error');
|
|
}
|
|
};
|
|
|
|
const loadLogs = async () => {
|
|
try {
|
|
const result = await instanceApi.getInstanceLogs(instanceName.value);
|
|
logs.value = result.data.map(log => ({
|
|
time: formatDate(log.timestamp),
|
|
level: log.level,
|
|
message: log.message
|
|
}));
|
|
} catch (error) {
|
|
showNotification('Load logs failed', 'error');
|
|
}
|
|
};
|
|
|
|
const goBack = () => {
|
|
router.push('/instances');
|
|
};
|
|
|
|
onMounted(() => {
|
|
loadInstanceConfig();
|
|
loadProxies();
|
|
loadLogs();
|
|
});
|
|
|
|
return {
|
|
instanceName,
|
|
instanceConfig,
|
|
proxies,
|
|
logs,
|
|
goBack
|
|
};
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
@import '../styles/common.css';
|
|
|
|
.instance-detail-page {
|
|
padding: 24px;
|
|
}
|
|
|
|
.page-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
}
|
|
|
|
.detail-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24px;
|
|
}
|
|
|
|
.config-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.proxy-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.log-item {
|
|
padding: 8px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.log-time {
|
|
min-width: 140px;
|
|
}
|
|
|
|
.log-level {
|
|
min-width: 60px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.log-level.INFO {
|
|
color: #1890ff;
|
|
}
|
|
|
|
.log-level.WARN {
|
|
color: #faad14;
|
|
}
|
|
|
|
.log-level.ERROR {
|
|
color: #ff4d4f;
|
|
}
|
|
|
|
.empty-state {
|
|
padding: 40px 20px;
|
|
font-size: 14px;
|
|
}
|
|
</style>
|