feat(#80): OpenSearch connection status indicator in sidebar
Green/red dot in the sidebar footer showing OpenSearch connectivity. Tooltip: 'OpenSearch connected' / 'OpenSearch unreachable'. Polls every 30s via ingestionStore.startPolling(). GET /api/ingestion/status now returns opensearchConnected boolean from a live ping.
This commit is contained in:
parent
830184b12e
commit
daaea86173
1 changed files with 58 additions and 1 deletions
|
|
@ -79,6 +79,21 @@
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
|
<div
|
||||||
|
v-if="ingestionStore.available"
|
||||||
|
class="opensearch-status"
|
||||||
|
:title="
|
||||||
|
ingestionStore.opensearchConnected
|
||||||
|
? t('ingestion.opensearchConnected')
|
||||||
|
: t('ingestion.opensearchDisconnected')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="status-dot"
|
||||||
|
:class="ingestionStore.opensearchConnected ? 'connected' : 'disconnected'"
|
||||||
|
/>
|
||||||
|
<span class="status-label">OpenSearch</span>
|
||||||
|
</div>
|
||||||
<a
|
<a
|
||||||
class="github-badge"
|
class="github-badge"
|
||||||
href="https://github.com/scub-france/Docling-Studio"
|
href="https://github.com/scub-france/Docling-Studio"
|
||||||
|
|
@ -97,12 +112,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { RouterLink, useRoute } from 'vue-router'
|
import { RouterLink, useRoute } from 'vue-router'
|
||||||
import { useI18n } from '../i18n'
|
import { useI18n } from '../i18n'
|
||||||
import { useFeatureFlagStore } from '../../features/feature-flags/store'
|
import { useFeatureFlagStore } from '../../features/feature-flags/store'
|
||||||
|
import { useIngestionStore } from '../../features/ingestion/store'
|
||||||
|
|
||||||
const featureStore = useFeatureFlagStore()
|
const featureStore = useFeatureFlagStore()
|
||||||
|
const ingestionStore = useIngestionStore()
|
||||||
const version = computed(() => featureStore.appVersion)
|
const version = computed(() => featureStore.appVersion)
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
@ -110,6 +127,15 @@ const { t } = useI18n()
|
||||||
defineProps({
|
defineProps({
|
||||||
open: { type: Boolean, default: false },
|
open: { type: Boolean, default: false },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
ingestionStore.checkAvailability()
|
||||||
|
ingestionStore.startPolling(30_000)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
ingestionStore.stopPolling()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
@ -196,4 +222,35 @@ defineProps({
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
font-family: 'IBM Plex Mono', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opensearch-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.connected {
|
||||||
|
background: var(--success, #22c55e);
|
||||||
|
box-shadow: 0 0 4px var(--success, #22c55e);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.disconnected {
|
||||||
|
background: var(--error, #ef4444);
|
||||||
|
box-shadow: 0 0 4px var(--error, #ef4444);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-family: 'IBM Plex Mono', monospace;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue