import * as fs from 'fs' ; import minimist from 'minimist' ; import { exit } from 'process' ; import { ArchiveUtils } from '../../webapp/src/blocks/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 { Item , Project , Section , Todoist } from './todoist' ; import { Utils } from './utils' ; ( global . window as any ) = { } ; const optionColors = [ 'propColorGray' , 'propColorBrown' , 'propColorOrange' , 'propColorYellow' , 'propColorGreen' , 'propColorBlue' , 'propColorPurple' , 'propColorPink' , 'propColorRed' , ] ; const defaultSections = [ 'No Status' , 'Next Up' , 'In Progress' , 'Completed' , 'Archived' ] . map ( title => { return { id : Utils . createGuid ( ) , name : title , } as Section ; } ) ; let noStatusSectionID ; let optionColorIndex = 0 ; function main ( ) { const args = 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 ) ; } const inputData = fs . readFileSync ( inputFile , 'utf-8' ) ; const input = JSON . parse ( inputData ) as Todoist ; const blocks = [ ] as Block [ ] ; input . projects . forEach ( project => { blocks . push ( ... convert ( input , project ) ) ; } ) ; const outputData = ArchiveUtils . buildBlockArchive ( blocks ) ; fs . writeFileSync ( outputFile , outputData ) ; console . log ( `Exported to ${ outputFile }` ) ; } function convert ( input , project ) { const blocks = [ ] ; if ( project . name === 'Inbox' ) { return blocks ; } const board = createBoard ( ) ; console . log ( `Board: ${ project . name }` ) ; board . rootId = board . id ; board . title = project . name ; board . fields . description = project . name ; const optionIdMap = new Map < string , string > ( ) ; const options = [ ] ; const columns = getProjectColumns ( input , project ) ; console . log ( "columns: " + JSON . stringify ( columns ) ) ; columns . forEach ( list => { const optionId = Utils . createGuid ( ) ; if ( list . name === 'No Status' ) { noStatusSectionID = list . id ; } optionIdMap . set ( String ( list . id ) , optionId ) ; const color = optionColors [ optionColorIndex % optionColors . length ] ; optionColorIndex += 1 ; const option = { id : optionId , value : list . name , color , } ; options . push ( option ) ; } ) ; const cardProperty = { id : Utils . createGuid ( ) , name : 'List' , type : 'select' , options } ; board . fields . cardProperties = [ cardProperty ] ; blocks . push ( board ) ; const view = createBoardView ( ) ; view . title = 'Board View' ; view . fields . viewType = 'board' ; view . rootId = board . id ; view . parentId = board . id ; blocks . push ( view ) ; const cards = getProjectCards ( input , project ) ; cards . forEach ( card => { const outCard = createCard ( ) ; outCard . title = card . content ; outCard . rootId = board . id ; outCard . parentId = board . id ; const cardSectionId = card . section_id ? card . section_id : noStatusSectionID ; const optionId = optionIdMap . get ( String ( cardSectionId ) ) ; if ( optionId ) { outCard . fields . properties [ cardProperty . id ] = optionId ; } else { console . warn ( `Invalid idList: ${ cardSectionId } for card: ${ card . content }` ) ; } blocks . push ( outCard ) ; const text = createTextBlock ( ) ; text . title = getCardDescription ( input , card ) . join ( '\n\n' ) ; text . rootId = board . id ; text . parentId = outCard . id ; blocks . push ( text ) ; outCard . fields . contentOrder = [ text . id ] ; } ) ; return blocks ; } function getProjectColumns ( input , project ) { const sections = [ { id : noStatusSectionID , name : 'No Section' , } as Section ] ; sections . push ( ... input . sections . filter ( section => section . project_id === project . id ) ) ; return sections . length > 1 ? sections : defaultSections ; } function getProjectCards ( input , project ) { return input . items . filter ( item => item . project_id === project . id ) ; } function getCardDescription ( input , item ) { return input . notes . filter ( note => note . item_id === item . id ) . map ( item => { let description = "" ; if ( item . content ) { description = item . content ; } if ( item . file_attachment ) { description += `\n\nAttachment: [${ item . file_attachment . title }](${ item . file_attachment . url })` ; } return description ; } ) ; } function showHelp ( ) { exit ( 1 ) ; } main ( ) ;