mirror of
https://github.com/directus/directus.git
synced 2026-01-27 13:37:59 -05:00
Collection display template (#487)
* Add translation strings for adding/editing item * Add display_template to collection type * Dont use functional for skeleton loader * Make title optional and add title slot * Make title prop optional in private view * Render -- for null values in render template * Render display template in header bar * Render null values in template as subdued -- * Render status dot aligned in the middle * Fetch latest collections on settings save
This commit is contained in:
@@ -356,7 +356,7 @@ body {
|
||||
.interface {
|
||||
position: relative;
|
||||
|
||||
::v-deep .v-skeleton-loader {
|
||||
.v-skeleton-loader {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template functional>
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div class="v-skeleton-loader" :class="props.type">
|
||||
<template v-if="props.type === 'list-item-icon'">
|
||||
<div :class="type" class="v-skeleton-loader">
|
||||
<template v-if="type === 'list-item-icon'">
|
||||
<div class="icon" />
|
||||
<div class="text" />
|
||||
</template>
|
||||
|
||||
@@ -43,6 +43,7 @@ export default defineComponent({
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin: 0 4px;
|
||||
vertical-align: middle;
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
"3": "Only super admins have access to this",
|
||||
"4": "Super Admin Token not provided",
|
||||
"11": "Can't Reach Database",
|
||||
"12": "Field has invalid regular expression",
|
||||
"100": "Incorrect Email/Password",
|
||||
"101": "Logged-out from Inactivity",
|
||||
"102": "Logged-out from Inactivity",
|
||||
@@ -375,6 +376,9 @@
|
||||
"statuses_not_configured": "Status mapping option configured incorrectly",
|
||||
"status_mapping": "Status Mapping",
|
||||
|
||||
"adding_in": "Adding New Item in {collection}",
|
||||
"editing_in": "Editing Item in {collection}",
|
||||
|
||||
"about_directus": "About Directus",
|
||||
"activity_log": "Activity Log",
|
||||
"add_field_filter": "Add a field filter",
|
||||
@@ -535,7 +539,6 @@
|
||||
"drop_files": "Can't Drop Files | Drop file here... | Drop files here...",
|
||||
"duplicate": "Duplicate",
|
||||
"duplicating_field": "Duplicating Field",
|
||||
"editing": "Editing Item: {collection}",
|
||||
"editing_item": "Editing Item",
|
||||
"editing_items": "Batch Editing {count} Items",
|
||||
"editing_my_profile": "Editing My Profile",
|
||||
|
||||
@@ -200,7 +200,7 @@ export default defineComponent({
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
}
|
||||
|
||||
::v-deep .v-skeleton-loader {
|
||||
.v-skeleton-loader {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -25,6 +25,7 @@ describe('Modules / Collections / Compositions / useNavigation', () => {
|
||||
managed: true,
|
||||
single: false,
|
||||
translation: null,
|
||||
display_template: null,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -60,6 +61,7 @@ describe('Modules / Collections / Compositions / useNavigation', () => {
|
||||
managed: true,
|
||||
single: false,
|
||||
translation: null,
|
||||
display_template: null,
|
||||
},
|
||||
{
|
||||
collection: 'test2',
|
||||
@@ -70,6 +72,7 @@ describe('Modules / Collections / Compositions / useNavigation', () => {
|
||||
managed: true,
|
||||
single: false,
|
||||
translation: null,
|
||||
display_template: null,
|
||||
},
|
||||
{
|
||||
collection: 'test3',
|
||||
@@ -80,6 +83,7 @@ describe('Modules / Collections / Compositions / useNavigation', () => {
|
||||
managed: true,
|
||||
single: false,
|
||||
translation: null,
|
||||
display_template: null,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -3,11 +3,22 @@
|
||||
<private-view
|
||||
v-else
|
||||
:title="
|
||||
$t(collectionInfo.single ? 'editing_single' : 'editing', {
|
||||
collection: collectionInfo.name,
|
||||
})
|
||||
isNew
|
||||
? $t('adding_in', { collection: collectionInfo.name })
|
||||
: $t('editing_in', { collection: collectionInfo.name })
|
||||
"
|
||||
>
|
||||
<template #title v-if="isNew === false && collectionInfo.display_template">
|
||||
<v-skeleton-loader class="title-loader" type="text" v-if="loading" />
|
||||
<h1 class="type-title" v-else>
|
||||
<render-template
|
||||
:collection="collectionInfo.collection"
|
||||
:item="templateValues"
|
||||
:template="collectionInfo.display_template"
|
||||
/>
|
||||
</h1>
|
||||
</template>
|
||||
|
||||
<template #title-outer:prepend>
|
||||
<v-button
|
||||
v-if="collectionInfo.single"
|
||||
@@ -190,6 +201,13 @@ export default defineComponent({
|
||||
() => `/${currentProjectKey.value}/collections/${collection.value}/`
|
||||
);
|
||||
|
||||
const templateValues = computed(() => {
|
||||
return {
|
||||
...(item.value || {}),
|
||||
...edits.value,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
item,
|
||||
loading,
|
||||
@@ -211,6 +229,7 @@ export default defineComponent({
|
||||
saveAsCopyAndNavigate,
|
||||
isBatch,
|
||||
softDeleteStatus,
|
||||
templateValues,
|
||||
};
|
||||
|
||||
async function saveAndQuit() {
|
||||
@@ -268,4 +287,8 @@ export default defineComponent({
|
||||
.v-form {
|
||||
padding: var(--content-padding);
|
||||
}
|
||||
|
||||
.title-loader {
|
||||
width: 260px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -52,7 +52,7 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .v-skeleton-loader {
|
||||
.v-skeleton-loader {
|
||||
--v-skeleton-loader-background-color: var(--background-normal-alt);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ import useProjectsStore from '@/stores/projects';
|
||||
import { i18n } from '@/lang';
|
||||
import useItem from '@/compositions/use-item';
|
||||
import router from '@/router';
|
||||
import useCollectionsStore from '@/stores/collections';
|
||||
|
||||
export default defineComponent({
|
||||
components: { SettingsNavigation, FieldsManagement },
|
||||
@@ -96,6 +97,7 @@ export default defineComponent({
|
||||
const { collection } = toRefs(props);
|
||||
const { info: collectionInfo, fields } = useCollection(collection);
|
||||
const { currentProjectKey } = toRefs(projectsStore.state);
|
||||
const collectionsStore = useCollectionsStore();
|
||||
|
||||
const breadcrumb = computed(() => {
|
||||
return [
|
||||
@@ -152,6 +154,7 @@ export default defineComponent({
|
||||
|
||||
async function saveAndQuit() {
|
||||
await save();
|
||||
await collectionsStore.hydrate();
|
||||
router.push(`/${currentProjectKey.value}/settings/data-model`);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -36,7 +36,7 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .v-skeleton-loader {
|
||||
.v-skeleton-loader {
|
||||
--v-skeleton-loader-background-color: var(--background-normal-alt);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-notice,
|
||||
::v-deep .v-skeleton-loader {
|
||||
.v-skeleton-loader {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface CollectionRaw {
|
||||
managed: boolean;
|
||||
icon: string | null;
|
||||
translation: Translation[] | null;
|
||||
display_template: string | null;
|
||||
}
|
||||
|
||||
export interface Collection extends CollectionRaw {
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
<div class="title-container">
|
||||
<slot name="headline" />
|
||||
<div class="title">
|
||||
<slot name="title:prepend" />
|
||||
<h1 class="type-title">{{ title }}</h1>
|
||||
<slot name="title:append" />
|
||||
<slot name="title">
|
||||
<slot name="title:prepend" />
|
||||
<h1 class="type-title">{{ title }}</h1>
|
||||
<slot name="title:append" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,7 +40,7 @@ export default defineComponent({
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="render-template">
|
||||
<template v-for="(part, index) in parts">
|
||||
<span :key="index" v-if="part === null || part.value === null" class="subdued">--</span>
|
||||
<component
|
||||
v-if="part !== null && typeof part === 'object'"
|
||||
v-else-if="typeof part === 'object'"
|
||||
:is="`display-${part.component}`"
|
||||
:key="index"
|
||||
:value="part.value"
|
||||
:value="part.value === null ? '--' : part.value"
|
||||
:interface="part.interface"
|
||||
:interface-options="part.interfaceOptions"
|
||||
v-bind="part.options"
|
||||
@@ -91,4 +92,8 @@ export default defineComponent({
|
||||
.render-template {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.subdued {
|
||||
color: var(--foreground-subdued);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -94,7 +94,7 @@ export default defineComponent({
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
|
||||
Reference in New Issue
Block a user