Neo platform - First Version
This commit is contained in:
87
frontend/pages/app/[appSlug]/[pageSlug].vue
Normal file
87
frontend/pages/app/[appSlug]/[pageSlug].vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-background">
|
||||
<header class="border-b">
|
||||
<div class="container mx-auto px-4 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<NuxtLink to="/" class="text-xl font-bold">Neo Platform</NuxtLink>
|
||||
<nav class="flex gap-4">
|
||||
<NuxtLink
|
||||
v-for="page in pages"
|
||||
:key="page.id"
|
||||
:to="`/app/${appSlug}/${page.slug}`"
|
||||
class="text-sm hover:text-primary"
|
||||
>
|
||||
{{ page.label }}
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<div v-if="loading" class="text-center py-12">Loading...</div>
|
||||
<div v-else-if="error" class="text-destructive">Error: {{ error }}</div>
|
||||
<div v-else-if="page">
|
||||
<h1 class="text-3xl font-bold mb-6">{{ page.label }}</h1>
|
||||
<p class="text-muted-foreground mb-4">Page Type: {{ page.type }}</p>
|
||||
|
||||
<div v-if="page.objectApiName">
|
||||
<h2 class="text-xl font-semibold mb-4">{{ page.object?.label }} Records</h2>
|
||||
|
||||
<div v-if="loadingRecords" class="text-center py-8">Loading records...</div>
|
||||
<div v-else-if="records.length === 0" class="text-center py-8 text-muted-foreground">
|
||||
No records found
|
||||
</div>
|
||||
<div v-else class="space-y-2">
|
||||
<NuxtLink
|
||||
v-for="record in records"
|
||||
:key="record.id"
|
||||
:to="`/app/${appSlug}/${pageSlug}/${record.id}`"
|
||||
class="block p-4 border rounded-lg hover:border-primary transition-colors bg-card"
|
||||
>
|
||||
<div class="font-medium">{{ record.name || record.id }}</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const route = useRoute()
|
||||
const { api } = useApi()
|
||||
|
||||
const appSlug = computed(() => route.params.appSlug as string)
|
||||
const pageSlug = computed(() => route.params.pageSlug as string)
|
||||
|
||||
const pages = ref([])
|
||||
const page = ref(null)
|
||||
const records = ref([])
|
||||
const loading = ref(true)
|
||||
const loadingRecords = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
const fetchPage = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
page.value = await api.get(`/runtime/apps/${appSlug.value}/pages/${pageSlug.value}`)
|
||||
|
||||
const app = await api.get(`/runtime/apps/${appSlug.value}`)
|
||||
pages.value = app.pages
|
||||
|
||||
if (page.value.objectApiName) {
|
||||
loadingRecords.value = true
|
||||
records.value = await api.get(`/runtime/objects/${page.value.objectApiName}/records`)
|
||||
}
|
||||
} catch (e: any) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
loadingRecords.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchPage()
|
||||
})
|
||||
</script>
|
||||
67
frontend/pages/app/[appSlug]/[pageSlug]/[recordId].vue
Normal file
67
frontend/pages/app/[appSlug]/[pageSlug]/[recordId].vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-background">
|
||||
<header class="border-b">
|
||||
<div class="container mx-auto px-4 py-4">
|
||||
<NuxtLink to="/" class="text-xl font-bold">Neo Platform</NuxtLink>
|
||||
</div>
|
||||
</header>
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<div v-if="loading" class="text-center py-12">Loading...</div>
|
||||
<div v-else-if="error" class="text-destructive">Error: {{ error }}</div>
|
||||
<div v-else-if="record">
|
||||
<div class="mb-6">
|
||||
<NuxtLink
|
||||
:to="`/app/${appSlug}/${pageSlug}`"
|
||||
class="text-sm text-primary hover:underline"
|
||||
>
|
||||
← Back to List
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<h1 class="text-3xl font-bold mb-6">{{ record.name || 'Record Detail' }}</h1>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div v-for="(value, key) in record" :key="key" class="border-b pb-2">
|
||||
<div class="text-sm text-muted-foreground">{{ key }}</div>
|
||||
<div class="font-medium">{{ value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const route = useRoute()
|
||||
const { api } = useApi()
|
||||
|
||||
const appSlug = computed(() => route.params.appSlug as string)
|
||||
const pageSlug = computed(() => route.params.pageSlug as string)
|
||||
const recordId = computed(() => route.params.recordId as string)
|
||||
|
||||
const record = ref(null)
|
||||
const loading = ref(true)
|
||||
const error = ref(null)
|
||||
const objectApiName = ref('')
|
||||
|
||||
const fetchRecord = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
// First get page metadata to know which object this is
|
||||
const page = await api.get(`/runtime/apps/${appSlug.value}/pages/${pageSlug.value}`)
|
||||
objectApiName.value = page.objectApiName
|
||||
|
||||
// Then fetch the record
|
||||
record.value = await api.get(`/runtime/objects/${objectApiName.value}/records/${recordId.value}`)
|
||||
} catch (e: any) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchRecord()
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user