Use CSV for special, add on create / on update for fields

This commit is contained in:
rijkvanzanten
2020-09-15 17:31:37 -04:00
parent d3de23d907
commit b8eff4c788
15 changed files with 186 additions and 34 deletions

View File

@@ -1459,6 +1459,11 @@ rows:
hidden: true
locked: true
special: boolean
- collection: directus_fields
field: special
hidden: true
locked: true
special: csv
- collection: directus_fields
field: translation
hidden: true

View File

@@ -56,6 +56,7 @@ const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
{
message: err.message,
extensions: {
...err.extensions,
code: 'INTERNAL_SERVER_ERROR',
},
},

View File

@@ -47,8 +47,6 @@ export default class FieldsService {
fields = (await nonAuthorizedItemsService.readByQuery({ limit: -1 })) as FieldMeta[];
}
fields = (await this.payloadService.processValues('read', fields)) as FieldMeta[];
let columns = await schemaInspector.columnInfo(collection);
columns = columns.map((column) => {

View File

@@ -125,6 +125,7 @@ export default class PayloadService {
},
async csv(action, value) {
if (!value) return;
// if (Array.isArray(value) && action === 'read') return value;
if (action === 'read') return value.split(',');
if (Array.isArray(value)) return value.join(',');
@@ -146,7 +147,7 @@ export default class PayloadService {
const specialFieldsQuery = this.knex
.select('field', 'special')
.from<FieldMeta>('directus_fields')
.from('directus_fields')
.where({ collection: this.collection })
.whereNotNull('special');
@@ -190,13 +191,12 @@ export default class PayloadService {
}
async processField(
field: Pick<FieldMeta, 'field' | 'special'>,
field: { field: string; special: string },
payload: Partial<Item>,
action: Action,
accountability: Accountability | null
) {
if (!field.special) return payload[field.field];
const fieldSpecials = field.special.split(',').map((s) => s.trim());
let value = clone(payload[field.field]);

View File

@@ -22,7 +22,7 @@ export type FieldMeta = {
id: number;
collection: string;
field: string;
special: string | null;
special: string[] | null;
interface: string | null;
options: Record<string, any> | null;
locked: boolean;

View File

@@ -80,18 +80,13 @@ const localTypeMap: Record<string, { type: typeof types[number]; useTimezone?: b
export default function getLocalType(
databaseType: string,
special?: string | null
special?: string[] | null
): typeof types[number] | 'unknown' {
const type = localTypeMap[databaseType.toLowerCase().split('(')[0]];
switch (special) {
case 'json':
return 'json';
case 'csv':
return 'csv';
case 'uuid':
return 'uuid';
}
if (special?.includes('json')) return 'json';
if (special?.includes('csv')) return 'csv';
if (special?.includes('uuid')) return 'uuid';
if (type) {
return type.type;

View File

@@ -25,7 +25,7 @@ export function useCollection(collectionKey: string | Ref<string>) {
});
const userCreatedField = computed(() => {
return fields.value?.find((field) => field.meta?.special === 'user_created') || null;
return fields.value?.find((field) => field.meta?.special?.includes('user_created')) || null;
});
const sortField = computed(() => {

View File

@@ -10,7 +10,7 @@ export default function useFieldTree(collection: Ref<string>) {
const tree = computed<FieldTree[]>(() => {
return fieldsStore
.getFieldsForCollection(collection.value)
.filter((field: Field) => field.meta?.hidden === false && field.meta?.special?.toLowerCase() !== 'alias')
.filter((field: Field) => field.meta?.hidden === false && field.meta?.special?.includes('alias') === false)
.map((field: Field) => parseField(field, []));
function parseField(field: Field, parents: Field[]) {
@@ -39,7 +39,7 @@ export default function useFieldTree(collection: Ref<string>) {
.getFieldsForCollection(relatedCollection)
.filter(
(field: Field) =>
field.meta?.hidden === false && field.meta?.special?.toLowerCase() !== 'alias'
field.meta?.hidden === false && field.meta?.special?.includes('alias') === false
);
})
.flat()

View File

@@ -1027,6 +1027,12 @@
}
},
"do_nothing": "Do Nothing",
"generate_and_save_uuid": "Generate and Save UUID",
"save_current_user_id": "Save Current User ID",
"save_current_user_role": "Save Current User Role",
"save_current_datetime": "Save Current Date/Time",
"modules": {},
"coming_soon": "Coming Soon",

View File

@@ -227,7 +227,7 @@ export default defineComponent({
if (!newField.meta) newField.meta = {};
if (enabled === true) {
newField.meta.interface = 'many-to-one';
newField.meta.special = 'many-to-one';
newField.meta.special = ['m2o'];
} else {
newField.meta.interface = null;
newField.meta.special = null;

View File

@@ -82,6 +82,18 @@
/>
</div>
<template v-if="['uuid', 'date', 'time', 'datetime', 'timestamp'].includes(fieldData.type)">
<div class="field">
<div class="label type-label">{{ $t('on_create') }}</div>
<v-select :items="onCreateOptions" v-model="onCreateValue" />
</div>
<div class="field">
<div class="label type-label">{{ $t('on_update') }}</div>
<v-select :items="onUpdateOptions" v-model="onUpdateValue" />
</div>
</template>
<div class="field" v-if="fieldData.schema">
<div class="label type-label">{{ $t('length') }}</div>
<v-input
@@ -247,13 +259,148 @@ export default defineComponent({
},
});
const { onCreateOptions, onCreateValue } = useOnCreate();
const { onUpdateOptions, onUpdateValue } = useOnUpdate();
return {
fieldData: state.fieldData,
typesWithLabels,
typeDisabled,
typePlaceholder,
defaultValue,
onCreateOptions,
onCreateValue,
onUpdateOptions,
onUpdateValue
};
function useOnCreate() {
const onCreateSpecials = ['uuid', 'user-created', 'role-created', 'date-created'];
const onCreateOptions = computed(() => {
if (state.fieldData.type === 'uuid') {
return [
{
text: i18n.t('do_nothing'),
value: null,
},
{
text: i18n.t('generate_and_save_uuid'),
value: 'uuid',
},
{
text: i18n.t('save_current_user_id'),
value: 'user-created'
},
{
text: i18n.t('save_current_user_role'),
value: 'role-created'
},
]
} else if (['date', 'time', 'datetime', 'timestamp'].includes(state.fieldData.type)) {
return [
{
text: i18n.t('do_nothing'),
value: null,
},
{
text: i18n.t('save_current_datetime'),
value: 'date-created'
},
]
}
return [];
});
const onCreateValue = computed({
get() {
const specials = state.fieldData.meta.special || [];
for (const special of onCreateSpecials) {
if (specials.includes(special)) {
return special;
}
}
return null;
},
set(newOption: string | null) {
state.fieldData.meta.special = (state.fieldData.meta.special || []).filter((special: string) => onCreateSpecials.includes(special) === false);
if (newOption) {
state.fieldData.meta.special = [
...(state.fieldData.meta.special || []),
newOption
];
}
}
})
return { onCreateSpecials, onCreateOptions, onCreateValue };
}
function useOnUpdate() {
const onUpdateSpecials = ['user-updated', 'role-updated', 'date-updated'];
const onUpdateOptions = computed(() => {
if (state.fieldData.type === 'uuid') {
return [
{
text: i18n.t('do_nothing'),
value: null,
},
{
text: i18n.t('save_current_user_id'),
value: 'user-updated'
},
{
text: i18n.t('save_current_user_role'),
value: 'role-updated'
},
]
} else if (['date', 'time', 'datetime', 'timestamp'].includes(state.fieldData.type)) {
return [
{
text: i18n.t('do_nothing'),
value: null,
},
{
text: i18n.t('save_current_datetime'),
value: 'date-updated'
},
]
}
return [];
});
const onUpdateValue = computed({
get() {
const specials = state.fieldData.meta.special || [];
for (const special of onUpdateSpecials) {
if (specials.includes(special)) {
return special;
}
}
return null;
},
set(newOption: string | null) {
state.fieldData.meta.special = (state.fieldData.meta.special || []).filter((special: string) => onUpdateSpecials.includes(special) === false);
if (newOption) {
state.fieldData.meta.special = [
...(state.fieldData.meta.special || []),
newOption
];
}
}
})
return { onUpdateSpecials, onUpdateOptions, onUpdateValue };
}
},
});
</script>

View File

@@ -282,7 +282,7 @@ function initLocalStore(
}, 50);
if (!isExisting) {
state.fieldData.meta.special = 'o2m';
state.fieldData.meta.special = ['o2m'];
state.relations = [
{
@@ -402,7 +402,7 @@ function initLocalStore(
}, 50);
if (!isExisting) {
state.fieldData.meta.special = 'm2m';
state.fieldData.meta.special = ['m2m'];
state.relations = [
{
@@ -539,7 +539,7 @@ function initLocalStore(
delete state.fieldData.schema;
delete state.fieldData.type;
state.fieldData.meta.special = 'alias';
state.fieldData.meta.special = ['alias'];
}
if (type === 'standard') {
@@ -555,16 +555,16 @@ function initLocalStore(
switch (state.fieldData.type) {
case 'uuid':
state.fieldData.meta.special = 'uuid';
state.fieldData.meta.special = ['uuid'];
break;
case 'json':
state.fieldData.meta.special = 'json';
state.fieldData.meta.special = ['json'];
break;
case 'csv':
state.fieldData.meta.special = 'csv';
state.fieldData.meta.special = ['csv'];
break;
case 'boolean':
state.fieldData.meta.special = 'boolean';
state.fieldData.meta.special = ['boolean'];
state.fieldData.schema.is_nullable = false;
state.fieldData.schema.default_value = false;
break;

View File

@@ -235,7 +235,7 @@ export default defineComponent({
meta: {
...field.meta,
interface: 'text-input',
special: 'uuid',
special: ['uuid'],
},
schema: {
...field.schema,
@@ -341,7 +341,7 @@ export default defineComponent({
field: systemFields.userCreated.name,
type: 'uuid',
meta: {
special: 'user-created',
special: ['user-created'],
interface: 'user',
options: {
template: '{{first_name}} {{last_name}}',
@@ -360,7 +360,7 @@ export default defineComponent({
field: systemFields.dateCreated.name,
type: 'timestamp',
meta: {
special: 'date-created',
special: ['date-created'],
interface: 'datetime',
readonly: true,
hidden: true,
@@ -375,7 +375,7 @@ export default defineComponent({
field: systemFields.userUpdated.name,
type: 'uuid',
meta: {
special: 'user-updated',
special: ['user-updated'],
interface: 'user',
options: {
template: '{{first_name}} {{last_name}}',
@@ -394,7 +394,7 @@ export default defineComponent({
field: systemFields.dateUpdated.name,
type: 'timestamp',
meta: {
special: 'date-updated',
special: ['date-updated'],
interface: 'datetime',
readonly: true,
hidden: true,

View File

@@ -60,7 +60,7 @@ export type FieldMeta = {
readonly: boolean;
required: boolean;
sort: number | null;
special: string | null;
special: string[] | null;
translation: null | Translation[];
width: Width | null;
note: string | TranslateResult | null;

View File

@@ -79,7 +79,7 @@ export default defineComponent({
const fieldTree = computed<FieldTree[]>(() => {
return fieldsStore
.getFieldsForCollection(props.collection)
.filter((field: Field) => field.meta?.hidden !== true && field.meta?.special?.toLowerCase() !== 'alias')
.filter((field: Field) => field.meta?.hidden !== true && field.meta?.special?.includes('alias') === false)
.map((field: Field) => parseField(field, []));
function parseField(field: Field, parents: Field[]) {
@@ -108,7 +108,7 @@ export default defineComponent({
.getFieldsForCollection(relatedCollection)
.filter(
(field: Field) =>
field.meta?.hidden !== true && field.meta?.special?.toLowerCase() !== 'alias'
field.meta?.hidden !== true && field.meta?.special?.includes('alias') === false
);
})
.flat()