Skip to content

Commit

Permalink
fix(asana): tags and projects selectors (#2320)
Browse files Browse the repository at this point in the history
* feat(config): add prettier config

* chore(asana): code style fixes apply

* fix(asana): spreadsheet selector on projects and tags

* fix(asana): tags & projects resolvers in board view

closes: #2321
closes: #2317
  • Loading branch information
askides authored Aug 13, 2024
1 parent 2d5afd3 commit 37697b5
Show file tree
Hide file tree
Showing 4 changed files with 545 additions and 82 deletions.
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@
"description": "Add Toggl Track one-click time tracking to popular web tools.",
"license": "Apache-2.0",
"main": "src/origins.js",
"types": "src/index.d.ts"
"types": "src/index.d.ts",
"devDependencies": {
"@toggl/prettier": "^1.1.0",
"prettier": "^3.3.3",
"prettier-plugin-jsdoc": "^1.3.0"
}
}
1 change: 1 addition & 0 deletions prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@toggl/prettier')
184 changes: 103 additions & 81 deletions src/content/asana.js
Original file line number Diff line number Diff line change
@@ -1,171 +1,193 @@
/**
* @name Asana
* @urlAlias app.asana.com
* @urlAlias app.asana.com
* @urlRegex *://app.asana.com/*
*/
'use strict';
'use strict'

const projectHeaderSelector = () => {
// Try to look for for page project title instead.
const projectHeader = document.querySelector(
'.ProjectPageHeaderProjectTitle-container',
);
)

if (!projectHeader) {
return '';
return ''
}
return projectHeader.textContent
.replace(/\u00a0/g, ' ') // There can be   in Asana header content
.trim();
};
.trim()
}

// Board view. Inserts button next to assignee/due date.
togglbutton.render('.BoardCardLayout:not(.toggl)', { observe: true },
boadCardElem => {
togglbutton.render(
'.BoardCardLayout:not(.toggl)',
{ observe: true },
(boadCardElem) => {
if (boadCardElem.querySelector('.toggl-button')) {
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
return;
return
}

const descriptionSelector = () => boadCardElem.querySelector('.BoardCard-taskName').textContent.trim();

const descriptionSelector = () =>
boadCardElem.querySelector('.BoardCard-taskName').textContent.trim()

const link = togglbutton.createTimerLink({
className: 'asana-board-view',
description: descriptionSelector,
buttonType: 'minimal',
projectName: projectHeaderSelector,
// N.B. Tags cannot be supported on board view as the information is not available.
});
})

const injectContainer = boadCardElem.querySelector('.BoardCardLayout-actionButtons');
const injectContainer = boadCardElem.querySelector(
'.BoardCardLayout-actionButtons',
)
if (injectContainer) {
injectContainer.insertAdjacentElement('afterbegin', link);
injectContainer.insertAdjacentElement('afterbegin', link)
}
}
);
},
)

// Spreadsheet view. Inserts button next to to the task name.
togglbutton.render('.SpreadsheetRow .SpreadsheetTaskName:not(.toggl)', { observe: true },
togglbutton.render(
'.SpreadsheetRow .SpreadsheetTaskName:not(.toggl)',
{ observe: true },
function (taskNameCell) {
const container = taskNameCell.closest('.SpreadsheetRow');
const container = taskNameCell.closest('.SpreadsheetRow')

if (container.querySelector('.toggl-button')) {
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
return;
return
}

const descriptionSelector = () => taskNameCell.querySelector('textarea').textContent.trim();
const descriptionSelector = () =>
taskNameCell.querySelector('textarea').textContent.trim()

const projectSelector = () => {
const projectCell = container.querySelector('.SpreadsheetTaskRow-projectsCell');
const projectCell = container.querySelector(
'.SpreadsheetTaskRow-projectsCell',
)
if (!projectCell) {
// Try to look for for page project title instead.
return projectHeaderSelector();
return projectHeaderSelector()
}

// There can be multiple projects, but we can't support trying to match multiple yet.
const firstProject = projectCell.querySelector('.Pill');
return firstProject ? firstProject.textContent.trim() : projectHeaderSelector();
};
const firstProject = projectCell.querySelector(
'.SpreadsheetPotsCell-potPill',
)
return firstProject
? firstProject.textContent.trim()
: projectHeaderSelector()
}

const tagsSelector = () => {
const tags = container.querySelectorAll('.SpreadsheetTaskRow-tagsCell .Pill');
return [...tags].map(tag => tag.textContent.trim());
};
const tags = container.querySelectorAll(
'.SpreadsheetTaskRow-tagsCell .SpreadsheetPotsCell-potPill',
)
return [...tags].map((tag) => tag.textContent.trim())
}

const link = togglbutton.createTimerLink({
className: 'asana-spreadsheet',
description: descriptionSelector,
projectName: projectSelector,
tags: tagsSelector,
buttonType: 'minimal'
});
buttonType: 'minimal',
})

taskNameCell.insertAdjacentElement('afterend', link);
}
);
taskNameCell.insertAdjacentElement('afterend', link)
},
)

// 2020 My Tasks view, possibly other similar views.
togglbutton.render('.MyTasksTaskRow:not(.toggl)', { observe: true },
togglbutton.render(
'.MyTasksTaskRow:not(.toggl)',
{ observe: true },
function (elem) {
if (elem.querySelector('.toggl-button')) {
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
return;
return
}
const descriptionSelector = () => elem.querySelector('.TaskName textarea').textContent;
const descriptionSelector = () =>
elem.querySelector('.TaskName textarea').textContent

// attempt at separating projects and tags, which are not differentiated in the dom
// assume first pill is a project and any others are tags
// misses tags which are in the "..." overflow, and if there is a tag without a project
const pillSelector = (type) => {
const pills = [...elem.querySelectorAll('.Pill')]
.map(pill => pill.textContent.trim());
const pills = [...elem.querySelectorAll('.Pill')].map((pill) =>
pill.textContent.trim(),
)
if (type === 'project') {
return pills.length ? pills : '';
return pills.length ? pills : ''
} else if (type === 'tags') {
return pills.length > 1 ? pills.slice(1) : [];
return pills.length > 1 ? pills.slice(1) : []
}
};
}

const projectSelector = () => {
return pillSelector('project');
};
return pillSelector('project')
}

const tagsSelector = () => {
return pillSelector('tags');
};
return pillSelector('tags')
}

const link = togglbutton.createTimerLink({
className: 'asana-new-ui',
description: descriptionSelector,
projectName: projectSelector,
tags: tagsSelector,
buttonType: 'minimal'
});
buttonType: 'minimal',
})

const wrapper = document.createElement('div');
wrapper.style.margin = '3px 0 0 4px';
wrapper.appendChild(link);
const wrapper = document.createElement('div')
wrapper.style.margin = '3px 0 0 4px'
wrapper.appendChild(link)

elem.appendChild(wrapper);
}
);
elem.appendChild(wrapper)
},
)

// Task detail. My Tasks, Spreadsheet, Board, ...
togglbutton.render('.TaskPane:not(.toggl)', { observe: true },
taskPaneEl => {
if (taskPaneEl.querySelector('.toggl-button')) {
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
return;
}
togglbutton.render('.TaskPane:not(.toggl)', { observe: true }, (taskPaneEl) => {
if (taskPaneEl.querySelector('.toggl-button')) {
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
return
}

const descriptionSelector = () => taskPaneEl.querySelector('.TaskPaneTitle textarea').textContent.trim();
const descriptionSelector = () =>
taskPaneEl.querySelector('.TaskPaneTitle textarea').textContent.trim()

const projectSelector = () => {
const projectElement = taskPaneEl.querySelector('.TokenizerPillBase-name');
if (!projectElement) return '';
const projectSelector = () => {
const projectElement = taskPaneEl.querySelector(
'.TaskProjectTokenPill-tokenPillWrapper .TaskProjects-projectTokenPill span',
)
if (!projectElement) return ''

return projectElement.textContent.trim();
};
return projectElement.textContent.trim()
}

const tagsSelector = () => {
const tags = taskPaneEl.querySelectorAll('.TokenizerPillBase-name');
return [...tags].map(tag => tag.textContent.trim());
}
const tagsSelector = () => {
const tags = taskPaneEl.querySelectorAll('.TaskTagTokenPills-potPill span')
return [...tags].map((tag) => tag.textContent.trim())
}

const link = togglbutton.createTimerLink({
className: 'TaskPaneToolbar-button',
description: descriptionSelector,
projectName: projectSelector,
buttonType: 'minimal',
tags: tagsSelector
});
const link = togglbutton.createTimerLink({
className: 'TaskPaneToolbar-button',
description: descriptionSelector,
projectName: projectSelector,
buttonType: 'minimal',
tags: tagsSelector,
})

const injectContainer = taskPaneEl.querySelector('.TaskPaneExtraActionsButton');
const injectContainer = taskPaneEl.querySelector(
'.TaskPaneExtraActionsButton',
)

if (injectContainer) {
injectContainer.parentNode.insertBefore(link, injectContainer.nextSibling);
}
if (injectContainer) {
injectContainer.parentNode.insertBefore(link, injectContainer.nextSibling)
}
);
})
Loading

0 comments on commit 37697b5

Please sign in to comment.