Skip to main content
Glama

mcptix

by ownlytics
comments.js5.62 kB
/** * Comments module for mcptix * Handles rendering and managing comments on tickets */ import { Storage } from './storage.js'; // Comment authors const COMMENT_AUTHORS = { DEVELOPER: 'developer', AGENT: 'agent', }; /** * Load comments for a ticket * @param {HTMLElement} container - The container to render comments in * @param {object} ticket - The ticket to load comments for * @returns {Promise} A promise that resolves when comments are loaded */ function loadComments(container, ticket) { if (!container || !ticket) { return Promise.resolve(); } // Clear the container container.innerHTML = '<div class="comments-loading">Loading comments...</div>'; // Get comments from the API return Storage.getComments(ticket.id) .then(comments => { // Clear the container container.innerHTML = ''; // Check if ticket has comments if (!comments || comments.length === 0) { container.innerHTML = '<div class="comments-empty">No comments yet</div>'; return; } // Sort comments by timestamp (oldest first) const sortedComments = [...comments].sort((a, b) => { return new Date(a.timestamp) - new Date(b.timestamp); }); // Render each comment sortedComments.forEach(comment => { renderComment(container, comment); }); }) .catch(error => { console.error('Error loading comments:', error); container.innerHTML = '<div class="comments-error">Error loading comments</div>'; }); } /** * Clear comments from a container * @param {HTMLElement} container - The container to clear comments from */ function clearComments(container) { if (container) { container.innerHTML = '<div class="comments-empty">No comments yet</div>'; } } /** * Render a single comment * @param {HTMLElement} container - The container to render the comment in * @param {object} comment - The comment to render */ function renderComment(container, comment) { // Create comment element const commentElement = document.createElement('div'); commentElement.className = `comment comment-author-${comment.author}`; commentElement.dataset.id = comment.id; // Format timestamp const timestamp = new Date(comment.timestamp).toLocaleString(); // Get author label const authorLabel = comment.author === COMMENT_AUTHORS.DEVELOPER ? 'Developer' : 'Agent'; // Create comment header const headerHTML = ` <div class="comment-header"> <span class="comment-author-badge">${authorLabel}</span> <span class="comment-timestamp">${timestamp}</span> </div> `; // Create comment content with markdown support let contentHTML = ''; if (comment.author === COMMENT_AUTHORS.AGENT) { // For agent comments, implement client-side expand/collapse // First paragraph or first 100 characters as summary let summary = ''; let fullContent = comment.content || ''; const firstParagraphMatch = fullContent.match(/^(.*?)(\n\n|\n|$)/); if (firstParagraphMatch && firstParagraphMatch[1]) { summary = firstParagraphMatch[1]; // If summary is too long, truncate it if (summary.length > 150) { summary = summary.substring(0, 147) + '...'; } } else { summary = fullContent.length > 150 ? fullContent.substring(0, 147) + '...' : fullContent; } // Create a collapsible content section contentHTML = ` <div class="comment-content"> <div class="comment-summary">${summary}</div> <div class="comment-full-text collapsed"> <div class="markdown-content"></div> </div> ${fullContent.length > summary.length ? '<button type="button" class="toggle-full-text-btn">Show More</button>' : ''} </div> `; } else { // Developer comment - simple rendering contentHTML = `<div class="comment-content">${comment.content || ''}</div>`; } // Set comment HTML - no actions section needed commentElement.innerHTML = headerHTML + contentHTML; // Add to container container.appendChild(commentElement); // Render markdown for all comments const markdownContainer = commentElement.querySelector('.markdown-content'); if (markdownContainer && typeof marked !== 'undefined') { try { markdownContainer.innerHTML = marked.parse(comment.content || ''); } catch (error) { console.error('Error parsing markdown:', error); markdownContainer.innerHTML = comment.content || ''; } } // Add toggle button event listener const toggleButton = commentElement.querySelector('.toggle-full-text-btn'); const fullTextContainer = commentElement.querySelector('.comment-full-text'); if (toggleButton && fullTextContainer) { toggleButton.addEventListener('click', () => { const isCollapsed = fullTextContainer.classList.contains('collapsed'); fullTextContainer.classList.toggle('collapsed'); toggleButton.textContent = isCollapsed ? 'Show Less' : 'Show More'; }); } } /** * Add a comment to a ticket * @param {string} ticketId - The ID of the ticket to add the comment to * @param {string} content - The content of the comment * @returns {Promise} A promise that resolves when the comment is added */ function addComment(ticketId, content) { // Create the comment object const comment = { content, author: COMMENT_AUTHORS.DEVELOPER, }; // Add the comment using the Storage API return Storage.addComment(ticketId, comment); } // Export the module functions and constants export const Comments = { loadComments, clearComments, addComment, COMMENT_AUTHORS, };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ownlytics/mcptix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server