Files
schemas-app/app/pages/schemas/[id].vue
T
argoyle 5dc29141d5 feat(graph): add Federation Graph page and enhance coverage
Adds a new Federation Graph page to display subgraphs and their 
schemas. Implements loading state and error handling. Enhances 
coverage reporting by including 'lcov' format for better insights 
into test coverage metrics.
2025-11-22 19:49:53 +01:00

226 lines
5.9 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">
const route = useRoute()
const _config = useRuntimeConfig()
const schema = ref<any>(null)
const loading = ref(true)
const snackbar = ref(false)
const snackbarText = ref('')
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}`)
}
// TODO: Fetch actual data from the GraphQL API
onMounted(() => {
// Mock data for now
setTimeout(() => {
schema.value = {
id: route.params.id,
service: 'users-service',
ref: 'production',
url: 'http://users.example.com/graphql',
wsUrl: 'ws://users.example.com/graphql',
updatedAt: '2024-11-21 19:30:00',
updatedBy: 'john.doe@example.com',
sdl: `type User @key(fields: "id") {
id: ID!
username: String!
email: String!
createdAt: DateTime!
}
type Query {
user(id: ID!): User
users(limit: Int, offset: Int): [User!]!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
input CreateUserInput {
username: String!
email: String!
}
input UpdateUserInput {
username: String
email: String
}
scalar DateTime`,
}
loading.value = false
}, 500)
})
</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>