|
|
@ -7,6 +7,25 @@ const jobStatusTooltip = { |
|
|
|
[JobStatus.FAILED]: 'Export failed', |
|
|
|
[JobStatus.FAILED]: 'Export failed', |
|
|
|
} as Record<string, string> |
|
|
|
} 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 { $api, $poller } = useNuxtApp() |
|
|
|
|
|
|
|
|
|
|
|
const { appInfo } = useGlobal() |
|
|
|
const { appInfo } = useGlobal() |
|
|
@ -60,7 +79,10 @@ const exportedFiles = computed(() => { |
|
|
|
const exportPayload = ref<{ |
|
|
|
const exportPayload = ref<{ |
|
|
|
tableId?: string |
|
|
|
tableId?: string |
|
|
|
viewId?: string |
|
|
|
viewId?: string |
|
|
|
}>({}) |
|
|
|
delimiter?: string |
|
|
|
|
|
|
|
}>({ |
|
|
|
|
|
|
|
delimiter: ',', |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const tableList = computed(() => { |
|
|
|
const tableList = computed(() => { |
|
|
|
return tables.value.map((table) => { |
|
|
|
return tables.value.map((table) => { |
|
|
@ -123,7 +145,10 @@ async function exportDataAsync() { |
|
|
|
|
|
|
|
|
|
|
|
isExporting.value = true |
|
|
|
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) |
|
|
|
jobList.value.unshift(jobData) |
|
|
|
|
|
|
|
|
|
|
|
$poller.subscribe( |
|
|
|
$poller.subscribe( |
|
|
@ -255,51 +280,133 @@ onMounted(async () => { |
|
|
|
'bg-nc-bg-gray-extralight': fullscreen, |
|
|
|
'bg-nc-bg-gray-extralight': fullscreen, |
|
|
|
}" |
|
|
|
}" |
|
|
|
> |
|
|
|
> |
|
|
|
<div |
|
|
|
<div class="p-3 flex flex-col gap-2"> |
|
|
|
class="p-3 flex items-center justify-between gap-2.5 flex-wrap" |
|
|
|
|
|
|
|
:class="{ |
|
|
|
|
|
|
|
'bg-white': fullscreen, |
|
|
|
|
|
|
|
}" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<div |
|
|
|
<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="{ |
|
|
|
:class="{ |
|
|
|
'max-w-[min(400px,calc(100%-131px))]': isExporting && !fullscreen && width > 425, |
|
|
|
'bg-white': fullscreen, |
|
|
|
'max-w-[min(400px,calc(100%_-_87px))]': !isExporting && !fullscreen && width > 425, |
|
|
|
|
|
|
|
'max-w-full': width <= 425, |
|
|
|
|
|
|
|
'max-w-[474px]': fullscreen, |
|
|
|
|
|
|
|
}" |
|
|
|
}" |
|
|
|
> |
|
|
|
> |
|
|
|
<a-form-item |
|
|
|
<div |
|
|
|
class="!my-0" |
|
|
|
class="nc-data-exporter-select-wrapper flex-1 flex items-center border-1 border-nc-border-gray-medium rounded-lg relative shadow-default" |
|
|
|
:class="{ |
|
|
|
:class="{ |
|
|
|
'flex-1 max-w-[237px]': fullscreen, |
|
|
|
'max-w-[min(400px,calc(100%-131px))]': isExporting && !fullscreen && width > 425, |
|
|
|
'min-w-1/2 max-w-[200px]': !fullscreen, |
|
|
|
'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 |
|
|
|
<NcSelect |
|
|
|
v-model:value="exportPayload.tableId" |
|
|
|
v-model:value="exportPayload.delimiter" |
|
|
|
placeholder="-select table-" |
|
|
|
placeholder="-select separator-" |
|
|
|
:disabled="isExporting" |
|
|
|
:disabled="isExporting" |
|
|
|
class="nc-data-exporter-table-select nc-select-shadow" |
|
|
|
class="nc-data-exporter-separator nc-select-shadow" |
|
|
|
:filter-option="filterOption" |
|
|
|
:filter-option="filterOption" |
|
|
|
dropdown-class-name="w-[250px]" |
|
|
|
dropdown-class-name="w-[250px]" |
|
|
|
show-search |
|
|
|
show-search |
|
|
|
size="large" |
|
|
|
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="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> |
|
|
|
<NcTooltip class="flex-1 truncate" show-on-truncate-only> |
|
|
|
<template #title>{{ table.label }}</template> |
|
|
|
<template #title>{{ delimiter.label }}</template> |
|
|
|
<span>{{ table.label }}</span> |
|
|
|
<span>{{ delimiter.label }}</span> |
|
|
|
</NcTooltip> |
|
|
|
</NcTooltip> |
|
|
|
<component |
|
|
|
<component |
|
|
|
:is="iconMap.check" |
|
|
|
:is="iconMap.check" |
|
|
|
v-if="exportPayload.tableId === table.value" |
|
|
|
v-if="exportPayload.delimiter === delimiter.value" |
|
|
|
id="nc-selected-item-icon" |
|
|
|
id="nc-selected-item-icon" |
|
|
|
class="flex-none text-primary w-4 h-4" |
|
|
|
class="flex-none text-primary w-4 h-4" |
|
|
|
/> |
|
|
|
/> |
|
|
@ -307,56 +414,6 @@ onMounted(async () => { |
|
|
|
</a-select-option> |
|
|
|
</a-select-option> |
|
|
|
</NcSelect> |
|
|
|
</NcSelect> |
|
|
|
</a-form-item> |
|
|
|
</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> |
|
|
|
</div> |
|
|
|
<div |
|
|
|
<div |
|
|
|