focalboard/webapp/src/archiver.ts
Jesús Espino be28b7dad5
Migrate webapp global state to redux (#737)
* Migrating workspace tree to redux

* More changes for use the redux store for boads and views

* Taking into account the templates on websocket event updates

* Fixing bug on boardTree maintenance

* Websocket client now connects once and subscribe/desubscribe on the fly

* Including usage of the new websocket client

* More work around migrating to redux

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Fixing some things

* WIP

* WIP

* Another small fix

* Restoring filtering, sorting and grouping

* Fixing some other bugs

* Add search text reducer

* Fixing another drag and drop problem

* Improve store names and api

* Fixing small bgus

* Some small fixes

* fixing login

* Fixing register page

* Some other improvements

* Removing unneeded old files

* Removing the need of userCache

* Fixing comments and fixing content ordering

* Fixing sort

* Fixing some TODOs

* Fixing tests

* Fixing snapshot

* Fixing cypress tests

* Fix eslint

* Fixing server tests

* Updating the add cards actions

* Fixing some tiny navigation problems

* Mocking the api calls to pass the tests

* Migrating a new test to redux

* Adding the card right after the insert of the block (not wait for ws event)

* Showing the ws disconnect banner only after 5 seconds of disconnection

* Fixing share view

* Fix eslint

* Fixing problem with sort/groupby modifications

* Fixing some details on redirections and templates creation

* Fixing small bugs around undo

* Fix update properties on click outside the dialog

* Improving the column resize look and feel

* Removing the class based objects from the store (now they are all plain objects

* Fix eslint

* Fixing tests

* Removing unneeded code
2021-08-02 17:46:00 +02:00

127 lines
4.4 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ArchiveUtils, ArchiveHeader, ArchiveLine, BlockArchiveLine} from './blocks/archive'
import {Block} from './blocks/block'
import {Board} from './blocks/board'
import {LineReader} from './lineReader'
import mutator from './mutator'
import {Utils} from './utils'
class Archiver {
static async exportBoardArchive(board: Board): Promise<void> {
const blocks = await mutator.exportArchive(board.id)
this.exportArchive(blocks)
}
static async exportFullArchive(): Promise<void> {
const blocks = await mutator.exportArchive()
this.exportArchive(blocks)
}
private static exportArchive(blocks: readonly Block[]): void {
const content = ArchiveUtils.buildBlockArchive(blocks)
const date = new Date()
const filename = `archive-${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}.focalboard`
const link = document.createElement('a')
link.style.display = 'none'
// const file = new Blob([content], { type: "text/json" })
// link.href = URL.createObjectURL(file)
link.href = 'data:text/json,' + encodeURIComponent(content)
link.download = filename
document.body.appendChild(link) // FireFox support
link.click()
// 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(link.href)
}
// TODO: Remove or reuse link
}
private static async importBlocksFromFile(file: File): Promise<void> {
let blockCount = 0
const maxBlocksPerImport = 1000
let blocks: Block[] = []
let isFirstLine = true
return new Promise<void>((resolve) => {
LineReader.readFile(file, async (line, completed) => {
if (completed) {
if (blocks.length > 0) {
await mutator.importFullArchive(blocks)
blockCount += blocks.length
}
Utils.log(`Imported ${blockCount} blocks.`)
resolve()
return
}
if (isFirstLine) {
isFirstLine = false
const header = JSON.parse(line) as ArchiveHeader
if (header.date && header.version >= 1) {
const date = new Date(header.date)
Utils.log(`Import archive, version: ${header.version}, date/time: ${date.toLocaleString()}.`)
}
} else {
const row = JSON.parse(line) as ArchiveLine
if (!row || !row.type || !row.data) {
Utils.logError('importFullArchive ERROR parsing line')
return
}
switch (row.type) {
case 'block': {
const blockLine = row as BlockArchiveLine
const block = blockLine.data
if (Archiver.isValidBlock(block)) {
blocks.push(block)
if (blocks.length >= maxBlocksPerImport) {
const blocksToSend = blocks
blocks = []
await mutator.importFullArchive(blocksToSend)
blockCount += blocksToSend.length
}
}
break
}
}
}
})
})
}
static isValidBlock(block: Block): boolean {
if (!block.id || !block.rootId) {
return false
}
return true
}
static importFullArchive(onComplete?: () => void): void {
const input = document.createElement('input')
input.type = 'file'
input.accept = '.focalboard'
input.onchange = async () => {
const file = input.files && input.files[0]
if (file) {
await Archiver.importBlocksFromFile(file)
}
onComplete?.()
}
input.style.display = 'none'
document.body.appendChild(input)
input.click()
// TODO: Remove or reuse input
}
}
export {Archiver}