mirror of
https://github.com/directus/directus.git
synced 2026-01-29 09:48:00 -05:00
add v-field-select
This commit is contained in:
@@ -13,6 +13,7 @@ import VDivider from './v-divider';
|
||||
import VError from './v-error';
|
||||
import VFancySelect from './v-fancy-select';
|
||||
import VFieldTemplate from './v-field-template';
|
||||
import VFieldSelect from './v-field-select';
|
||||
import VForm from './v-form';
|
||||
import VHover from './v-hover/';
|
||||
import VIcon from './v-icon/';
|
||||
@@ -64,6 +65,7 @@ Vue.component('v-divider', VDivider);
|
||||
Vue.component('v-error', VError);
|
||||
Vue.component('v-fancy-select', VFancySelect);
|
||||
Vue.component('v-field-template', VFieldTemplate);
|
||||
Vue.component('v-field-select', VFieldSelect);
|
||||
Vue.component('v-form', VForm);
|
||||
Vue.component('v-hover', VHover);
|
||||
Vue.component('v-icon', VIcon);
|
||||
|
||||
37
app/src/components/v-field-select/field-list-item.vue
Normal file
37
app/src/components/v-field-select/field-list-item.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<v-list-item
|
||||
v-if="field.children === undefined"
|
||||
@click="$emit('add', `${parent ? parent + '.' : ''}${field.field}`)"
|
||||
>
|
||||
<v-list-item-content>{{ field.name }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-group v-else>
|
||||
<template #activator>{{ field.name }}</template>
|
||||
<field-list-item
|
||||
v-for="childField in field.children"
|
||||
:key="childField.field"
|
||||
:parent="`${parent ? parent + '.' : ''}${field.field}`"
|
||||
:field="childField"
|
||||
@add="$emit('add', $event)"
|
||||
/>
|
||||
</v-list-group>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from '@vue/composition-api';
|
||||
import { FieldTree } from './types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'field-list-item',
|
||||
props: {
|
||||
field: {
|
||||
type: Object as PropType<FieldTree>,
|
||||
required: true,
|
||||
},
|
||||
parent: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
4
app/src/components/v-field-select/index.ts
Normal file
4
app/src/components/v-field-select/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import VFieldSelect from './v-field-select.vue';
|
||||
|
||||
export default VFieldSelect;
|
||||
export { VFieldSelect };
|
||||
1
app/src/components/v-field-select/readme.md
Normal file
1
app/src/components/v-field-select/readme.md
Normal file
@@ -0,0 +1 @@
|
||||
# Field Select
|
||||
7
app/src/components/v-field-select/types.ts
Normal file
7
app/src/components/v-field-select/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { TranslateResult } from 'vue-i18n';
|
||||
|
||||
export type FieldTree = {
|
||||
field: string;
|
||||
name: string | TranslateResult;
|
||||
children?: FieldTree[];
|
||||
};
|
||||
138
app/src/components/v-field-select/v-field-select.vue
Normal file
138
app/src/components/v-field-select/v-field-select.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="v-field-select">
|
||||
<draggable v-model="activeFields" handle=".drag-handle" :set-data="hideDragImage">
|
||||
<div
|
||||
v-for="(field, index) in activeFields"
|
||||
:key="index"
|
||||
:value="field.field"
|
||||
:label="field.name"
|
||||
class="field"
|
||||
>
|
||||
<v-icon @click.stop="removeField(field.field)" name="close" />
|
||||
<span class="name">{{ field.name }}</span>
|
||||
<v-icon @click.stop name="drag_handle" class="drag-handle" />
|
||||
</div>
|
||||
</draggable>
|
||||
<v-menu attached v-model="menuActive" v-show="selectableFields.length > 0">
|
||||
<template #activator="{ toggle }">
|
||||
<div class="field" @click="toggle">
|
||||
<v-icon name="add" />
|
||||
<span class="name">Add field</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<v-list dense>
|
||||
<field-list-item @add="addField" v-for="field in selectableFields" :key="field.field" :field="field" />
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs, ref, watch, onMounted, onUnmounted, PropType, computed } from '@vue/composition-api';
|
||||
import FieldListItem from './field-list-item.vue';
|
||||
import { useFieldsStore } from '@/stores';
|
||||
import { Field } from '@/types/';
|
||||
import Draggable from 'vuedraggable';
|
||||
import useFieldTree from '@/composables/use-field-tree';
|
||||
import useCollection from '@/composables/use-collection';
|
||||
import { FieldTree } from '../v-field-template/types';
|
||||
import hideDragImage from '@/utils/hide-drag-image';
|
||||
|
||||
export default defineComponent({
|
||||
components: { FieldListItem, Draggable },
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
value: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: null,
|
||||
},
|
||||
collection: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const menuActive = ref(false);
|
||||
|
||||
const { collection } = toRefs(props);
|
||||
const { tree } = useFieldTree(collection);
|
||||
const { info, primaryKeyField, fields: fieldsInCollection, sortField } = useCollection(collection);
|
||||
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(newVal: string[]) {
|
||||
emit('input', newVal);
|
||||
},
|
||||
});
|
||||
|
||||
const treeFlattened = computed(() => {
|
||||
const fields: FieldTree[] = [];
|
||||
const stack: FieldTree[] = tree.value;
|
||||
|
||||
while (stack.length > 0) {
|
||||
const field = stack.shift();
|
||||
if (field === undefined) continue;
|
||||
fields.push(field);
|
||||
if (field.children === undefined) continue;
|
||||
stack.push(...field.children);
|
||||
}
|
||||
return fields;
|
||||
});
|
||||
|
||||
const activeFields = computed({
|
||||
get() {
|
||||
const list = _value.value.map((field) => fieldsInCollection.value.find((f) => f.field === field));
|
||||
const filteredList: Field[] = [];
|
||||
list.forEach((field) => {
|
||||
if (field !== undefined) filteredList.push(field);
|
||||
});
|
||||
|
||||
return filteredList;
|
||||
},
|
||||
set(newVal: Field[]) {
|
||||
_value.value = newVal.map((field) => field.field);
|
||||
},
|
||||
});
|
||||
|
||||
const selectableFields = computed(() => {
|
||||
return fieldsInCollection.value.filter((field) => _value.value.includes(field.field) === false);
|
||||
});
|
||||
|
||||
return { tree, menuActive, addField, activeFields, removeField, selectableFields, hideDragImage };
|
||||
|
||||
function removeField(field: string) {
|
||||
_value.value = _value.value.filter((f) => f !== field);
|
||||
}
|
||||
|
||||
function addField(field: string) {
|
||||
const newArray = _value.value;
|
||||
newArray.push(field);
|
||||
_value.value = newArray;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.field {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.v-icon {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div class="layout-tabular">
|
||||
<portal to="layout-options">
|
||||
<div class="layout-option">
|
||||
<div class="option-label">Test</div>
|
||||
<v-field-select :collection="collection" v-model="selectedFields" />
|
||||
</div>
|
||||
|
||||
<div class="layout-option">
|
||||
<div class="option-label">{{ $t('layouts.tabular.spacing') }}</div>
|
||||
<v-select
|
||||
@@ -211,6 +216,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const selectedFields = ref(['title']);
|
||||
const table = ref<Vue | null>(null);
|
||||
const mainElement = inject('main-element', ref<Element | null>(null));
|
||||
|
||||
@@ -290,6 +296,7 @@ export default defineComponent({
|
||||
activeFilterCount,
|
||||
refresh,
|
||||
resetPresetAndRefresh,
|
||||
selectedFields,
|
||||
};
|
||||
|
||||
async function resetPresetAndRefresh() {
|
||||
|
||||
Reference in New Issue
Block a user