I created two scripts, which work independently, you can choose which one best fits your case.
Script A (without Mention Filter)
Focuses on gathering comments from a specified channel, formatting them for readability, and then creating a new thread entity that compiles these comments in a structured manner.
Use Cases for Script A:
- Summarizing feedback from team discussions or customer feedback channels.
- Compiling notes or discussions from meetings into a single, accessible document.
- Archiving discussions for future reference or for newcomers to quickly catch up.
Script B (with Mention Filter)
Extends the functionality of Script A by adding a filtering mechanism based on Mention links within comments. It fetches comments from a channel, filters them based on specified Mention entity, formats the filtered comments, and creates a new thread entity containing only the comments that match the filtering criteria.
Use Cases for Script B:
- Creating focused summaries of discussions that pertain only to specific topics, identified by tags.
- Filtering customer feedback or team discussions to isolate comments relevant to particular features, issues, or areas of interest.
- Enhancing project management by automatically organizing task-related discussions into dedicated threads for better clarity and actionability.
Script A: Without Mention Filter
const fibery = context.getService('fibery');
const threadsDb = 'Threads/Channel'; // Database for Channel
const threadDb = 'Threads/Thread'; // Database for Thread
const fiberyBaseURL = 'https://cce.fibery.io'; // Base URL for your Fibery instance
async function formatComment(comment, indentLevel = 0, channelPublicId) {
const commentEntity = await fibery.getEntityById('comments/comment', comment['Id'], ['Author', 'fibery/creation-date', 'comments/parent', 'fibery/public-id']);
const authorName = commentEntity['Author']['Name'] || "Unknown Author";
const commentContent = await fibery.getDocumentContent(comment['Document Secret'], 'md');
const creationDate = new Date(commentEntity['fibery/creation-date']);
const formattedDate = `${creationDate.getFullYear()}-${String(creationDate.getMonth() + 1).padStart(2, '0')}-${String(creationDate.getDate()).padStart(2, '0')}, ${String(creationDate.getHours()).padStart(2, '0')}:${String(creationDate.getMinutes()).padStart(2, '0')}`;
const commentPublicId = commentEntity['fibery/public-id'];
const headerLink = `[**${authorName}** (${formattedDate})](${fiberyBaseURL}/Threads/Channel/${channelPublicId}/comment=${commentPublicId})`;
const indentation = "> ".repeat(indentLevel);
return `${indentation}${headerLink}:\n${indentation}${commentContent.replace(/\n/g, `\n${indentation}`)}\n\n`;
}
async function createThreadWithComments(entityId) {
// Fetching the Channel entity to obtain its name and public ID
const channelEntity = await fibery.getEntityById(threadsDb, entityId, ['Name', 'fibery/public-id']);
const channelName = channelEntity['Name'];
const channelPublicId = channelEntity['fibery/public-id'];
const entityWithComments = await fibery.getEntityById(threadsDb, entityId, ['Comments']);
let content = "";
if (entityWithComments.Comments && entityWithComments.Comments.length > 0) {
const topLevelComments = [];
const repliesMap = {};
for (const comment of entityWithComments.Comments) {
const commentEntity = await fibery.getEntityById('comments/comment', comment['Id'], ['comments/parent', 'fibery/public-id']);
const parentId = commentEntity['comments/parent'] ? commentEntity['comments/parent']['Id'] : null;
if (parentId) {
if (!repliesMap[parentId]) {
repliesMap[parentId] = [];
}
repliesMap[parentId].push(comment);
} else {
topLevelComments.push(comment);
}
}
for (const comment of topLevelComments) {
content += await formatComment(comment, 0, channelPublicId);
const replies = repliesMap[comment['Id']];
if (replies && replies.length > 0) {
for (const reply of replies) {
content += await formatComment(reply, 1, channelPublicId);
}
}
}
} else {
console.log(`No comments found for entity ${entityId}.`);
return;
}
const creationTimestamp = new Date();
const formattedTimestamp = `${creationTimestamp.getFullYear()}-${String(creationTimestamp.getMonth() + 1).padStart(2, '0')}-${String(creationTimestamp.getDate()).padStart(2, '0')} ${String(creationTimestamp.getHours()).padStart(2, '0')}:${String(creationTimestamp.getMinutes()).padStart(2, '0')}`;
const newThreadData = { 'Name': `${channelName} Comments (${formattedTimestamp})`, 'Channel': entityId };
const newThread = await fibery.createEntity(threadDb, newThreadData);
if (newThread['Description'] && newThread['Description'].Secret) {
await fibery.setDocumentContent(newThread['Description'].Secret, content, 'md');
console.log(`New Thread entity created and description updated with comments for Channel entity ${entityId}. Thread ID: ${newThread.id}.`);
} else {
console.log(`Failed to update Description for the new Thread entity linked to Channel entity ${entityId}.`);
}
}
async function processChannelComments() {
try {
if (!args.currentEntities || args.currentEntities.length === 0) {
throw new Error('No current entity found.');
}
for (const currentEntity of args.currentEntities) {
await createThreadWithComments(currentEntity.id);
}
} catch (error) {
console.error(`Error processing comments for the entity: ${error.message}`, error);
}
}
await processChannelComments();
Script B: With Mention Filter
const fibery = context.getService('fibery');
const threadsDb = 'Threads/Channel'; // Adjust according to your actual Channel database
const threadDb = 'Threads/Thread'; // Adjust to your Thread database
const fiberyBaseURL = 'https://cce.fibery.io'; // Base URL for your Fibery instance
async function fetchChannelTags(channelId) {
const channelEntity = await fibery.getEntityById(threadsDb, channelId, ['Tags']);
return channelEntity.Tags ? channelEntity.Tags : [];
}
async function fetchCommentsForChannel(channelId) {
const entity = await fibery.getEntityById(threadsDb, channelId, ['Comments']);
return entity.Comments ? entity.Comments : [];
}
async function filterCommentsByTagUuids(comments, tagUuids) {
const matchingComments = [];
for (const comment of comments) {
const commentContent = await fibery.getDocumentContent(comment['Document Secret'], 'md');
if (tagUuids.some(tagUuid => commentContent.includes(tagUuid))) {
matchingComments.push(comment);
}
}
return matchingComments;
}
async function formatComment(comment, channelPublicId) {
const commentEntity = await fibery.getEntityById('comments/comment', comment['Id'], ['Author', 'fibery/creation-date', 'fibery/public-id']);
const authorName = commentEntity['Author']['Name'] || "Unknown Author";
const creationDate = new Date(commentEntity['fibery/creation-date']);
const formattedDate = `${creationDate.getFullYear()}-${String(creationDate.getMonth() + 1).padStart(2, '0')}-${String(creationDate.getDate()).padStart(2, '0')} ${String(creationDate.getHours()).padStart(2, '0')}:${String(creationDate.getMinutes()).padStart(2, '0')}`;
const commentPublicId = commentEntity['fibery/public-id'];
const headerLink = `[**${authorName}** (${formattedDate})](${fiberyBaseURL}/Threads/Channel/${channelPublicId}/comment=${commentPublicId})`;
const commentContent = await fibery.getDocumentContent(comment['Document Secret'], 'md');
return `${headerLink}:\n${commentContent}\n\n`;
}
async function createThreadWithComments(entityName, comments, channelPublicId) {
const newThreadData = {
'Name': entityName,
'Channel': channelPublicId,
};
const newThread = await fibery.createEntity(threadDb, newThreadData);
let descriptionContent = "Filtered Comments:\n\n";
for (const comment of comments) {
descriptionContent += await formatComment(comment, channelPublicId);
}
await fibery.setDocumentContent(newThread['Description'].Secret, descriptionContent, 'md');
return `New Thread created with ID: ${newThread.id}, linked to Channel ${channelPublicId}, containing ${comments.length} filtered comments.`;
}
async function processChannelComments() {
try {
if (!args.currentEntities || args.currentEntities.length === 0) {
return 'No current entity found to process.';
}
let messages = [];
for (const currentEntity of args.currentEntities) {
const channelId = currentEntity.id;
const tags = await fetchChannelTags(channelId);
const tagUuids = tags.map(tag => tag['Id']);
const tagNames = tags.map(tag => `[${tag['Name']}]`).join(' ');
const comments = await fetchCommentsForChannel(channelId);
const matchingComments = await filterCommentsByTagUuids(comments, tagUuids);
if (matchingComments.length > 0) {
const creationTimestamp = new Date();
const formattedTimestamp = `${creationTimestamp.getFullYear()}-${String(creationTimestamp.getMonth() + 1).padStart(2, '0')}-${String(creationTimestamp.getDate()).padStart(2, '0')} ${String(creationTimestamp.getHours()).padStart(2, '0')}:${String(creationTimestamp.getMinutes()).padStart(2, '0')}`;
const entityName = `Filtered Comments with ${tagNames} ${formattedTimestamp}`;
const message = await createThreadWithComments(entityName, matchingComments, channelId);
messages.push(message);
} else {
messages.push(`No matching comments found for the selected tags in Channel ${channelId}.`);
}
}
return messages.join("\n");
} catch (error) {
throw new Error(`Error processing comments for the channel: ${error.message}`);
}
}
return await processChannelComments();
Explanation
Script A
- Initialize Fibery service and database names.
- Define
formatComment
function to fetch comment details, format content, and construct clickable link headers. - Define
createThreadWithComments
function to fetch channel details, organize comments into a structured format, and create a new thread with formatted comments. - Fetch channel’s public ID for URL construction.
- Iterate through comments to distinguish top-level comments from replies, applying formatting recursively.
- Construct a new thread entity with a timestamped name and link it to the channel.
- Update the new thread’s description with the formatted comments.
- Define
processChannelComments
as the main function to process each provided channel entity, using the above functions. - Execute
processChannelComments
, orchestrating the script’s operations. - Log success or failure messages based on the outcome of operations.
Script B:
- Initialize Fibery service and database constants.
- Define
fetchChannelTags
to retrieve tags associated with a given channel. - Define
fetchCommentsForChannel
to fetch all comments linked to a channel. - Define
filterCommentsByTagUuids
to filter comments based on content containing any tag UUIDs. - Define
formatComment
to format comment details and create clickable link headers. - Define
createThreadWithComments
to compile filtered comments into a description and create a new thread entity linked to the channel. - In
createThreadWithComments
, use the channel’s public ID for URL constructions within comments and the internal UUID for entity linking. - Define
processChannelComments
as the main function to orchestrate fetching tags, comments, filtering by tags, and thread creation. - Execute the filtering logic; if no comments match the tags, prepare a message indicating no matching comments were found.
- If matching comments are found, proceed with thread creation and compile a success message detailing the action taken.
- Adjust
processChannelComments
to return a custom message to the user based on the outcome, including success notifications or error messages if applicable. - Execute
processChannelComments
and return its output as the script’s final action, displaying the outcome message to the user.