From d24ef19e015dcc352b208fc6fd3fb24a776a4b6f Mon Sep 17 00:00:00 2001 From: bpDevTc <104766829+bpDevTc@users.noreply.github.com> Date: Tue, 18 Aug 2026 08:59:40 +0200 Subject: [PATCH 1/2] [BP-28] Clickup v2 --- _locales/en/messages.json | 3 + integrationList.json | 5 + manifest.json | 10 -- scripts-2.0/style/clickup.scss | 6 + scripts-2.0/style/main.scss | 1 + scripts-2.0/third_party/clickup.js | 47 +++++++ scripts/third_party/clickup.js | 208 ----------------------------- styles/sites/clickup.css | 70 ---------- 8 files changed, 62 insertions(+), 288 deletions(-) create mode 100644 scripts-2.0/style/clickup.scss create mode 100644 scripts-2.0/third_party/clickup.js delete mode 100644 scripts/third_party/clickup.js delete mode 100644 styles/sites/clickup.css diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c1d25a3..6326c3e 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -192,6 +192,9 @@ "asana_task_not_found_in_backend_integration_info": { "message": "This task is not synchronized in TimeCamp. Choose task by yourself or check workspaces in integration settings" }, + "clickup_task_not_found_in_backend_integration_info": { + "message": "This task is not synchronized in TimeCamp. Choose task by yourself or check workspaces in integration settings" + }, "todoist_task_not_found_in_backend_integration_info": { "message": "This task is not synchronized in TimeCamp. Choose task by yourself." }, diff --git a/integrationList.json b/integrationList.json index 98db88e..7af65d5 100644 --- a/integrationList.json +++ b/integrationList.json @@ -4,6 +4,11 @@ "script": ["asana.js"], "isActiveInProd": true }, + { + "matches": ["*://app.clickup.com/*"], + "script": ["clickup.js"], + "isActiveInProd": true + }, { "matches": ["*://docs.google.com/*"], "script": ["google-docs.js"], diff --git a/manifest.json b/manifest.json index f756863..148d87f 100644 --- a/manifest.json +++ b/manifest.json @@ -74,16 +74,6 @@ "js": ["scripts/lib/jquery-2.1.1.min.js", "scripts/lib/jquery-ui.min.js", "scripts/lib/moment.min.js", "scripts/lib/moment-range.min.js", "scripts/config.js", "scripts/TokenManager.js", "scripts/ApiService.js", "scripts/common.js", "scripts/TimerBase.js","scripts/TimerButton.js", "scripts/third_party/todoist.js"] - }, - { - "matches": [ - "*://app.clickup.com/*" - ], - "css": ["styles/common.css", "styles/font-awesome.css", "styles/bootstrap.min.css", "styles/jquery-ui.structure.min.css", "styles/jquery-ui.theme.min.css", - "styles/sites/clickup.css"], - "js": ["scripts/lib/jquery-2.1.1.min.js", "scripts/lib/jquery-ui.min.js", "scripts/lib/moment.min.js", "scripts/lib/moment-range.min.js", - "scripts/config.js", "scripts/TokenManager.js", "scripts/ApiService.js", "scripts/common.js", "scripts/TimerBase.js","scripts/TimerButton.js", - "scripts/third_party/clickup.js"] } ], "homepage_url": "http://www.timecamp.com/", diff --git a/scripts-2.0/style/clickup.scss b/scripts-2.0/style/clickup.scss new file mode 100644 index 0000000..aea844a --- /dev/null +++ b/scripts-2.0/style/clickup.scss @@ -0,0 +1,6 @@ +.tc-button.clickup { + &__task-view { + align-self: center; + margin-left: 12px; + } +} diff --git a/scripts-2.0/style/main.scss b/scripts-2.0/style/main.scss index 954f546..6f3c8da 100644 --- a/scripts-2.0/style/main.scss +++ b/scripts-2.0/style/main.scss @@ -91,6 +91,7 @@ @import 'coda'; @import 'codeable'; @import 'codebase'; +@import 'clickup'; @import 'desk'; @import 'devdocs'; @import 'dobambam'; diff --git a/scripts-2.0/third_party/clickup.js b/scripts-2.0/third_party/clickup.js new file mode 100644 index 0000000..6963d9d --- /dev/null +++ b/scripts-2.0/third_party/clickup.js @@ -0,0 +1,47 @@ +'use strict'; + +const CLICKUP = 'clickup'; +const CLICKUP_EXTERNAL_ID_PREFIX = 'task'; +const TASK_NOT_FOUND_INFO = 'clickup_task_not_found_in_backend_integration_info'; + +const buildExternalIdForClickUp = (taskId) => { + return CLICKUP_EXTERNAL_ID_PREFIX + '_' + taskId; +}; + +const getTaskIdFromUrl = (url) => { + let lastUrlSegmentStartIndex = url.lastIndexOf('/') + 1; + + return url.substring(lastUrlSegmentStartIndex); +}; + +//Task view +tcbutton.render( + '.cu-task-hero-section__actions .cu-task-hero-actions .container:not(.tc)', + {observe: true}, + elem => { + let taskId = getTaskIdFromUrl(document.URL); + if (!taskId) { + return false; + } + + const externalTaskId = buildExternalIdForClickUp(taskId); + const description = () => { + const note = $('[data-test="task-title__title-overlay"]')?.textContent.trim() ?? ''; + + return note; + }; + + const link = tcbutton.createTimerLink({ + className: CLICKUP, + additionalClasses: [CLICKUP + '__task-view'], + description: description, + externalTaskId: externalTaskId, + isBackendIntegration: true, + taskNotFoundInfo: TASK_NOT_FOUND_INFO + }); + + elem.insertAdjacentElement('afterend', link); + + return true; + } +); diff --git a/scripts/third_party/clickup.js b/scripts/third_party/clickup.js deleted file mode 100644 index c54bd5b..0000000 --- a/scripts/third_party/clickup.js +++ /dev/null @@ -1,208 +0,0 @@ -function ClickupTimer () { - var $this = this; - this.timeFormat = 'classic'; - - Messages.set('buttonTimerStopped', 'BUTTON_TIMER_STOPPED'); - Messages.set('buttonTimerStopTrackingAnotherTask', 'BUTTON_TIMER_STOPPED'); - - Messages.set('buttonTimerStarted', 'EMPTY_MESSAGE'); - Messages.set('buttonTimerStopping', 'BUTTON_TIMER_STOPPED'); - Messages.set('buttonTimerStarting', 'BUTTON_TIMER_STOPPED'); - - this.currentTaskId = function () { - var url = document.URL; - var lastUrlSegmentStartIndex = url.lastIndexOf('/') + 1; - var taskId = url.substring(lastUrlSegmentStartIndex); - return "task_" + taskId; - }; - - this.isCurrentUrlMatchingTaskUrl = function () { - var url = document.URL; - var taskUrlRegex = new RegExp('^https:\/\/app\.clickup\.com\/t.*'); - return taskUrlRegex.test(url); - }; - - this.onSyncSuccess = function (response) { - if (this.isTimerRunning) { - this.trackedTaskId = response.external_task_id; - if (!this.trackedTaskId){ - return; - } - this.appendBadges(); - } else { - this.onSyncFailure(); - } - }; - - this.appendBadges = function() { - var badges = $('.list-cards a[href^="/c/' + this.trackedTaskId + '"]').siblings('div.badges'); - if (badges.find("#tc-badge").length == 0) { - var badge = $("#tc-badge"); - - if (badge.length > 0) { - badge.detach(); - } else { - badge = $('', - { - id: "tc-badge", - class: "badge", - src: chrome.runtime.getURL('images/icon-14.png'), - title: Messages.badgeTimerRunning - }); - } - badges.append(badge); - } - }; - - this.isButtonInserted = function() { - if (this.buttonInsertionInProgress) { - return true; - } - return $('#timecamp-track-button').length > 0; - }; - - this.insertButtonIntoPage = function () { - if (!this.isCurrentUrlMatchingTaskUrl()) { - return; - } - - var currentTaskId = $this.currentTaskId(); - if (!currentTaskId) - return; - - if (this.buttonInsertionInProgress === true) { - return; - } - - var buttonObj; - if (ButtonList[currentTaskId]) - buttonObj = ButtonList[currentTaskId]; - else - { - var taskName = $this.currentTaskName(); - buttonObj = new TimerButton(currentTaskId, taskName, this.timeFormat); - ButtonList[currentTaskId] = buttonObj; - } - - buttonObj.insertInProgress = true; - this.buttonInsertionInProgress = true; - - var button = this.createClickupTimerButton(); - buttonObj.uiElement = button; - this.button = button; - - $.when(this.updateButtonState()) - .always(function () { - $this.buttonInsertionInProgress = false; - }); - - var clickupUserTaskHeaderSection = $(".cu-task-hero-section__actions .cu-task-hero-actions .container"); - if (!clickupUserTaskHeaderSection) { - clickupUserTaskHeaderSection = document - .querySelector('[data-test="task-hero-section__row"]') - ?.querySelector(".cu-task-hero-section__row-item"); - } - - $(button).insertAfter(clickupUserTaskHeaderSection); - buttonObj.insertInProgress = false; - - }; - - this.createClickupTimerButton = function() - { - var button = $('', { 'class': 'button-link', 'id': 'timecamp-track-button', 'data-taskId': this.currentTaskId(), 'status': 'unknown' }); - button.append($('')); - button.append($('').hide()); - button.append($('', { 'class': 'text' }).text(Messages.buttonTimerStopped)); - button.append($('', { 'class': 'time' }).text("00:00").hide()); - return button; - }; - - this.clearEntriesContainer = function () - { - $('.tc-entries-container').html(''); - $('.tc-entries-container').remove(); - }; - - this.onEntriesLoaded = function(event, eventData) - { - $this.clearEntriesContainer(); - - var clickupTaskHistoryItem = $('.cu-task-history-item'); - var lastTaskHistoryItem = clickupTaskHistoryItem.last(); - var entriesContainer = $(''); - - entriesContainer.insertAfter(lastTaskHistoryItem); - $this.renderEntries(eventData.data); - }; - - this.renderEntries = function(entries) - { - var entriesContainer = $('.tc-entries-container'); - for (var i = 0; i < entries.length; i++) - { - var entry = entries[i]; - var entryItem = this.renderEntryItem(entry); - - entriesContainer.append(entryItem); - } - }; - - this.renderEntryItem = function(entry) - { - var formattedDuration = convertToTimesheetDurationFormat(entry.duration); - var timesheetEntryDateLink = $this.createLinkToTimesheetDay(entry.date, formattedDuration); - - var entryItem = - '' + - '' + - '' + - 'You ' + - 'tracked ' + - timesheetEntryDateLink + - '' + - '' + - moment(entry.date).format("MMM D") + - ' at ' + - moment(entry.end_time_formatted, "HH:mm").format("h:mm a") + - '' + - '' + - ''; - - return entryItem; - }; - - this.createLinkToTimesheetDay = function (date, anchorText) - { - var link = serverUrl + 'app#/timesheets/timer/' + date; - var htmlLink = '' + anchorText + ''; - return htmlLink; - }; - - this.handleShowTimer = function() - { - $this.button.css('background', '#ff3c00'); - $this.button.find('.text').css('display','none'); - $this.button.find('.fa-play').css('display','none'); - $this.button.find('.fa-stop').css('display','inline-block'); - }; - - this.handleHideTimer = function () - { - $this.button.find('.fa-stop').css('display','none'); - $this.button.find('.fa-play').css('display','inline-block'); - $this.button.find('.text').css('display','inline-block'); - $this.button.css('background', '#4bb063'); - }; - - this.bindEvents(this); -} - - - -$(document).ready(function () { - ClickupTimer.prototype = new TimerBase(); - timer = new ClickupTimer(); -}); - -Service = "clickup"; diff --git a/styles/sites/clickup.css b/styles/sites/clickup.css deleted file mode 100644 index e1f7af7..0000000 --- a/styles/sites/clickup.css +++ /dev/null @@ -1,70 +0,0 @@ -.tc-sidebar { - display: none !important; -} - -#tc-logo { - vertical-align: middle; - margin-top: -1px; - padding: 0; -} - -#timecamp-track-button { - margin-left: 15px; - height: 35px; - width: 140px; - overflow: hidden; - border-radius: 3px; - background-color: #4bb063; -} - -.fa { - color: #ffffff; - margin-right: 3px; - margin-left: 10px; - margin-top: 9px; - font-size: 18px; - display: inline-block; -} - -#timecamp-track-button .text { - vertical-align: middle; - margin-bottom: 4px; - margin-left: 6px; - display: inline-block; - color: #ffffff !important; - font-size: 15px; - font-weight: 300; - text-transform: uppercase; -} - -#timecamp-track-button .time { - font-size: 15px; - display: block; - position: relative; - margin-top: -16px; - padding-left: 55px; - color: #ffffff !important; -} - -#tc-badge { - padding: 1px 4px; - height: 14px; -} - -#tc-integration-link { - margin-top: 5px; -} - -.tc-button-cont { - display: inline; - cursor: pointer; -} - -.button-link { - cursor: pointer; - vertical-align: middle; - display: inline-block; - padding: 0px 0px 0px 5px; -} - - From 8d807ea0c771fd3e6645e655bc1b8eac1d9586ae Mon Sep 17 00:00:00 2001 From: bpDevTc <104766829+bpDevTc@users.noreply.github.com> Date: Tue, 18 Aug 2026 09:06:19 +0200 Subject: [PATCH 2/2] [BP-28] Version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f36a0d5..ed520de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "timecamp-chrome-extension", - "version": "3.145.0", + "version": "3.145.28", "description": "TimeCamp Google Chrome Time Tracking Extension", "main": "index.js", "scripts": {