harb/web-app/src/components/layouts/StackVersionFooter.vue

124 lines
3.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<footer class="stack-version-footer" data-testid="stack-version-footer">
<div class="stack-version-footer__items">
<div class="stack-version-footer__item" v-for="item in footerItems" :key="item.key">
<span class="stack-version-footer__label">{{ item.label }}</span>
<span class="stack-version-footer__value" :class="valueClass(item.key)" :data-testid="`stack-version-${item.key}`">
{{ item.value }}
</span>
</div>
</div>
<p v-if="footerMessage" class="stack-version-footer__warning" data-testid="stack-version-warning">
{{ footerMessage }}
</p>
</footer>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { DEFAULT_CHAIN_ID } from '@/config';
import { resolveGraphqlEndpoint } from '@/utils/graphqlRetry';
import { useVersionCheckOnMount } from '@/composables/useVersionCheck';
import logger from '@/utils/logger';
const endpointHint = ref<string | null>(null);
let endpoint: string | undefined;
try {
endpoint = resolveGraphqlEndpoint(DEFAULT_CHAIN_ID);
logger.info('Stack version footer resolved GraphQL endpoint', endpoint);
} catch (error) {
endpoint = undefined;
endpointHint.value = 'GraphQL endpoint unavailable ensure the stack is running.';
logger.error('Failed to resolve GraphQL endpoint for stack version footer', error);
}
const { versionStatus, stackVersions, isChecking, hasChecked } = useVersionCheckOnMount(endpoint);
const footerItems = computed(() => {
const loading = isChecking.value && !hasChecked.value;
const loadingText = loading ? 'Loading…' : '—';
return [
{
key: 'contracts',
label: 'Contracts',
value: stackVersions.value.contractVersion !== null ? `v${stackVersions.value.contractVersion}` : loadingText,
},
{
key: 'ponder',
label: 'Ponder',
value: stackVersions.value.ponderVersion ? `v${stackVersions.value.ponderVersion}` : loadingText,
},
{
key: 'kraiken-lib',
label: 'kraiken-lib',
value: `v${stackVersions.value.kraikenLibVersion}`,
},
{
key: 'web-app',
label: 'Web App',
value: `v${stackVersions.value.webAppVersion}`,
},
] as const;
});
const footerMessage = computed(() => {
if (!versionStatus.value.isValid) {
return versionStatus.value.error ?? 'Stack version mismatch detected.';
}
return endpointHint.value;
});
function valueClass(key: (typeof footerItems.value)[number]['key']) {
if (key === 'kraiken-lib') {
return versionStatus.value.isValid ? null : 'stack-version-footer__value--warning';
}
return null;
}
</script>
<style lang="sass" scoped>
.stack-version-footer
padding: 12px 24px
background: rgba(7, 17, 27, 0.92)
color: #cbd5f5
border-top: 1px solid rgba(255, 255, 255, 0.08)
font-size: 12px
letter-spacing: 0.04em
display: flex
flex-direction: column
gap: 8px
align-items: center
width: 100%
.stack-version-footer__items
display: flex
flex-wrap: wrap
justify-content: center
gap: 16px
.stack-version-footer__item
display: flex
gap: 6px
align-items: baseline
.stack-version-footer__label
text-transform: uppercase
font-weight: 600
font-size: 11px
color: #94a3b8
.stack-version-footer__value
font-family: 'Fira Code', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace
font-weight: 600
color: #e2e8f0
.stack-version-footer__value--warning
color: #f97316
.stack-version-footer__warning
margin: 0
color: #f97316
font-size: 11px
text-align: center
</style>