focalboard/webapp/src/csvExporter.ts

87 lines
2.9 KiB
TypeScript
Raw Normal View History

2020-10-20 21:50:53 +02:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IntlShape} from 'react-intl'
2020-10-20 21:52:56 +02:00
import {BoardView} from './blocks/boardView'
2020-10-21 03:54:39 +02:00
import {BoardTree} from './viewModel/boardTree'
2020-10-20 21:52:56 +02:00
import {OctoUtils} from './octoUtils'
import {Utils} from './utils'
2020-10-08 18:21:27 +02:00
class CsvExporter {
static exportTableCsv(boardTree: BoardTree, intl: IntlShape, view?: BoardView): void {
2020-10-20 21:50:53 +02:00
const {activeView} = boardTree
const viewToExport = view ?? activeView
2020-10-08 18:21:27 +02:00
2020-11-12 20:18:19 +01:00
if (!viewToExport) {
return
}
const rows = CsvExporter.generateTableArray(boardTree, viewToExport, intl)
2020-10-08 18:21:27 +02:00
2020-10-20 21:52:56 +02:00
let csvContent = 'data:text/csv;charset=utf-8,'
2020-10-08 18:21:27 +02:00
2020-10-20 21:50:53 +02:00
rows.forEach((row) => {
const encodedRow = row.join(',')
2020-10-20 21:52:56 +02:00
csvContent += encodedRow + '\r\n'
2020-10-20 21:50:53 +02:00
})
2020-10-08 18:21:27 +02:00
2020-11-12 20:18:19 +01:00
const filename = `${Utils.sanitizeFilename(viewToExport.title || 'Untitled')}.csv`
2020-10-20 21:50:53 +02:00
const encodedUri = encodeURI(csvContent)
const link = document.createElement('a')
2020-10-20 21:52:56 +02:00
link.style.display = 'none'
2020-10-20 21:50:53 +02:00
link.setAttribute('href', encodedUri)
link.setAttribute('download', filename)
document.body.appendChild(link) // FireFox support
2020-10-08 18:21:27 +02:00
2020-10-20 21:50:53 +02:00
link.click()
2020-10-08 18:21:27 +02:00
// TODO: Review if this is needed in the future, this is to fix the problem with linux webview links
if ((window as any).openInNewBrowser) {
(window as any).openInNewBrowser(encodedUri)
}
2020-10-20 21:50:53 +02:00
// TODO: Remove or reuse link
}
2020-10-08 18:21:27 +02:00
private static encodeText(text: string): string {
return text.replace(/"/g, '""')
}
private static generateTableArray(boardTree: BoardTree, viewToExport: BoardView, intl: IntlShape): string[][] {
2020-11-12 20:18:19 +01:00
const {board, cards} = boardTree
2020-10-08 18:21:27 +02:00
2020-10-20 21:50:53 +02:00
const rows: string[][] = []
const visibleProperties = board.cardProperties.filter((template) => viewToExport.visiblePropertyIds.includes(template.id))
2020-10-08 18:21:27 +02:00
2020-10-20 21:50:53 +02:00
{
// Header row
const row: string[] = ['Title']
2020-10-20 21:50:53 +02:00
visibleProperties.forEach((template) => {
row.push(template.name)
2020-10-20 21:52:56 +02:00
})
2020-10-20 21:50:53 +02:00
rows.push(row)
}
2020-10-08 18:21:27 +02:00
2020-10-20 21:50:53 +02:00
cards.forEach((card) => {
const row: string[] = []
row.push(`"${this.encodeText(card.title)}"`)
2020-10-20 21:50:53 +02:00
visibleProperties.forEach((template) => {
const propertyValue = card.properties[template.id]
const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, template, intl) || ''
2020-10-20 21:50:53 +02:00
if (template.type === 'number') {
2020-11-12 20:18:19 +01:00
const numericValue = propertyValue ? Number(propertyValue).toString() : ''
2020-10-20 21:50:53 +02:00
row.push(numericValue)
} else {
// Export as string
row.push(`"${this.encodeText(displayValue)}"`)
2020-10-20 21:50:53 +02:00
}
})
rows.push(row)
2020-10-20 21:52:56 +02:00
})
2020-10-08 18:21:27 +02:00
2020-10-20 21:50:53 +02:00
return rows
}
2020-10-08 18:21:27 +02:00
}
2020-10-20 21:50:53 +02:00
export {CsvExporter}