// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import * as fs from 'fs' import minimist from 'minimist' import {exit} from 'process' import {ArchiveUtils} from '../util/archive' import {Block} from '../../webapp/src/blocks/block' import {IPropertyOption, IPropertyTemplate, createBoard} from '../../webapp/src/blocks/board' import {createBoardView} from '../../webapp/src/blocks/boardView' import {createCard} from '../../webapp/src/blocks/card' import {createTextBlock} from '../../webapp/src/blocks/textBlock' import {createCheckboxBlock} from '../../webapp/src/blocks/checkboxBlock' import {Trello} from './trello' import {Utils} from './utils' // HACKHACK: To allow Utils.CreateGuid to work (global.window as any) = {} const optionColors = [ // 'propColorDefault', 'propColorGray', 'propColorBrown', 'propColorOrange', 'propColorYellow', 'propColorGreen', 'propColorBlue', 'propColorPurple', 'propColorPink', 'propColorRed', ] let optionColorIndex = 0 function main() { const args: minimist.ParsedArgs = minimist(process.argv.slice(2)) const inputFile = args['i'] const outputFile = args['o'] || 'archive.focalboard' if (!inputFile) { showHelp() } if (!fs.existsSync(inputFile)) { console.error(`File not found: ${inputFile}`) exit(2) } // Read input const inputData = fs.readFileSync(inputFile, 'utf-8') const input = JSON.parse(inputData) as Trello // Convert const blocks = convert(input) // Save output // TODO: Stream output const outputData = ArchiveUtils.buildBlockArchive(blocks) fs.writeFileSync(outputFile, outputData) console.log(`Exported to ${outputFile}`) } function convert(input: Trello): Block[] { const blocks: Block[] = [] // Board const board = createBoard() console.log(`Board: ${input.name}`) board.rootId = board.id board.title = input.name board.fields.description = input.desc // Convert lists (columns) to a Select property const optionIdMap = new Map() const options: IPropertyOption[] = [] input.lists.forEach(list => { const optionId = Utils.createGuid() optionIdMap.set(list.id, optionId) const color = optionColors[optionColorIndex % optionColors.length] optionColorIndex += 1 const option: IPropertyOption = { id: optionId, value: list.name, color, } options.push(option) }) const cardProperty: IPropertyTemplate = { id: Utils.createGuid(), name: 'List', type: 'select', options } board.fields.cardProperties = [cardProperty] blocks.push(board) // Board view const view = createBoardView() view.title = 'Board View' view.fields.viewType = 'board' view.rootId = board.id view.parentId = board.id blocks.push(view) // Cards input.cards.forEach(card => { console.log(`Card: ${card.name}`) const outCard = createCard() outCard.title = card.name outCard.rootId = board.id outCard.parentId = board.id // Map lists to Select property options if (card.idList) { const optionId = optionIdMap.get(card.idList) if (optionId) { outCard.fields.properties[cardProperty.id] = optionId } else { console.warn(`Invalid idList: ${card.idList} for card: ${card.name}`) } } else { console.warn(`Missing idList for card: ${card.name}`) } blocks.push(outCard) if (card.desc) { // console.log(`\t${card.desc}`) const text = createTextBlock() text.title = card.desc text.rootId = board.id text.parentId = outCard.id blocks.push(text) outCard.fields.contentOrder = [text.id] } // Add Checklists if (card.idChecklists && card.idChecklists.length > 0) { card.idChecklists.forEach(checklistID => { const lookup = input.checklists.find(e => e.id === checklistID) if (lookup) { lookup.checkItems.forEach(trelloCheckBox=> { const checkBlock = createCheckboxBlock() checkBlock.title = trelloCheckBox.name if (trelloCheckBox.state === 'complete') { checkBlock.fields.value = true } else { checkBlock.fields.value = false } checkBlock.rootId = outCard.rootId checkBlock.parentId = outCard.id blocks.push(checkBlock) outCard.fields.contentOrder.push(checkBlock.id) }) } }) } }) console.log('') console.log(`Found ${input.cards.length} card(s).`) return blocks } function showHelp() { console.log('import -i -o [output.focalboard]') exit(1) } main()