@@ -125,6 +133,12 @@
{{ $t('step1.graphRagDesc') }}
+
+
@@ -201,7 +215,8 @@ const props = defineProps({
ontologyProgress: Object,
buildProgress: Object,
graphData: Object,
- systemLogs: { type: Array, default: () => [] }
+ systemLogs: { type: Array, default: () => [] },
+ errorMsg: { type: String, default: '' }
})
defineEmits(['next-step'])
@@ -349,6 +364,7 @@ watch(() => props.systemLogs.length, () => {
.badge.processing { background: #FF5722; color: #FFF; }
.badge.accent { background: #FF5722; color: #FFF; }
.badge.pending { background: #F5F5F5; color: #999; }
+.badge.error { background: #FFEBEE; color: #D32F2F; }
.api-note {
font-family: 'JetBrains Mono', monospace;
@@ -364,6 +380,28 @@ watch(() => props.systemLogs.length, () => {
margin-bottom: 16px;
}
+.error-alert {
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ background: #FFF5F5;
+ border: 1px solid #FFCDD2;
+ border-radius: 6px;
+ padding: 12px;
+ margin-top: 8px;
+}
+
+.error-icon {
+ font-size: 14px;
+}
+
+.error-text {
+ font-size: 12px;
+ color: #C62828;
+ line-height: 1.4;
+ word-break: break-word;
+}
+
/* Step 01 Tags */
.tags-container {
margin-top: 12px;
diff --git a/frontend/src/views/MainView.vue b/frontend/src/views/MainView.vue
index 513c70d8..e8c48bd6 100644
--- a/frontend/src/views/MainView.vue
+++ b/frontend/src/views/MainView.vue
@@ -59,6 +59,7 @@
:buildProgress="buildProgress"
:graphData="graphData"
:systemLogs="systemLogs"
+ :errorMsg="error"
@next-step="handleNextStep"
/>
@@ -83,7 +84,7 @@ import { useI18n } from 'vue-i18n'
import GraphPanel from '../components/GraphPanel.vue'
import Step1GraphBuild from '../components/Step1GraphBuild.vue'
import Step2EnvSetup from '../components/Step2EnvSetup.vue'
-import { generateOntology, getProject, buildGraph, getTaskStatus, getGraphData } from '../api/graph'
+import { generateOntology, getProject, buildGraph, getTaskStatus, getGraphData, getGraphConfig } from '../api/graph'
import { getPendingUpload, clearPendingUpload } from '../store/pendingUpload'
import LanguageSwitcher from '../components/LanguageSwitcher.vue'
@@ -114,6 +115,9 @@ const systemLogs = ref([])
let pollTimer = null
let graphPollTimer = null
+// Graph polling config (fetched from backend)
+const graphPollInterval = ref(0) // 0 = manual only
+
// --- Computed Layout Styles ---
const leftPanelStyle = computed(() => {
if (viewMode.value === 'graph') return { width: '100%', opacity: 1, transform: 'translateX(0)' }
@@ -184,6 +188,19 @@ const handleGoBack = () => {
const initProject = async () => {
addLog('Project view initialized.')
+
+ // Fetch graph polling config from backend
+ try {
+ const configRes = await getGraphConfig()
+ if (configRes.success && configRes.data) {
+ graphPollInterval.value = configRes.data.poll_interval || 0
+ addLog(`Graph config loaded: poll_interval=${graphPollInterval.value}s, cache_ttl=${configRes.data.cache_ttl}s`)
+ }
+ } catch (err) {
+ addLog('Could not load graph config, defaulting to manual refresh only.')
+ graphPollInterval.value = 0
+ }
+
if (currentProjectId.value === 'new') {
await handleNewProject()
} else {
@@ -295,9 +312,17 @@ const startBuildGraph = async () => {
}
const startGraphPolling = () => {
- addLog('Started polling for graph data...')
+ // Always do one immediate fetch
fetchGraphData()
- graphPollTimer = setInterval(fetchGraphData, 10000)
+
+ // Only set up automatic polling if poll_interval > 0 (paid plan)
+ if (graphPollInterval.value > 0) {
+ const intervalMs = graphPollInterval.value * 1000
+ addLog(`Started automatic graph polling (every ${graphPollInterval.value}s)...`)
+ graphPollTimer = setInterval(fetchGraphData, intervalMs)
+ } else {
+ addLog('Automatic graph polling disabled (FREE plan). Use manual refresh.')
+ }
}
const fetchGraphData = async () => {
diff --git a/frontend/src/views/Process.vue b/frontend/src/views/Process.vue
index 2d2d3cc1..591c5473 100644
--- a/frontend/src/views/Process.vue
+++ b/frontend/src/views/Process.vue
@@ -414,7 +414,7 @@