Browse Source

feat(nc-gui): add separator option in csv export extension

nc-feat/export-csv-delimiters
Ramesh Mane 2 days ago
parent
commit
cfb9815243
  1. 213
      packages/nc-gui/extensions/data-exporter/index.vue

213
packages/nc-gui/extensions/data-exporter/index.vue

@ -7,6 +7,25 @@ const jobStatusTooltip = {
[JobStatus.FAILED]: 'Export failed',
} as Record<string, string>
const delimiters = [
{
label: 'Comma (,)',
value: ',',
},
{
label: 'Semicolon (;)',
value: ';',
},
{
label: 'Tab (\\t)',
value: '\\t',
},
{
label: 'Pipe (|)',
value: '|',
},
]
const { $api, $poller } = useNuxtApp()
const { appInfo } = useGlobal()
@ -60,7 +79,10 @@ const exportedFiles = computed(() => {
const exportPayload = ref<{
tableId?: string
viewId?: string
}>({})
delimiter?: string
}>({
delimiter: ',',
})
const tableList = computed(() => {
return tables.value.map((table) => {
@ -123,7 +145,10 @@ async function exportDataAsync() {
isExporting.value = true
const jobData = await $api.export.data(exportPayload.value.viewId, 'csv', { extension_id: extension.value.id })
const jobData = await $api.export.data(exportPayload.value.viewId, 'csv', {
extension_id: extension.value.id,
delimiter: exportPayload.value.delimiter,
})
jobList.value.unshift(jobData)
$poller.subscribe(
@ -255,51 +280,133 @@ onMounted(async () => {
'bg-nc-bg-gray-extralight': fullscreen,
}"
>
<div
class="p-3 flex items-center justify-between gap-2.5 flex-wrap"
:class="{
'bg-white': fullscreen,
}"
>
<div class="p-3 flex flex-col gap-2">
<div
class="nc-data-exporter-select-wrapper flex-1 flex items-center border-1 border-nc-border-gray-medium rounded-lg relative shadow-default"
class="flex items-center justify-between gap-2.5 flex-wrap"
:class="{
'max-w-[min(400px,calc(100%-131px))]': isExporting && !fullscreen && width > 425,
'max-w-[min(400px,calc(100%_-_87px))]': !isExporting && !fullscreen && width > 425,
'max-w-full': width <= 425,
'max-w-[474px]': fullscreen,
'bg-white': fullscreen,
}"
>
<a-form-item
class="!my-0"
<div
class="nc-data-exporter-select-wrapper flex-1 flex items-center border-1 border-nc-border-gray-medium rounded-lg relative shadow-default"
:class="{
'flex-1 max-w-[237px]': fullscreen,
'min-w-1/2 max-w-[200px]': !fullscreen,
'max-w-[min(400px,calc(100%-131px))]': isExporting && !fullscreen && width > 425,
'max-w-[min(400px,calc(100%_-_87px))]': !isExporting && !fullscreen && width > 425,
'max-w-full': width <= 425,
'max-w-[474px]': fullscreen,
}"
>
<a-form-item
class="!my-0"
:class="{
'flex-1 max-w-[237px]': fullscreen,
'min-w-1/2 max-w-[200px]': !fullscreen,
}"
>
<NcSelect
v-model:value="exportPayload.tableId"
placeholder="-select table-"
:disabled="isExporting"
class="nc-data-exporter-table-select nc-select-shadow"
:filter-option="filterOption"
dropdown-class-name="w-[250px]"
show-search
size="large"
@change="onTableSelect"
>
<a-select-option v-for="table of tableList" :key="table.label" :value="table.value">
<div class="w-full flex items-center gap-2">
<div class="min-w-5 flex items-center justify-center">
<GeneralTableIcon :meta="{ meta: table.meta }" class="text-gray-500" />
</div>
<NcTooltip class="flex-1 truncate" show-on-truncate-only>
<template #title>{{ table.label }}</template>
<span>{{ table.label }}</span>
</NcTooltip>
<component
:is="iconMap.check"
v-if="exportPayload.tableId === table.value"
id="nc-selected-item-icon"
class="flex-none text-primary w-4 h-4"
/>
</div>
</a-select-option>
</NcSelect>
</a-form-item>
<a-form-item
class="!my-0"
:class="{
'flex-1 max-w-[237px]': fullscreen,
'min-w-1/2 max-w-[200px]': !fullscreen,
}"
>
<NcSelect
v-model:value="exportPayload.viewId"
placeholder="-select view-"
:disabled="isExporting"
class="nc-data-exporter-view-select nc-select-shadow"
dropdown-class-name="w-[250px]"
:filter-option="filterOption"
show-search
size="large"
placement="bottomRight"
@change="onViewSelect"
>
<a-select-option v-for="view of viewList" :key="view.label" :value="view.value">
<div class="w-full flex items-center gap-2">
<div class="min-w-5 flex items-center justify-center">
<GeneralViewIcon :meta="{ meta: view.meta, type: view.type }" class="flex-none text-gray-500" />
</div>
<NcTooltip class="flex-1 truncate" show-on-truncate-only>
<template #title>{{ view.label }}</template>
<span>{{ view.label }}</span>
</NcTooltip>
<component
:is="iconMap.check"
v-if="exportPayload.viewId === view.value"
id="nc-selected-item-icon"
class="flex-none text-primary w-4 h-4"
/>
</div> </a-select-option
></NcSelect>
</a-form-item>
</div>
<div class="flex-none flex justify-end">
<NcTooltip class="flex" placement="topRight" :disabled="!isExporting">
<template #title> The CSV file is being prepared in the background. You'll be notified once it's ready. </template>
<NcButton
:disabled="!exportPayload?.viewId || isExporting"
:loading="isExporting"
size="medium"
@click="exportDataAsync"
>{{ isExporting ? 'Generating' : 'Export' }}</NcButton
>
</NcTooltip>
</div>
</div>
<div>
<a-form-item class="!my-0 flex-1 max-w-[237px]">
<NcSelect
v-model:value="exportPayload.tableId"
placeholder="-select table-"
v-model:value="exportPayload.delimiter"
placeholder="-select separator-"
:disabled="isExporting"
class="nc-data-exporter-table-select nc-select-shadow"
class="nc-data-exporter-separator nc-select-shadow"
:filter-option="filterOption"
dropdown-class-name="w-[250px]"
show-search
size="large"
@change="onTableSelect"
>
<a-select-option v-for="table of tableList" :key="table.label" :value="table.value">
<a-select-option v-for="delimiter of delimiters" :key="delimiter.label" :value="delimiter.value">
<div class="w-full flex items-center gap-2">
<div class="min-w-5 flex items-center justify-center">
<GeneralTableIcon :meta="{ meta: table.meta }" class="text-gray-500" />
</div>
<NcTooltip class="flex-1 truncate" show-on-truncate-only>
<template #title>{{ table.label }}</template>
<span>{{ table.label }}</span>
<template #title>{{ delimiter.label }}</template>
<span>{{ delimiter.label }}</span>
</NcTooltip>
<component
:is="iconMap.check"
v-if="exportPayload.tableId === table.value"
v-if="exportPayload.delimiter === delimiter.value"
id="nc-selected-item-icon"
class="flex-none text-primary w-4 h-4"
/>
@ -307,56 +414,6 @@ onMounted(async () => {
</a-select-option>
</NcSelect>
</a-form-item>
<a-form-item
class="!my-0"
:class="{
'flex-1 max-w-[237px]': fullscreen,
'min-w-1/2 max-w-[200px]': !fullscreen,
}"
>
<NcSelect
v-model:value="exportPayload.viewId"
placeholder="-select view-"
:disabled="isExporting"
class="nc-data-exporter-view-select nc-select-shadow"
dropdown-class-name="w-[250px]"
:filter-option="filterOption"
show-search
size="large"
placement="bottomRight"
@change="onViewSelect"
>
<a-select-option v-for="view of viewList" :key="view.label" :value="view.value">
<div class="w-full flex items-center gap-2">
<div class="min-w-5 flex items-center justify-center">
<GeneralViewIcon :meta="{ meta: view.meta, type: view.type }" class="flex-none text-gray-500" />
</div>
<NcTooltip class="flex-1 truncate" show-on-truncate-only>
<template #title>{{ view.label }}</template>
<span>{{ view.label }}</span>
</NcTooltip>
<component
:is="iconMap.check"
v-if="exportPayload.viewId === view.value"
id="nc-selected-item-icon"
class="flex-none text-primary w-4 h-4"
/>
</div> </a-select-option
></NcSelect>
</a-form-item>
</div>
<div class="flex-none flex justify-end">
<NcTooltip class="flex" placement="topRight" :disabled="!isExporting">
<template #title> The CSV file is being prepared in the background. You'll be notified once it's ready. </template>
<NcButton
:disabled="!exportPayload?.viewId || isExporting"
:loading="isExporting"
size="medium"
@click="exportDataAsync"
>{{ isExporting ? 'Generating' : 'Export' }}</NcButton
>
</NcTooltip>
</div>
</div>
<div

Loading…
Cancel
Save