1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-02-13 10:10:36 +01:00

feat: format options of csv export, closes #196

This commit is contained in:
Fabio Di Stasio 2023-06-14 19:47:09 +02:00
parent e07e7b736e
commit 3ad1e51f42
3 changed files with 126 additions and 12 deletions

View File

@ -152,6 +152,77 @@
</div> </div>
</template> </template>
</ConfirmModal> </ConfirmModal>
<ConfirmModal
v-if="csvModalRequest"
@confirm="downloadTable('csv', csvModalRequest as string, true)"
@hide="csvModalRequest = false"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-file-export mr-1" />
<span class="cut-text">{{ t('message.csvExportOptions') }}</span>
</div>
</template>
<template #body>
<div class="columns">
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label cut-text">{{ t('message.csvFieldDelimiter') }}:</label>
</div>
<div class="column col-7">
<input
v-model.number="csvExportOptions.fieldDelimiter"
type="string"
class="form-input"
>
</div>
</div>
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label cut-text">{{ t('message.csvStringDelimiter') }}:</label>
</div>
<div class="column col-7">
<BaseSelect
v-model="csvExportOptions.stringDelimiter"
class="form-select"
:options="[
{value: '', label: t('word.none')},
{value: 'single', label: t('word.singleQuote')},
{value: 'double', label: t('word.doubleQuote')}
]"
/>
</div>
</div>
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label cut-text">{{ t('message.csvLinesTerminator') }}:</label>
</div>
<div class="column col-7">
<textarea
v-model.number="csvExportOptions.linesTerminator"
class="form-input"
:style="'resize: none'"
rows="1"
/>
</div>
</div>
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label">
{{ t('message.csvIncludeHeader') }}
</label>
</div>
<div class="column col-7">
<label class="form-switch d-inline-block" @click.prevent="csvExportOptions.header = !csvExportOptions.header">
<input type="checkbox" :checked="csvExportOptions.header">
<i class="form-icon" />
</label>
</div>
</div>
</div>
</template>
</ConfirmModal>
</div> </div>
</template> </template>
@ -223,11 +294,18 @@ const rowHeight = ref(23);
const selectedField = ref(null); const selectedField = ref(null);
const isEditingRow = ref(false); const isEditingRow = ref(false);
const chunkModalRequest: Ref<false | string> = ref(false); const chunkModalRequest: Ref<false | string> = ref(false);
const csvModalRequest: Ref<false | string> = ref(false);
const sqlExportOptions = ref({ const sqlExportOptions = ref({
sqlInsertAfter: 250, sqlInsertAfter: 250,
sqlInsertDivider: 'bytes' as 'bytes' | 'rows', sqlInsertDivider: 'bytes' as 'bytes' | 'rows',
targetTable: '' targetTable: ''
}); });
const csvExportOptions = ref({
header: true,
fieldDelimiter: ';',
linesTerminator: '\n',
stringDelimiter: 'double'
});
const workspaceSchema = computed(() => getWorkspace(props.connUid).breadcrumbs.schema); const workspaceSchema = computed(() => getWorkspace(props.connUid).breadcrumbs.schema);
const workspaceClient = computed(() => getWorkspace(props.connUid).client); const workspaceClient = computed(() => getWorkspace(props.connUid).client);
@ -718,10 +796,10 @@ const selectResultset = (index: number) => {
resultsetIndex.value = index; resultsetIndex.value = index;
}; };
const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, chunks = false) => { const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, popup = false) => {
if (!sortedResults.value) return; if (!sortedResults.value) return;
if (format === 'sql' && !chunks && customizations.value.exportByChunks) { if (format === 'sql' && !popup && customizations.value.exportByChunks) {
sqlExportOptions.value = { sqlExportOptions.value = {
sqlInsertAfter: 250, sqlInsertAfter: 250,
sqlInsertDivider: 'bytes' as 'bytes' | 'rows', sqlInsertDivider: 'bytes' as 'bytes' | 'rows',
@ -730,8 +808,20 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, ch
chunkModalRequest.value = table; chunkModalRequest.value = table;
return; return;
} }
else else if (format === 'csv' && !popup) {
csvExportOptions.value = {
header: true,
fieldDelimiter: ';',
linesTerminator: '\\n',
stringDelimiter: 'double'
};
csvModalRequest.value = table;
return;
}
else {
chunkModalRequest.value = false; chunkModalRequest.value = false;
csvModalRequest.value = false;
}
const rows = sortedResults.value.map((row: any) => { const rows = sortedResults.value.map((row: any) => {
const clonedRow = { ...row }; const clonedRow = { ...row };
@ -747,7 +837,8 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, ch
}, },
client: workspaceClient.value, client: workspaceClient.value,
table, table,
sqlOptions: chunks ? { ...sqlExportOptions.value }: null sqlOptions: popup ? { ...sqlExportOptions.value }: null,
csvOptions: popup ? { ...csvExportOptions.value }: null
}); });
}; };

View File

@ -150,7 +150,10 @@ export const enUS = {
label: 'Label', label: 'Label',
icon: 'Icon', icon: 'Icon',
resultsTable: 'Results table', resultsTable: 'Results table',
ddl: 'DDL' ddl: 'DDL',
none: 'None',
singleQuote: 'Single quote',
doubleQuote: 'Double quote'
}, },
message: { message: {
appWelcome: 'Welcome to Antares SQL Client!', appWelcome: 'Welcome to Antares SQL Client!',
@ -349,7 +352,12 @@ export const enUS = {
closeOtherTabs: 'Close other tabs', closeOtherTabs: 'Close other tabs',
closeTabsToLeft: 'Close tabs to the left', closeTabsToLeft: 'Close tabs to the left',
closeTabsToRight: 'Close tabs to the right', closeTabsToRight: 'Close tabs to the right',
switchDatabase: 'Switch the database' switchDatabase: 'Switch the database',
csvExportOptions: 'CSV export options',
csvFieldDelimiter: 'Field delimiter',
csvLinesTerminator: 'Line terminator',
csvStringDelimiter: 'String delimiter',
csvIncludeHeader: 'Include header'
}, },
faker: { faker: {
address: 'Address', address: 'Address',

View File

@ -10,7 +10,17 @@ export const exportRows = (args: {
fields?: { fields?: {
[key: string]: {type: string; datePrecision: number}; [key: string]: {type: string; datePrecision: number};
}; };
sqlOptions?: {sqlInsertAfter: number; sqlInsertDivider: 'bytes' | 'rows'; targetTable: string}; sqlOptions?: {
sqlInsertAfter: number;
sqlInsertDivider: 'bytes' | 'rows';
targetTable: string;
};
csvOptions?: {
header: boolean;
fieldDelimiter: string;
linesTerminator: string;
stringDelimiter: string;
};
}) => { }) => {
let mime; let mime;
let content; let content;
@ -19,20 +29,25 @@ export const exportRows = (args: {
case 'csv': { case 'csv': {
mime = 'text/csv'; mime = 'text/csv';
const csv = []; const csv = [];
const sd = args.csvOptions.stringDelimiter === 'single'
? '\''
: args.csvOptions.stringDelimiter === 'single'
? '"'
: '';
if (args.content.length) if (args.content.length && args.csvOptions.header)
csv.push(Object.keys(args.content[0]).join(';')); csv.push(Object.keys(args.content[0]).join(args.csvOptions.fieldDelimiter));
for (const row of args.content) { for (const row of args.content) {
csv.push(Object.values(row).map(col => { csv.push(Object.values(row).map(col => {
if (typeof col === 'string') return `"${col}"`; if (typeof col === 'string') return `${sd}${col}${sd}`;
if (col instanceof Buffer) return col.toString('base64'); if (col instanceof Buffer) return col.toString('base64');
if (col instanceof Uint8Array) return Buffer.from(col).toString('base64'); if (col instanceof Uint8Array) return Buffer.from(col).toString('base64');
return col; return col;
}).join(';')); }).join(args.csvOptions.fieldDelimiter));
} }
content = csv.join('\n'); content = csv.join(args.csvOptions.linesTerminator.replaceAll('\\n', '\n').replaceAll('\\r', '\r'));
break; break;
} }
case 'sql': { case 'sql': {