Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
412 changes: 378 additions & 34 deletions dist/doboard-widget-bundle.js

Large diffs are not rendered by default.

118 changes: 109 additions & 9 deletions dist/doboard-widget-bundle.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/doboard-widget-bundle.min.js.map

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions js/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const attachmentAddDoboard = async (fileData) => {
attachment_order: fileData.attachmentOrder,
};
const result = await spotfixApiCall(data, 'attachment_add', accountId);
//await getTasksCommentsDoboard(fileData.sessionId, params.accountId, params.projectToken, currentActiveTaskId);
// @ToDo need to handle result?
};

Expand Down Expand Up @@ -288,6 +289,27 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, curre
await spotfixIndexedDB.clearPut(SPOTFIX_TABLE_COMMENTS, comments);
return comments;
};
const getTasksAttachmenDoboard = async (sessionId, accountId, projectToken, currentActiveTaskId, status = 'ACTIVE') => {
const data = {
session_id: sessionId,
project_token: projectToken,
status: status,
task_id: currentActiveTaskId
}
const result = await spotfixApiCall(data, 'attachment_get', accountId);

const attachment = result.attachments.map((item, index) => ({
attachmentId: item.attachment_id || `att_${item.task_id}_${index}_${Date.now()}`,
taskId: item.task_id,
commentId: item.comment_id,
attachmentOrder: item.attachment_order,
URL_thumbnail: item.URL_thumbnail,
URL: item.URL,
filename: item.filename,
}));
await spotfixIndexedDB.clearPut(SPOTFIX_TABLE_ATTACHMENT, attachment);
return attachment;
};

const getUserDoboard = async (sessionId, projectToken, accountId, userId) => {
const data = {
Expand Down
2 changes: 1 addition & 1 deletion js/src/fileuploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class FileUploader {
this.maxFiles = 5;

/** @type {string[]} Allowed MIME types for files */
this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain', 'application/msword'];
this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain', 'application/msword', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];

/** @type {function} HTML escaping function for XSS protection */
this.escapeHtmlHandler = escapeHtmlHandler;
Expand Down
5 changes: 4 additions & 1 deletion js/src/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ async function spotFixConfirmUserEmail(emailConfirmationToken, params) {
async function getTasksFullDetails(params, tasks, currentActiveTaskId, nonRequesting = false) {
if (tasks.length > 0) {
const sessionId = localStorage.getItem('spotfix_session_id');
if (!nonRequesting) {
if (!nonRequesting && currentActiveTaskId && +currentActiveTaskId !== 0) {
await getTasksAttachmenDoboard(sessionId, params.accountId, params.projectToken, currentActiveTaskId);
await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken, currentActiveTaskId);
}
const comments = await spotfixIndexedDB.getAll(SPOTFIX_TABLE_COMMENTS);
const attachments = await spotfixIndexedDB.getAll(SPOTFIX_TABLE_ATTACHMENT);
if (!nonRequesting) {
await getUserDoboard(sessionId, params.projectToken, params.accountId);
}
Expand All @@ -57,6 +59,7 @@ async function getTasksFullDetails(params, tasks, currentActiveTaskId, nonReques
return {
comments: comments,
users: users,
attachments: attachments,
taskStatus: foundTask?.taskStatus,
taskName: foundTask?.taskTitle,
};
Expand Down
161 changes: 161 additions & 0 deletions js/src/loaders/SpotFixSVGLoader.js

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions js/src/loaders/SpotFixTemplatesLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,22 @@ class SpotFixTemplatesLoader {
</div>
<div class="doboard_task_widget-comment_text_container">
<div class="doboard_task_widget-comment_body">{{commentBody}}</div>
<div class="doboard_task_widget-comment_attachments">{{commentAttachments}}</div>
<div class="doboard_task_widget-comment_time">{{commentTime}}</div>
</div>
</div>
`;
}

static concrete_issue_attachment() {
return `
<div class="doboard_task_widget-attachment_item {{attachmentClass}}" data-attachment-url="{{attachmentUrl}}" data-is-image="{{attachmentIsImage}}">
<img src="{{attachmentIcon}}" alt="{{attachmentFilename}}">
<span class="doboard_task_widget-attachment_filename">{{attachmentFilename}}</span>
</div>
`;
}

static create_issue() {
return `
<div class="doboard_task_widget-container">
Expand Down Expand Up @@ -462,4 +472,18 @@ class SpotFixTemplatesLoader {
return `<p class="doboard_task_widget-bottom-is-fixed-task-block"><span class="doboard_task_widget-bottom-is-fixed-task">This issue already fixed</span></p>`;
}

static imageLightbox() {
return `
<div class="doboard_task_widget-lightbox" id="doboard_task_widget-lightbox">
<div class="doboard_task_widget-lightbox-overlay"></div>
<div class="doboard_task_widget-lightbox-content">
<img src="{{imageUrl}}" alt="{{imageAlt}}" class="doboard_task_widget-lightbox-image">
</div>
<button class="doboard_task_widget-lightbox-close doboard_task_widget_cursor-pointer" title="Close">
<img src="{{buttonCloseScreen}}" alt="Close">
</button>
</div>
`;
}

}
4 changes: 3 additions & 1 deletion js/src/localDB.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
const SPOTFIX_INDEXED_DB_NAME = 'spotfix-localDB';
const spotfixIndexedDBVersion = 1;
const spotfixIndexedDBVersion = 2;

const SPOTFIX_TABLE_USERS = 'users';
const SPOTFIX_TABLE_TASKS = 'tasks';
const SPOTFIX_TABLE_COMMENTS = 'comments';
const SPOTFIX_TABLE_ATTACHMENT = 'attachment';

const LOCAL_DATA_BASE_TABLE = [
{ name: SPOTFIX_TABLE_USERS, keyPath: 'user_id' },
{ name: SPOTFIX_TABLE_TASKS, keyPath: 'taskId' },
{ name: SPOTFIX_TABLE_COMMENTS, keyPath: 'commentId' },
{ name: SPOTFIX_TABLE_ATTACHMENT, keyPath: 'attachmentId' },
];

const SPOTFIX_LAST_DB_KEY = 'spotfix_last_db_key';
Expand Down
32 changes: 8 additions & 24 deletions js/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ function getTaskFullDetails(tasksDetails, taskId) {
return comment?.taskId?.toString() === taskId?.toString()
});
const users = tasksDetails.users;
const attachments = tasksDetails.attachments || [];
// Last comment
let lastComment = comments.length > 0 ? comments[0] : null;
// Author of the last comment
Expand Down Expand Up @@ -223,13 +224,19 @@ function getTaskFullDetails(tasksDetails, taskId) {
if (users && users.length > 0) {
author = users.find(u => String(u.user_id) === String(comment.userId));
}
// Get attachments for this comment
const commentAttachments = attachments
.filter(att => String(att.commentId) === String(comment.commentId))
.sort((a, b) => (a.attachmentOrder || 0) - (b.attachmentOrder || 0));

return {
commentAuthorAvatarSrc: getAvatarSrc(author),
commentAuthorName: getAuthorName(author),
commentBody: comment.commentBody,
commentDate: date,
commentTime: time,
commentUserId: comment.userId || 'Unknown User',
commentAttachments: commentAttachments,
};
})
};
Expand Down Expand Up @@ -369,7 +376,7 @@ function ksesFilter(html, options = false) {
a: ['href', 'title', 'target', 'rel', 'style', 'class'],
span: ['style', 'class', 'id'],
p: ['style', 'class'],
div: ['style', 'class', 'id', 'data-node-path', 'data-task-id'],
div: ['style', 'class', 'id', 'data-node-path', 'data-task-id', 'data-attachment-url', 'data-is-image'],
img: ['src', 'alt', 'title', 'class', 'style', 'width', 'height'],
input: ['type', 'class', 'style', 'id', 'multiple', 'accept', 'value'],
label: ['for', 'class', 'style'],
Expand All @@ -390,28 +397,7 @@ function ksesFilter(html, options = false) {
const tag = node.tagName.toLowerCase();

if (options) {
if (allowedTags[tag]) {
// Special handling for images in 'concrete_issue_day_content' template (wrap img in link always)
if (tag === 'img' && options.template === 'concrete_issue_day_content' && options.imgFilter) {
const src = node.getAttribute('src') || '';
const alt = node.getAttribute('alt') || '[image]';
const link = doc.createElement('a');
link.href = src;
link.target = '_blank';
link.className = 'doboard_task_widget-img-link';
const img = doc.createElement('img');
img.src = src;
img.alt = alt;
img.className = 'doboard_task_widget-comment_body-img-strict';
link.appendChild(img);
node.parentNode.insertBefore(link, node);
node.remove();
return;
}
}

if (!allowedTags[tag]) {
// Special handling for images in 'list_issues' template
if (tag === 'img' && options.template === 'list_issues' && options.imgFilter) {
const src = node.getAttribute('src') || '';
const alt = node.getAttribute('alt') || '[image]';
Expand All @@ -426,7 +412,6 @@ function ksesFilter(html, options = false) {
}
}

// Remove disallowed attributes
[...node.attributes].forEach(attr => {
const attrName = attr.name.toLowerCase();
if (!allowedAttrs[tag]?.includes(attrName) ||
Expand All @@ -436,7 +421,6 @@ function ksesFilter(html, options = false) {
}
});
}
// Recursively clean children
[...node.childNodes].forEach(clean);
}
[...doc.body.childNodes].forEach(clean);
Expand Down
23 changes: 22 additions & 1 deletion js/src/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ const handleIncomingData = async (data) => {
});
break;

case 'attachments':
if (data.data.status === 'REMOVED') {
await spotfixIndexedDB.delete(SPOTFIX_TABLE_ATTACHMENT, data.data.attachment_id);
break;
}
await spotfixIndexedDB.put(SPOTFIX_TABLE_ATTACHMENT, {
attachmentId: data.data.attachment_id,
taskId: data.data.task_id,
commentId: data.data.comment_id,
userId: data.data.user_id,
filename: data.data.filename,
URL: data.data.URL,
URL_thumbnail: data.data.URL_thumbnail,
mimeType: data.data.mime_content_type,
fileSize: data.data.file_size,
attachmentOrder: data.data.attachment_order,
created: data.data.created,
updated: data.data.updated,
});
break;

default:
break;
}
Expand Down Expand Up @@ -104,7 +125,7 @@ const wsSpotfix = {
return;
}

if (!['users', 'tasks', 'comments'].includes(data.object)) return;
if (!['users', 'tasks', 'comments', 'attachments'].includes(data.object)) return;

const eventId = data.id ? `${data.object}-${data.id}` : JSON.stringify(data);

Expand Down
Loading