mirror of
				https://github.com/Fabio286/antares.git
				synced 2025-06-05 21:59:22 +02:00 
			
		
		
		
	feat: format options of csv export, closes #196
This commit is contained in:
		| @@ -152,6 +152,77 @@ | ||||
|             </div> | ||||
|          </template> | ||||
|       </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> | ||||
| </template> | ||||
|  | ||||
| @@ -223,11 +294,18 @@ const rowHeight = ref(23); | ||||
| const selectedField = ref(null); | ||||
| const isEditingRow = ref(false); | ||||
| const chunkModalRequest: Ref<false | string> = ref(false); | ||||
| const csvModalRequest: Ref<false | string> = ref(false); | ||||
| const sqlExportOptions = ref({ | ||||
|    sqlInsertAfter: 250, | ||||
|    sqlInsertDivider: 'bytes' as 'bytes' | 'rows', | ||||
|    targetTable: '' | ||||
| }); | ||||
| const csvExportOptions = ref({ | ||||
|    header: true, | ||||
|    fieldDelimiter: ';', | ||||
|    linesTerminator: '\n', | ||||
|    stringDelimiter: 'double' | ||||
| }); | ||||
|  | ||||
| const workspaceSchema = computed(() => getWorkspace(props.connUid).breadcrumbs.schema); | ||||
| const workspaceClient = computed(() => getWorkspace(props.connUid).client); | ||||
| @@ -718,10 +796,10 @@ const selectResultset = (index: number) => { | ||||
|    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 (format === 'sql' && !chunks && customizations.value.exportByChunks) { | ||||
|    if (format === 'sql' && !popup && customizations.value.exportByChunks) { | ||||
|       sqlExportOptions.value = { | ||||
|          sqlInsertAfter: 250, | ||||
|          sqlInsertDivider: 'bytes' as 'bytes' | 'rows', | ||||
| @@ -730,8 +808,20 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, ch | ||||
|       chunkModalRequest.value = table; | ||||
|       return; | ||||
|    } | ||||
|    else | ||||
|    else if (format === 'csv' && !popup) { | ||||
|       csvExportOptions.value = { | ||||
|          header: true, | ||||
|          fieldDelimiter: ';', | ||||
|          linesTerminator: '\\n', | ||||
|          stringDelimiter: 'double' | ||||
|       }; | ||||
|       csvModalRequest.value = table; | ||||
|       return; | ||||
|    } | ||||
|    else { | ||||
|       chunkModalRequest.value = false; | ||||
|       csvModalRequest.value = false; | ||||
|    } | ||||
|  | ||||
|    const rows = sortedResults.value.map((row: any) => { | ||||
|       const clonedRow = { ...row }; | ||||
| @@ -747,7 +837,8 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, ch | ||||
|       }, | ||||
|       client: workspaceClient.value, | ||||
|       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', | ||||
|       icon: 'Icon', | ||||
|       resultsTable: 'Results table', | ||||
|       ddl: 'DDL' | ||||
|       ddl: 'DDL', | ||||
|       none: 'None', | ||||
|       singleQuote: 'Single quote', | ||||
|       doubleQuote: 'Double quote' | ||||
|    }, | ||||
|    message: { | ||||
|       appWelcome: 'Welcome to Antares SQL Client!', | ||||
| @@ -349,7 +352,12 @@ export const enUS = { | ||||
|       closeOtherTabs: 'Close other tabs', | ||||
|       closeTabsToLeft: 'Close tabs to the left', | ||||
|       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: { | ||||
|       address: 'Address', | ||||
|   | ||||
| @@ -10,7 +10,17 @@ export const exportRows = (args: { | ||||
|    fields?: { | ||||
|       [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 content; | ||||
| @@ -19,20 +29,25 @@ export const exportRows = (args: { | ||||
|       case 'csv': { | ||||
|          mime = 'text/csv'; | ||||
|          const csv = []; | ||||
|          const sd = args.csvOptions.stringDelimiter === 'single' | ||||
|             ? '\'' | ||||
|             : args.csvOptions.stringDelimiter === 'single' | ||||
|                ? '"' | ||||
|                : ''; | ||||
|  | ||||
|          if (args.content.length) | ||||
|             csv.push(Object.keys(args.content[0]).join(';')); | ||||
|          if (args.content.length && args.csvOptions.header) | ||||
|             csv.push(Object.keys(args.content[0]).join(args.csvOptions.fieldDelimiter)); | ||||
|  | ||||
|          for (const row of args.content) { | ||||
|             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 Uint8Array) return Buffer.from(col).toString('base64'); | ||||
|                return col; | ||||
|             }).join(';')); | ||||
|             }).join(args.csvOptions.fieldDelimiter)); | ||||
|          } | ||||
|  | ||||
|          content = csv.join('\n'); | ||||
|          content = csv.join(args.csvOptions.linesTerminator.replaceAll('\\n', '\n').replaceAll('\\r', '\r')); | ||||
|          break; | ||||
|       } | ||||
|       case 'sql': { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user