Support ODS, XLS, and other spreadsheet formats in the attachment editor.
Detect editable attachments by extension and write back in the original book type instead of always forcing xlsx. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+2
-5
@@ -4,6 +4,7 @@
|
||||
import { parseRoute, buildHash, currentHash } from './lib/route.js'
|
||||
import MarkdownEditor from './lib/MarkdownEditor.svelte'
|
||||
import ExcelEditor from './lib/ExcelEditor.svelte'
|
||||
import { isSpreadsheetName } from './lib/spreadsheet.js'
|
||||
|
||||
let user = $state(null)
|
||||
let loading = $state(true)
|
||||
@@ -398,10 +399,6 @@
|
||||
return `${(n / (1024 * 1024)).toFixed(1)} MB`
|
||||
}
|
||||
|
||||
function isExcelName(name) {
|
||||
return /\.xlsx$/i.test(name || '')
|
||||
}
|
||||
|
||||
async function onAttachFile(e) {
|
||||
const file = e.target?.files?.[0]
|
||||
e.target.value = ''
|
||||
@@ -963,7 +960,7 @@
|
||||
<span class="muted">{formatBytes(a.sizeBytes)}</span>
|
||||
</div>
|
||||
<div class="row" style="width: auto; justify-content: flex-end;">
|
||||
{#if isExcelName(a.filename)}
|
||||
{#if isSpreadsheetName(a.filename)}
|
||||
<button class="primary" onclick={() => (excelAtt = a)}>Edit</button>
|
||||
{/if}
|
||||
<a
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script>
|
||||
import { api } from './api.js'
|
||||
import { spreadsheetWriteOptions } from './spreadsheet.js'
|
||||
|
||||
let {
|
||||
projectId,
|
||||
@@ -87,11 +88,9 @@
|
||||
try {
|
||||
await ensureXlsx()
|
||||
workbook.Sheets[activeSheet] = gridToSheet(grid)
|
||||
const out = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' })
|
||||
await api.putAttachment(projectId, ticketId, attachment.id, out, {
|
||||
contentType:
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
})
|
||||
const { bookType, contentType } = spreadsheetWriteOptions(attachment.filename)
|
||||
const out = XLSX.write(workbook, { bookType, type: 'array' })
|
||||
await api.putAttachment(projectId, ticketId, attachment.id, out, { contentType })
|
||||
onsaved()
|
||||
msgOk()
|
||||
} catch (e) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/** Extensions SheetJS can read/write for simple cell editing. */
|
||||
const FORMATS = {
|
||||
xlsx: {
|
||||
bookType: 'xlsx',
|
||||
contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
},
|
||||
xlsm: {
|
||||
bookType: 'xlsm',
|
||||
contentType: 'application/vnd.ms-excel.sheet.macroEnabled.12',
|
||||
},
|
||||
xlsb: {
|
||||
bookType: 'xlsb',
|
||||
contentType: 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||
},
|
||||
xls: {
|
||||
bookType: 'xls',
|
||||
contentType: 'application/vnd.ms-excel',
|
||||
},
|
||||
ods: {
|
||||
bookType: 'ods',
|
||||
contentType: 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
},
|
||||
fods: {
|
||||
bookType: 'fods',
|
||||
contentType: 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
},
|
||||
csv: {
|
||||
bookType: 'csv',
|
||||
contentType: 'text/csv',
|
||||
},
|
||||
}
|
||||
|
||||
const EXT_RE = /\.([a-z0-9]+)$/i
|
||||
|
||||
export function isSpreadsheetName(name) {
|
||||
const m = String(name || '').match(EXT_RE)
|
||||
if (!m) return false
|
||||
return Object.prototype.hasOwnProperty.call(FORMATS, m[1].toLowerCase())
|
||||
}
|
||||
|
||||
export function spreadsheetWriteOptions(filename) {
|
||||
const m = String(filename || '').match(EXT_RE)
|
||||
const ext = m ? m[1].toLowerCase() : 'xlsx'
|
||||
return FORMATS[ext] || FORMATS.xlsx
|
||||
}
|
||||
Reference in New Issue
Block a user