Files
schemas-app/app/pages/schemas/[id].vue
T
argoyle 5c17c798c4 feat: enhance authentication error handling and schema fetching
Handle authentication errors related to consent and login in the Apollo 
client by redirecting users to the Auth0 login page as necessary. Update
the schema-fetching logic to support dynamic references from the URL, 
removing mock data and improving overall data integrity in the 
application.
Ensure proper loading states during the fetching process.
2025-11-23 14:01:32 +01:00

226 lines
6.3 KiB
Vue

<template>
<div>
<v-row>
<v-col cols="12">
<v-btn
prepend-icon="mdi-arrow-left"
variant="text"
@click="navigateTo('/schemas')"
>
Back to Schemas
</v-btn>
</v-col>
</v-row>
<v-row v-if="schema">
<v-col cols="12">
<h1 class="text-h3 mb-2">{{ schema.service }}</h1>
<v-chip class="mr-2">{{ schema.ref }}</v-chip>
<v-chip color="success">Active</v-chip>
</v-col>
</v-row>
<v-row v-if="schema">
<v-col cols="12" md="6">
<v-card>
<v-card-title>Details</v-card-title>
<v-card-text>
<v-list>
<v-list-item>
<v-list-item-title>Service</v-list-item-title>
<v-list-item-subtitle>{{ schema.service }}</v-list-item-subtitle>
</v-list-item>
<v-list-item>
<v-list-item-title>Ref</v-list-item-title>
<v-list-item-subtitle>{{ schema.ref }}</v-list-item-subtitle>
</v-list-item>
<v-list-item>
<v-list-item-title>URL</v-list-item-title>
<v-list-item-subtitle>{{ schema.url }}</v-list-item-subtitle>
</v-list-item>
<v-list-item v-if="schema.wsUrl">
<v-list-item-title>WebSocket URL</v-list-item-title>
<v-list-item-subtitle>{{ schema.wsUrl }}</v-list-item-subtitle>
</v-list-item>
<v-list-item>
<v-list-item-title>Last Updated</v-list-item-title>
<v-list-item-subtitle>{{ schema.updatedAt }}</v-list-item-subtitle>
</v-list-item>
<v-list-item>
<v-list-item-title>Updated By</v-list-item-title>
<v-list-item-subtitle>{{ schema.updatedBy }}</v-list-item-subtitle>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-col>
<v-col cols="12" md="6">
<v-card>
<v-card-title>Actions</v-card-title>
<v-card-text>
<v-btn
block
prepend-icon="mdi-download"
variant="outlined"
class="mb-2"
@click="downloadSchema"
>
Download SDL
</v-btn>
<v-btn
block
prepend-icon="mdi-content-copy"
variant="outlined"
class="mb-2"
@click="copyToClipboard"
>
Copy SDL
</v-btn>
<v-btn
block
prepend-icon="mdi-graph"
variant="outlined"
color="primary"
@click="viewFederationGraph"
>
View Federation Graph
</v-btn>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row v-if="schema">
<v-col cols="12">
<v-card>
<v-card-title class="d-flex justify-space-between align-center">
<span>Schema Definition (SDL)</span>
<v-btn
icon="mdi-content-copy"
variant="text"
size="small"
@click="copyToClipboard"
/>
</v-card-title>
<v-card-text>
<pre class="sdl-viewer"><code>{{ schema.sdl }}</code></pre>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row v-if="!schema && !loading">
<v-col cols="12" class="text-center py-12">
<v-icon icon="mdi-alert-circle" size="64" class="mb-4 text-warning" />
<p class="text-h6">Schema not found</p>
</v-col>
</v-row>
<v-snackbar v-model="snackbar" :timeout="2000">
{{ snackbarText }}
</v-snackbar>
</div>
</template>
<script setup lang="ts">
import { useAuth0 } from '@auth0/auth0-vue'
import { useLatestSchemaQuery } from '~/graphql/generated'
const auth0 = useAuth0()
const route = useRoute()
const _config = useRuntimeConfig()
// Parse the ID which should contain both ref and service info
// The ID format from backend is typically: orgId_ref_service or similar
const schemaId = route.params.id as string
const snackbar = ref(false)
const snackbarText = ref('')
// We need to fetch all schemas and find the matching one
// Since we don't have a direct query for a single subgraph by ID,
// we'll need to get it from the URL or store it in a better format
// For now, let's extract ref from the route query or use a default
const schemaRef = computed(() => {
return (route.query.ref as string) || 'production'
})
// Fetch latest schema for the ref
const latestSchemaQuery = useLatestSchemaQuery(() => ({
ref: schemaRef.value,
}), () => ({
skip: !auth0.isAuthenticated.value,
}))
// Find the specific subgraph matching our ID
const schema = computed(() => {
if (!latestSchemaQuery.result.value?.latestSchema?.subGraphs) return null
const subgraph = latestSchemaQuery.result.value.latestSchema.subGraphs.find(
s => s.id === schemaId,
)
if (!subgraph) return null
return {
id: subgraph.id,
service: subgraph.service,
ref: schemaRef.value,
url: subgraph.url || 'N/A',
wsUrl: subgraph.wsUrl,
updatedAt: new Date(subgraph.changedAt).toLocaleString(),
updatedBy: subgraph.changedBy,
sdl: subgraph.sdl,
}
})
const loading = computed(() => latestSchemaQuery.loading.value)
const downloadSchema = () => {
if (!schema.value) return
const blob = new Blob([schema.value.sdl], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${schema.value.service}-${schema.value.ref}.graphql`
a.click()
URL.revokeObjectURL(url)
snackbarText.value = 'Schema downloaded'
snackbar.value = true
}
const copyToClipboard = async () => {
if (!schema.value) return
try {
await navigator.clipboard.writeText(schema.value.sdl)
snackbarText.value = 'SDL copied to clipboard'
snackbar.value = true
} catch (_err) {
snackbarText.value = 'Failed to copy'
snackbar.value = true
}
}
const viewFederationGraph = () => {
if (!schema.value?.ref) return
navigateTo(`/graph/${schema.value.ref}`)
}
</script>
<style scoped>
.sdl-viewer {
background: #f5f5f5;
padding: 16px;
border-radius: 4px;
overflow-x: auto;
font-family: Monaco, Menlo, 'Ubuntu Mono', monospace;
font-size: 14px;
line-height: 1.5;
}
</style>