106 lines
3.1 KiB
Vue
106 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
import { t } from '@/i18n'
|
|
|
|
import { computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { usePermissionsStore } from '@/stores/permissions'
|
|
import DashboardShell from '@/components/DashboardShell.vue'
|
|
import DirectoryAddButton from '@/components/DirectoryAddButton.vue'
|
|
import DirectoryLoadError from '@/components/DirectoryLoadError.vue'
|
|
import SchemaEmpty from '@/components/SchemaEmpty.vue'
|
|
import NoAccessState from '@/components/NoAccessState.vue'
|
|
import SchemaTable from '@/components/SchemaTable.vue'
|
|
import { useSchemaGate } from '@/composables/useSchemaGate'
|
|
import { builtinRow, customRow, schemaSummary } from '@/lib/schemaRows'
|
|
import { useIsDesktop } from '@/composables/useIsDesktop'
|
|
|
|
const NEW_TYPE_PATH = '/schema/new'
|
|
|
|
const router = useRouter()
|
|
const permissions = usePermissionsStore()
|
|
const isDesktop = useIsDesktop()
|
|
|
|
const {
|
|
sessionReady,
|
|
forbidden,
|
|
loading,
|
|
showSkeleton,
|
|
customFailed,
|
|
builtinFailed,
|
|
customItems,
|
|
builtinItems,
|
|
retry,
|
|
} = useSchemaGate('all')
|
|
const failed = computed(
|
|
() => !forbidden.value && !loading.value && (customFailed.value || builtinFailed.value),
|
|
)
|
|
const empty = computed(() => !loading.value && !failed.value && customItems.value.length === 0)
|
|
const populated = computed(() => !loading.value && !failed.value)
|
|
|
|
const customRows = computed(() => customItems.value.map(customRow))
|
|
const builtinRows = computed(() => builtinItems.value.map(builtinRow))
|
|
const summary = computed(() => schemaSummary(customItems.value.length, builtinItems.value.length))
|
|
|
|
const canEdit = computed(() => permissions.can('schema.edit'))
|
|
|
|
function createType() {
|
|
router.push(NEW_TYPE_PATH)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<DashboardShell compact-padding :full-bleed="forbidden" :mobile-title="t('Schema')">
|
|
<NoAccessState v-if="forbidden" />
|
|
|
|
<div v-else-if="sessionReady" class="flex flex-col gap-4">
|
|
<div class="flex flex-wrap items-end gap-4">
|
|
<div class="flex min-w-50 flex-1 flex-col gap-0.5">
|
|
<h1 class="text-xl font-semibold text-highlighted max-lg:sr-only">
|
|
{{ t('Schema') }}
|
|
</h1>
|
|
<p class="text-muted">
|
|
{{ t('Content types and the fields they are made of.') }}
|
|
</p>
|
|
</div>
|
|
<UButton
|
|
v-if="canEdit"
|
|
icon="i-lucide-plus"
|
|
class="h-8 px-3.5 max-md:h-11"
|
|
:disabled="loading"
|
|
@click="createType"
|
|
>
|
|
{{ t('New content type') }}
|
|
</UButton>
|
|
</div>
|
|
|
|
<DirectoryLoadError
|
|
v-if="failed"
|
|
:title="t('Couldn\'t load content types')"
|
|
:description="
|
|
t('GET /v1/content-type failed. Check your connection and try again.')
|
|
"
|
|
@retry="retry"
|
|
/>
|
|
|
|
<template v-else>
|
|
<SchemaEmpty v-if="empty" @create="createType" />
|
|
<SchemaTable
|
|
v-if="showSkeleton || populated"
|
|
:custom="customRows"
|
|
:builtin="builtinRows"
|
|
:loading="showSkeleton"
|
|
/>
|
|
<p v-if="populated && !empty" class="text-muted">{{ summary }}</p>
|
|
</template>
|
|
</div>
|
|
|
|
<DirectoryAddButton
|
|
v-if="!isDesktop && !forbidden && canEdit && populated && !empty"
|
|
pinned
|
|
@click="createType"
|
|
>
|
|
{{ t('New content type') }}
|
|
</DirectoryAddButton>
|
|
</DashboardShell>
|
|
</template>
|