Skip to content

Instantly share code, notes, and snippets.

@nsrCodes
Last active June 11, 2021 17:27
Show Gist options
  • Save nsrCodes/8e37ba510d55dba2265909cd38040f37 to your computer and use it in GitHub Desktop.
Save nsrCodes/8e37ba510d55dba2265909cd38040f37 to your computer and use it in GitHub Desktop.
If you have ever exported data from trello, you know that it is the worst structured json that you will ever see. I was trying to make sense from all that data while shifting from trello to github discussions but this is the overall structuring result complete
# Actual structure
*Important parts*
{
id,
name,
desc,
cards {
id,
name,
desc, // description
idList,
idCheckLists, // if any
idMembers,
url,
attachments { // if exists... else empty
// array of attachments
date, // Date()
mimeType,
name,
url, // openToAll
fileName,
id,
isUploaded // idk, just felt important
},
labels: {
// array of labels applied to card
id,
name,
color
}
},
checklists {
// array of check lists
id,
idCard,
name,
checkItems { // array of items of checklist
state, // complete or incomplete
name,
}
},
actions { // comments
// array of actions like add members, update cards, etc
id,
data {
text,
type, // we are looking for commentCard
date, // Date()
card {
id
},
list {
id,
name,
},
},
memberCreator {
username,
fullName
}
},
lists {
id,
name,
closed, // true or false,
},
labels { // Labels i the board
id,
name,
color
},
members {
// array of members on the board
id,
bio
fullName,
username,
url
}
}
# Rewamped structure
*First Draft*
[ ] figure out whether as issue or notes, currently for preparing as issue
[ ] Might have problems with attachments in comments
## Issue draft
**Title**
<description>
> auto generated issue while importing
*description text*
---
**checklists**
**attachments**
---
by *author*
url *trello url*
</description>
{
Board : {
info : {
id,
name,
members: [],
labels: [],
},
data : {
lists : {
info: {
id,
name,
closed,
}
cards : {
raw_data: {
id,
name, // title
desc, // description
labels,
attachments,
checkLists: [] // from idCheckLists
members, // participants
comments,
otherActions: // array of actions of other types
}
info : {
ids: {
id,
idList,
idCheckLists,
idMembers,
},
url,
},
data : {
title,
description,
// make sure to keep this as the top most comment
// include attachments and checklists in this as markup
// include data of creator and link to original ticket
comments: [] // array in order
issue_info: {
labels,
participants
}
}
}
}
}
}
}
```javascript
let card = {
raw_data: {
id: "",
name: "", // title
desc: "", // description
labels: [],
attachments: [],
checkLists: [], // from idCheckLists
members: [], // participants
comments: [],
otherActions: [],// array of actions of other types
},
info : {
ids: {
id: "",
idList: "",
idCheckLists: "",
idMembers: "",
},
url: "",
},
data : {
title: "",
// make sure to keep this as the top most comment
// include attachments and checklists in this as markup
// include data of creator and link to original ticket
description : "",
comments: [], // array in order
issueInfo: {
labels: [],
participants: []
}
}
}
```
const fs = require('fs');
const path = require('path');
const store = true
// const dir = `./${Date.now()}`;
const dir = "doingAgain"
if (store && !fs.existsSync(dir))
fs.mkdirSync(dir)
const rawData = fs.readFileSync('trello.json');
const importedTrelloData = JSON.parse(rawData);
const storeData = (data, name) => {
try {
if (store)
fs.writeFileSync(path.join(dir, name), JSON.stringify(data))
} catch (err) {
console.error(err)
}
}
// Create markdown description from collected data
const getDescription = (data, ticketURL) => {
// return data.desc
let final, start, main, checkList, attachments, end;
start = `> This is an auto generated issue made during migration from trello`
main = `\n ${data.desc} \n --- \n`
end = `\n *trello ticket url - ${ticketURL}* \n`
// Checklist string
if (data.checkLists.length > 0) {
for(let list of data.checkLists) {
let listString = `### CheckList - ${list.name} \n`
// Writing each list item as markdown
for (const item of list.checkItems) {
listString += `[${(item.state=="complete")?"X":" "}] ${item.name} \n`
}
checkList += listString + "\n";
}
checkList += "\n --- \n"
} else checkList = ""
// Attachment string
if (data.attachments.length > 0) {
attachments += "### Attachments \n"
for( let item of data.attachments ){
attachments += `![${item.name}](${item.url}) \n`
}
attachments += "\n\n --- \n"
} else attachments = ""
final = start + main + checkList + attachments + end;
return final
}
const getMembers = () => {
let rawData = importedTrelloData.members;
let data = []
for (let i=0; i < rawData.length; i++) {
data[i] = {
id: rawData[i].id,
bio: rawData[i].bio,
fullName: rawData[i].fullName,
username: rawData[i].username,
url: rawData[i].url,
}
}
return data;
}
const getLabels = () => {
let rawData = importedTrelloData.labels;
let data = []
for (let i=0; i < rawData.length; i++) {
data[i] = {
id: rawData[i].id,
color: rawData[i].color,
name: rawData[i].name,
}
}
return data;
}
const getOrganizedListData = () => {
let rawListsData = {};
let rawCardsData = importedTrelloData.cards;
let rawCheckListsData = importedTrelloData.checklists;
let rawActionsData = importedTrelloData.actions;
let cards = {};
//
for (const rawCard of rawCardsData) {
let card = {
raw_data: {
id: rawCard.id,
name: rawCard.name, // title
desc: rawCard.desc, // description
labels: rawCard.labels, // array
attachments: rawCard.attachments, // array
members: rawCard.members, // array
checkLists: [], // from idCheckLists
comments: [], // from actions
// otherActions: [],//actions of other types // took out because data was not consistent
},
info : {
ids: {
id: rawCard.id,
idList: rawCard.idList,
idCheckLists: rawCard.idCheckLists,
idMembers: rawCard.idMembers,
},
url: rawCard.url,
},
}
// rawListsData[rawCard.idList][rawCard.id] = card
cards[card.raw_data.id] = card
}
//
for (const rawCheckList of rawCheckListsData) {
// Refining individual checkItems
let rawCheckItems = rawCheckList.checkItems, checkItems = [];
rawCheckItems.forEach(item => {
checkItems.push({
state: item.state,
name: item.name,
})
});
let checkList = {
id: rawCheckList.id,
idCard: rawCheckList.idCard,
name: rawCheckList.name,
// checkItems: { // array of items of checklist
// state: rawCheckList.state, // complete or incomplete
// name: rawCheckList.name,
// }
checkItems: checkItems,
// checkItems: rawCheckList.checkItems,
}
// checkLists[checkList.id] = checkList
cards[checkList.idCard].raw_data.checkLists.push(checkList)
}
//
for (const rawAction of rawActionsData) {
if (rawAction.type == "comentCard") {
let action = {
id: rawAction.id,
data: {
text: rawAction.data.text,
type: rawAction.data.type, // we are looking for commentCard
date: rawAction.data.date, // Date()
card: {
id: rawAction.data.card.id,
},
// list: {
// id: rawAction.data.list.id,
// name: rawAction.data.list.name,
// },
},
// memberCreator: {
// username: rawAction.data.memberCreator.username,
// fullName: rawAction.data.memberCreator.fullName,
// }
}
if (rawAction.data.list) {
action.data.list = {
id: rawAction.data.list.id,
name: rawAction.data.list.name,
}
}
if (rawAction.data.memberCreator) {
action.memberCreator = {
username: rawAction.data.memberCreator.username,
fullName: rawAction.data.memberCreator.fullName,
}
}
// actions[action.id] = action
// if (action.type == "commentCard") {
// cards[action.card.id].raw_data.comments.push(action)
// } else {
// // cards[action.card.id].raw_data.otherActions.push(action)
// console.log(action)
// }
cards[action.card.id].raw_data.comments.push(action)
} // catch (e) {
// console.log(rawAction)
// console.log(e)
// }
}
// final structuring of cards
for (const cardId in cards) {
const cardData = cards[cardId].raw_data
let data = {
title: cardData.name,
description : getDescription(cardData, cards[cardId].info.url),
comments: cardData.comments, // array in order
issueInfo: {
labels: cardData.labels,
participants: cardData.members,
}
}
let cardListId = cards[cardId].info.ids.idList
cards[cardId].data = data;
if (!rawListsData[cardListId])
rawListsData[cardListId] = {}
rawListsData[cardListId][cardData.id] = cards[cardId]
}
// return [cards, rawListsData]
storeData(cards, `cards.json`)
return rawListsData
}
const getLists = () => {
let rawListData = importedTrelloData.lists;
let data = []
for (let i=0; i < rawListData.length; i++) {
data[i] = {
info: {
id: rawListData[i].id,
closed: rawListData[i].closed,
name: rawListData[i].name,
},
cards : []
}
}
// TODO: refine data
listData = getOrganizedListData()
for (const listId of Object.keys(listData)) {
let listIndex = data.findIndex(list => {
return list.info.id == listId
})
if (listIndex != -1) {
data[listIndex].cards = listData
}
}
storeData(data, `lists.json`)
return data;
}
function main() {
let structuredData = {
info : {
id : importedTrelloData.id,
name: importedTrelloData.name,
members: [],
labels: [],
},
data : {
lists : []
}
}
structuredData.info.members = getMembers()
structuredData.info.labels = getLabels()
structuredData.data.lists = getLists()
storeData(structuredData, `board.json`)
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment