mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Use regular dropdown for default status field, make form work without field meta
This commit is contained in:
@@ -9,11 +9,13 @@
|
||||
|
||||
<component
|
||||
v-if="interfaceExists"
|
||||
:is="`interface-${field.meta.interface}`"
|
||||
v-bind="field.meta.options"
|
||||
:is="
|
||||
field.meta ? `interface-${field.meta.interface}` : `interface-${getDefaultInterfaceForType(field.type)}`
|
||||
"
|
||||
v-bind="(field.meta && field.meta.options) || {}"
|
||||
:disabled="disabled"
|
||||
:value="value === undefined ? field.schema.default_value : value"
|
||||
:width="field.meta.width"
|
||||
:width="(field.meta && field.meta.width) || 'full'"
|
||||
:type="field.type"
|
||||
:collection="field.collection"
|
||||
:field="field.field"
|
||||
@@ -23,7 +25,7 @@
|
||||
/>
|
||||
|
||||
<v-notice v-else type="warning">
|
||||
{{ $t('interface_not_found', { interface: field.meta.interface }) }}
|
||||
{{ $t('interface_not_found', { interface: field.meta && field.meta.interface }) }}
|
||||
</v-notice>
|
||||
</div>
|
||||
</template>
|
||||
@@ -32,6 +34,7 @@
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import { Field } from '@/types';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { getDefaultInterfaceForType } from '@/utils/get-default-interface-for-type';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -68,10 +71,10 @@ export default defineComponent({
|
||||
const interfaces = getInterfaces();
|
||||
|
||||
const interfaceExists = computed(() => {
|
||||
return !!interfaces.value.find((inter) => inter.id === props.field.meta.interface);
|
||||
return !!interfaces.value.find((inter) => inter.id === props.field?.meta?.interface || 'text-input');
|
||||
});
|
||||
|
||||
return { interfaceExists };
|
||||
return { interfaceExists, getDefaultInterfaceForType };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="field" :key="field.field" :class="field.meta.width">
|
||||
<div class="field" :key="field.field" :class="(field.meta && field.meta.width) || 'full'">
|
||||
<v-menu v-if="field.hideLabel !== true" placement="bottom-start" show-arrow :disabled="isDisabled">
|
||||
<template #activator="{ toggle, active }">
|
||||
<form-field-label
|
||||
@@ -33,7 +33,7 @@
|
||||
@input="$emit('input', $event)"
|
||||
/>
|
||||
|
||||
<small class="note" v-if="field.meta.note" v-html="marked(field.meta.note)" />
|
||||
<small class="note" v-if="field.meta && field.meta.note" v-html="marked(field.meta.note)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -84,7 +84,7 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const isDisabled = computed(() => {
|
||||
if (props.disabled) return true;
|
||||
if (props.field.meta.readonly) return true;
|
||||
if (props.field?.meta?.readonly === true) return true;
|
||||
if (props.batchMode && props.batchActive === false) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -5,12 +5,13 @@ import getDefaultInterfaceForType from '@/utils/get-default-interface-for-type';
|
||||
import { getInterfaces } from '@/interfaces';
|
||||
import { FormField } from '@/components/v-form/types';
|
||||
import { Field } from '@/types';
|
||||
import { clone } from 'lodash';
|
||||
|
||||
export default function useFormFields(fields: Ref<Field[]>) {
|
||||
const interfaces = getInterfaces();
|
||||
|
||||
const formFields = computed(() => {
|
||||
let formFields = [...fields.value];
|
||||
let formFields = clone(fields.value);
|
||||
|
||||
// Sort the fields on the sort column value
|
||||
formFields = formFields.sort((a, b) => {
|
||||
@@ -24,31 +25,7 @@ export default function useFormFields(fields: Ref<Field[]>) {
|
||||
});
|
||||
|
||||
formFields = formFields.map((field, index) => {
|
||||
if (!field.meta) {
|
||||
field.meta = {
|
||||
id: -1,
|
||||
collection: field.collection,
|
||||
field: field.field,
|
||||
group: null,
|
||||
hidden: false,
|
||||
locked: false,
|
||||
interface: null,
|
||||
options: null,
|
||||
display: null,
|
||||
display_options: null,
|
||||
readonly: false,
|
||||
required: false,
|
||||
sort: null,
|
||||
special: null,
|
||||
translation: null,
|
||||
width: 'full',
|
||||
note: null,
|
||||
};
|
||||
}
|
||||
|
||||
if (!field.meta.width) {
|
||||
field.meta.width = 'full';
|
||||
}
|
||||
if (!field.meta) return field;
|
||||
|
||||
let interfaceUsed = interfaces.value.find((int) => int.id === field.meta.interface);
|
||||
const interfaceExists = interfaceUsed !== undefined;
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { defineDisplay } from '@/displays/define';
|
||||
import DisplayStatusBadge from './status-badge.vue';
|
||||
|
||||
export default defineDisplay(({ i18n }) => ({
|
||||
id: 'status-badge',
|
||||
name: i18n.t('status_badge'),
|
||||
types: ['string'],
|
||||
icon: 'flag',
|
||||
handler: DisplayStatusBadge,
|
||||
options: null,
|
||||
}));
|
||||
@@ -1,4 +0,0 @@
|
||||
# Status Badge
|
||||
|
||||
Renders the set status formatted according to the status mapping set in the interface options.
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import withPadding from '../../../.storybook/decorators/with-padding';
|
||||
import { withKnobs, text, object } from '@storybook/addon-knobs';
|
||||
import readme from './readme.md';
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
|
||||
export default {
|
||||
title: 'Displays / Status (Badge)',
|
||||
decorators: [withPadding, withKnobs],
|
||||
parameters: {
|
||||
notes: readme,
|
||||
},
|
||||
};
|
||||
|
||||
const defaultStatusMapping = {
|
||||
published: {
|
||||
name: 'Published',
|
||||
value: 'published',
|
||||
text_color: '#fff',
|
||||
background_color: 'var(--primary)',
|
||||
},
|
||||
draft: {
|
||||
name: 'Draft',
|
||||
value: 'draft',
|
||||
text_color: 'var(--primary-subdued)',
|
||||
background_color: 'var(--background-subdued)',
|
||||
},
|
||||
deleted: {
|
||||
name: 'Deleted',
|
||||
value: 'deleted',
|
||||
text_color: 'var(--danger)',
|
||||
background_color: 'var(--danger-alt)',
|
||||
},
|
||||
};
|
||||
|
||||
export const basic = () =>
|
||||
defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
default: text('Value', 'published'),
|
||||
},
|
||||
statusMapping: {
|
||||
default: object('Status Mapping', defaultStatusMapping),
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<display-status-badge
|
||||
:value="value"
|
||||
:interface-options="{
|
||||
status_mapping: statusMapping,
|
||||
}"
|
||||
/>
|
||||
`,
|
||||
});
|
||||
@@ -1,73 +0,0 @@
|
||||
import DisplayStatusBadge from './status-badge.vue';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
import VIcon from '@/components/v-icon';
|
||||
import VueCompositionAPI from '@vue/composition-api';
|
||||
import Tooltip from '@/directives/tooltip';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.component('v-icon', VIcon);
|
||||
localVue.use(VueCompositionAPI);
|
||||
localVue.directive('tooltip', Tooltip);
|
||||
|
||||
describe('Displays / Status Badge', () => {
|
||||
it('Renders an empty span if no value is passed', () => {
|
||||
const component = shallowMount(DisplayStatusBadge, {
|
||||
localVue,
|
||||
propsData: {
|
||||
value: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(component.find('span').exists()).toBe(true);
|
||||
expect(component.find('span').text()).toBe('');
|
||||
});
|
||||
|
||||
it('Renders a question mark icon is status is unknown in interface options', () => {
|
||||
const component = shallowMount(DisplayStatusBadge, {
|
||||
localVue,
|
||||
propsData: {
|
||||
value: 'draft',
|
||||
interfaceOptions: {
|
||||
status_mapping: {
|
||||
published: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(component.find(VIcon).exists()).toBe(true);
|
||||
expect(component.attributes('name')).toBe('help_outline');
|
||||
});
|
||||
|
||||
it('Renders the badge with the correct colors', () => {
|
||||
const component = shallowMount(DisplayStatusBadge, {
|
||||
localVue,
|
||||
propsData: {
|
||||
value: 'draft',
|
||||
interfaceOptions: {
|
||||
status_mapping: {
|
||||
draft: {
|
||||
background_color: 'rgb(171, 202, 188)',
|
||||
text_color: 'rgb(150, 100, 125)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(component.exists()).toBe(true);
|
||||
expect(component.attributes('style')).toBe('background-color: rgb(171, 202, 188); color: rgb(150, 100, 125);');
|
||||
});
|
||||
|
||||
it('Sets status to null if interface options are missing', () => {
|
||||
const component = shallowMount(DisplayStatusBadge, {
|
||||
localVue,
|
||||
propsData: {
|
||||
value: 'draft',
|
||||
interfaceOptions: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect((component.vm as any).status).toBe(null);
|
||||
});
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
<template>
|
||||
<span v-if="!value" />
|
||||
<v-icon name="help_outline" v-else-if="!status" />
|
||||
<div
|
||||
v-else
|
||||
class="badge type-text"
|
||||
:style="{
|
||||
backgroundColor: status.background_color,
|
||||
color: status.text_color,
|
||||
}"
|
||||
>
|
||||
{{ status.name }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
interfaceOptions: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const status = computed(() => {
|
||||
if (props.interfaceOptions === null) return null;
|
||||
|
||||
return props.interfaceOptions.status_mapping?.[props.value];
|
||||
});
|
||||
|
||||
return { status };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
color: var(--foreground-inverted);
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +0,0 @@
|
||||
import InterfaceStatus from './status.vue';
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
|
||||
export default defineInterface(({ i18n }) => ({
|
||||
id: 'status',
|
||||
name: i18n.t('status'),
|
||||
icon: 'bubble_chart',
|
||||
component: InterfaceStatus,
|
||||
types: ['string'],
|
||||
options: [
|
||||
/** @TODO change this to a custom options element */
|
||||
{
|
||||
field: 'status_mapping',
|
||||
name: i18n.t('status_mapping'),
|
||||
type: 'json',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'code',
|
||||
options: {
|
||||
language: 'json'
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
}));
|
||||
@@ -1,26 +0,0 @@
|
||||
# Status Interface
|
||||
|
||||
Renders a dropdown with the available status options.
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description | Default |
|
||||
|------------------|-----------------------------|---------|
|
||||
| `status_mapping` | What statuses are available | `null` |
|
||||
|
||||
### Status Mapping format
|
||||
|
||||
```ts
|
||||
type Status = {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
text_color: string;
|
||||
background_color: string;
|
||||
soft_delete: boolean;
|
||||
published: boolean;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`status_mapping` is the only option for an interface that isn't camelCased. This is due to the fact
|
||||
that the API relies on the same setting for it's permissions management.
|
||||
@@ -1,55 +0,0 @@
|
||||
import withPadding from '../../../.storybook/decorators/with-padding';
|
||||
import { defineComponent, ref } from '@vue/composition-api';
|
||||
import { boolean, withKnobs, object } from '@storybook/addon-knobs';
|
||||
import readme from './readme.md';
|
||||
import RawValue from '../../../.storybook/raw-value.vue';
|
||||
import i18n from '@/lang';
|
||||
|
||||
export default {
|
||||
title: 'Interfaces / Status',
|
||||
decorators: [withPadding, withKnobs],
|
||||
parameters: {
|
||||
notes: readme,
|
||||
},
|
||||
};
|
||||
|
||||
export const basic = () =>
|
||||
defineComponent({
|
||||
i18n,
|
||||
components: { RawValue },
|
||||
props: {
|
||||
statusMapping: {
|
||||
default: object('Status Mapping', {
|
||||
published: {
|
||||
name: 'Published',
|
||||
background_color: 'var(--primary)',
|
||||
},
|
||||
draft: {
|
||||
name: 'Draft',
|
||||
background_color: 'var(--background-normal)',
|
||||
},
|
||||
deleted: {
|
||||
name: 'Deleted',
|
||||
background_color: 'var(--danger)',
|
||||
},
|
||||
}),
|
||||
},
|
||||
disabled: {
|
||||
default: boolean('Disabled', false),
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const value = ref(null);
|
||||
return { value };
|
||||
},
|
||||
template: `
|
||||
<div style="max-width: 300px;">
|
||||
<interface-status
|
||||
v-model="value"
|
||||
:status_mapping="statusMapping"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
<raw-value>{{ value }}</raw-value>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
@@ -1,66 +0,0 @@
|
||||
import VueCompositionAPI from '@vue/composition-api';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import InterfaceStatus from './status.vue';
|
||||
import VNotice from '@/components/v-notice';
|
||||
import VMenu from '@/components/v-menu';
|
||||
import VList, { VListItem, VListItemIcon, VListItemContent } from '@/components/v-list';
|
||||
import i18n from '@/lang';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(VueCompositionAPI);
|
||||
localVue.component('v-notice', VNotice);
|
||||
localVue.component('v-menu', VMenu);
|
||||
localVue.component('v-list', VList);
|
||||
localVue.component('v-list-item', VListItem);
|
||||
localVue.component('v-list-item-content', VListItemContent);
|
||||
localVue.component('v-list-item-icon', VListItemIcon);
|
||||
|
||||
describe('Interfaces / Slider', () => {
|
||||
it('Renders a notice when status mapping is missing', () => {
|
||||
const component = shallowMount(InterfaceStatus, {
|
||||
localVue,
|
||||
i18n,
|
||||
propsData: {},
|
||||
});
|
||||
|
||||
expect(component.find(VNotice).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('Converts the status mapping into a loopable array', () => {
|
||||
const component = shallowMount(InterfaceStatus, {
|
||||
localVue,
|
||||
i18n,
|
||||
propsData: {
|
||||
status_mapping: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect((component.vm as any).statuses).toBe(null);
|
||||
|
||||
component.setProps({
|
||||
status_mapping: {
|
||||
test: {
|
||||
name: 'Test',
|
||||
background_color: '#abcabc',
|
||||
},
|
||||
another_test: {
|
||||
name: 'Another Test',
|
||||
background_color: '#123123',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect((component.vm as any).statuses).toEqual([
|
||||
{
|
||||
value: 'test',
|
||||
name: 'Test',
|
||||
color: '#abcabc',
|
||||
},
|
||||
{
|
||||
value: 'another_test',
|
||||
name: 'Another Test',
|
||||
color: '#123123',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,99 +0,0 @@
|
||||
<template>
|
||||
<v-notice v-if="!statuses">
|
||||
{{ $t('statuses_not_configured') }}
|
||||
</v-notice>
|
||||
<v-menu v-else attached :disabled="disabled">
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input
|
||||
readonly
|
||||
@click="toggle"
|
||||
:value="current ? current.name : null"
|
||||
:placeholder="$t('choose_status')"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<template #prepend>
|
||||
<div
|
||||
class="status-dot"
|
||||
:style="
|
||||
current
|
||||
? { backgroundColor: current.backgroundColor }
|
||||
: { backgroundColor: 'var(--border-normal)' }
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #append><v-icon name="expand_more" :class="{ active }" /></template>
|
||||
</v-input>
|
||||
</template>
|
||||
|
||||
<v-list dense>
|
||||
<v-list-item
|
||||
v-for="(status, key) in statuses"
|
||||
:key="key"
|
||||
:active="key === value"
|
||||
@click="$emit('input', key)"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<div class="status-dot" :style="{ backgroundColor: status.backgroundColor }" />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>{{ status.name }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
statuses: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const current = computed(() => {
|
||||
if (props.value === null) return null;
|
||||
if (props.statuses.hasOwnProperty(props.value) === false) return null;
|
||||
|
||||
return props.statuses[props.value] || null;
|
||||
});
|
||||
|
||||
return { current };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-input {
|
||||
.v-icon {
|
||||
transition: transform var(--medium) var(--transition-out);
|
||||
|
||||
&.active {
|
||||
transform: scaleY(-1);
|
||||
transition-timing-function: var(--transition-in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 2px solid var(--background-page);
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.v-list {
|
||||
.status-dot {
|
||||
border: 2px solid var(--background-subdued);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -7,7 +7,7 @@
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
{{ saveError && saveError.response && saveErrors.response.data.error.message }}
|
||||
{{ saveError && saveError.response && saveError.response.data.errors[0].message }}
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
@@ -120,6 +120,10 @@ export default defineComponent({
|
||||
|
||||
const sortField = ref<string>();
|
||||
|
||||
const archiveField = ref<string>();
|
||||
const archiveValue = ref<string>();
|
||||
const unarchiveValue = ref<string>();
|
||||
|
||||
const systemFields = reactive({
|
||||
status: {
|
||||
enabled: false,
|
||||
@@ -186,6 +190,9 @@ export default defineComponent({
|
||||
collection: collectionName.value,
|
||||
fields: [getPrimaryKeyField(), ...getSystemFields()],
|
||||
sort_field: sortField.value,
|
||||
archive_field: archiveField.value,
|
||||
archive_value: archiveValue.value,
|
||||
unarchive_value: unarchiveValue.value,
|
||||
});
|
||||
|
||||
await collectionsStore.hydrate();
|
||||
@@ -269,31 +276,31 @@ export default defineComponent({
|
||||
width: 'full',
|
||||
required: true,
|
||||
options: {
|
||||
statuses: {
|
||||
published: {
|
||||
name: 'Published',
|
||||
color: 'white',
|
||||
backgroundColor: '#2f80ed',
|
||||
choices: [
|
||||
{
|
||||
value: 'published',
|
||||
text: 'Published',
|
||||
},
|
||||
draft: {
|
||||
name: 'Draft',
|
||||
color: 'white',
|
||||
backgroundColor: '#eceff1',
|
||||
{
|
||||
text: 'Draft',
|
||||
value: 'draft',
|
||||
},
|
||||
deleted: {
|
||||
name: 'Deleted',
|
||||
color: 'white',
|
||||
backgroundColor: '#eb5757',
|
||||
softDelete: true,
|
||||
{
|
||||
text: 'Archived',
|
||||
value: 'archived',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
interface: 'status',
|
||||
interface: 'dropdown',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'draft',
|
||||
},
|
||||
});
|
||||
|
||||
archiveField.value = 'status';
|
||||
archiveValue.value = 'archived';
|
||||
unarchiveValue.value = 'draft';
|
||||
}
|
||||
|
||||
// Sort
|
||||
|
||||
@@ -36,33 +36,6 @@ const fakeFilesField: Field = {
|
||||
},
|
||||
};
|
||||
|
||||
function getMetaDefault(collection: string, field: string): Field['meta'] {
|
||||
/**
|
||||
* @TODO
|
||||
*
|
||||
* Get rid of this. Have it work without any meta
|
||||
*/
|
||||
return {
|
||||
id: -1,
|
||||
collection,
|
||||
field,
|
||||
group: null,
|
||||
hidden: false,
|
||||
interface: null,
|
||||
display: null,
|
||||
display_options: null,
|
||||
locked: false,
|
||||
options: null,
|
||||
readonly: false,
|
||||
required: false,
|
||||
sort: null,
|
||||
special: null,
|
||||
translation: null,
|
||||
width: 'full',
|
||||
note: null,
|
||||
};
|
||||
}
|
||||
|
||||
export const useFieldsStore = createStore({
|
||||
id: 'fieldsStore',
|
||||
state: () => ({
|
||||
@@ -92,13 +65,11 @@ export const useFieldsStore = createStore({
|
||||
parseField(field: FieldRaw): Field {
|
||||
let name: string | VueI18n.TranslateResult;
|
||||
|
||||
const meta = field.meta === null ? getMetaDefault(field.collection, field.field) : field.meta;
|
||||
|
||||
if (i18n.te(`fields.${field.collection}.${field.field}`)) {
|
||||
name = i18n.t(`fields.${field.collection}.${field.field}`);
|
||||
} else if (notEmpty(meta.translation) && meta.translation.length > 0) {
|
||||
for (let i = 0; i < meta.translation.length; i++) {
|
||||
const { locale, translation } = meta.translation[i];
|
||||
} else if (field.meta && notEmpty(field.meta.translation) && field.meta.translation.length > 0) {
|
||||
for (let i = 0; i < field.meta.translation.length; i++) {
|
||||
const { locale, translation } = field.meta.translation[i];
|
||||
|
||||
i18n.mergeLocaleMessage(locale, {
|
||||
fields: {
|
||||
@@ -117,7 +88,6 @@ export const useFieldsStore = createStore({
|
||||
return {
|
||||
...field,
|
||||
name,
|
||||
meta,
|
||||
};
|
||||
},
|
||||
async createField(collectionKey: string, newField: Field) {
|
||||
|
||||
@@ -76,6 +76,4 @@ export interface FieldRaw {
|
||||
|
||||
export interface Field extends FieldRaw {
|
||||
name: string | TranslateResult;
|
||||
type: typeof types[number];
|
||||
meta: FieldMeta;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user