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:
parent
e07e7b736e
commit
3ad1e51f42
@ -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
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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',
|
||||||
|
@ -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': {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user