Add new export experience (#12201)

* Use script setup

* Start on export dialog

* Use new system field interface, replace limit with numeric input

* Set placeholder

* Add sort config

* Use folder picker, correct layoutQuery use

* Add local download button

* Allow writing exports to file

* Add notification after export

* Fix sort config, use new export endpoint

* Setup notification hints

* Add information notice

* Fix local limit, cancel button

* Add (basic) docs for export functionality

* Fix json export file format

* Implement xml batch stitching

* Resolve review points
This commit is contained in:
Rijk van Zanten
2022-03-17 15:43:45 -04:00
committed by GitHub
parent aca9ff9709
commit 1c3e94d830
25 changed files with 1095 additions and 416 deletions

View File

@@ -0,0 +1,12 @@
import { defineInterface } from '@directus/shared/utils';
import InterfaceSystemFields from './system-fields.vue';
export default defineInterface({
id: 'system-fields',
name: '$t:interfaces.fields.name',
icon: 'search',
component: InterfaceSystemFields,
types: ['csv', 'json'],
options: [],
system: true,
});

View File

@@ -0,0 +1,87 @@
<template>
<v-list>
<draggable v-model="fields" :force-fallback="true" item-key="key" handle=".drag-handle">
<template #item="{ element: field }">
<v-list-item block>
<v-icon name="drag_handle" class="drag-handle" left />
<div class="name">{{ field.name }}</div>
<div class="spacer" />
<v-icon name="close" clickable @click="removeField(field.key)" />
</v-list-item>
</template>
</draggable>
</v-list>
<v-menu placement="bottom-start" show-arrow>
<template #activator="{ toggle }">
<button class="toggle" @click="toggle">
{{ t('add_field') }}
<v-icon name="expand_more" />
</button>
</template>
<v-field-list :disabled-fields="value" :collection="collectionName" @select-field="addField" />
</v-menu>
</template>
<script lang="ts" setup>
import { useFieldsStore } from '@/stores/fields';
import { Field } from '@directus/shared/types';
import { computed } from 'vue';
import Draggable from 'vuedraggable';
import { useI18n } from 'vue-i18n';
interface Props {
collectionName: string;
value?: string[] | null;
}
const props = withDefaults(defineProps<Props>(), { value: () => null });
const emit = defineEmits(['input']);
const fieldsStore = useFieldsStore();
const fields = computed<(Field & { key: string })[]>({
get() {
return (
props.value?.map((fieldKey) => ({
key: fieldKey,
...fieldsStore.getField(props.collectionName, fieldKey)!,
})) ?? []
);
},
set(updatedFields) {
const newFields = updatedFields.map((field) => field.key);
emit('input', newFields);
},
});
const { t } = useI18n();
function addField(fieldKey: string) {
emit('input', [...(props.value ?? []), fieldKey]);
}
function removeField(fieldKey: string) {
const newArray = props.value?.filter((val) => val !== fieldKey);
if (!newArray || newArray.length === 0) {
emit('input', null);
}
emit('input', newArray);
}
</script>
<style lang="scss" scoped>
.toggle {
color: var(--primary);
font-weight: 600;
margin-left: 10px;
margin-top: 6px;
.v-icon {
position: absolute;
}
}
</style>