Skip to content

Commit 37697b5

Browse files
authored
fix(asana): tags and projects selectors (#2320)
* 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
1 parent 2d5afd3 commit 37697b5

File tree

4 files changed

+545
-82
lines changed

4 files changed

+545
-82
lines changed

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
"description": "Add Toggl Track one-click time tracking to popular web tools.",
66
"license": "Apache-2.0",
77
"main": "src/origins.js",
8-
"types": "src/index.d.ts"
8+
"types": "src/index.d.ts",
9+
"devDependencies": {
10+
"@toggl/prettier": "^1.1.0",
11+
"prettier": "^3.3.3",
12+
"prettier-plugin-jsdoc": "^1.3.0"
13+
}
914
}

prettier.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('@toggl/prettier')

src/content/asana.js

Lines changed: 103 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,171 +1,193 @@
11
/**
22
* @name Asana
3-
* @urlAlias app.asana.com
3+
* @urlAlias app.asana.com
44
* @urlRegex *://app.asana.com/*
55
*/
6-
'use strict';
6+
'use strict'
77

88
const projectHeaderSelector = () => {
99
// Try to look for for page project title instead.
1010
const projectHeader = document.querySelector(
1111
'.ProjectPageHeaderProjectTitle-container',
12-
);
12+
)
1313

1414
if (!projectHeader) {
15-
return '';
15+
return ''
1616
}
1717
return projectHeader.textContent
1818
.replace(/\u00a0/g, ' ') // There can be   in Asana header content
19-
.trim();
20-
};
19+
.trim()
20+
}
2121

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

30-
const descriptionSelector = () => boadCardElem.querySelector('.BoardCard-taskName').textContent.trim();
31-
32+
const descriptionSelector = () =>
33+
boadCardElem.querySelector('.BoardCard-taskName').textContent.trim()
3234

3335
const link = togglbutton.createTimerLink({
3436
className: 'asana-board-view',
3537
description: descriptionSelector,
3638
buttonType: 'minimal',
3739
projectName: projectHeaderSelector,
3840
// N.B. Tags cannot be supported on board view as the information is not available.
39-
});
41+
})
4042

41-
const injectContainer = boadCardElem.querySelector('.BoardCardLayout-actionButtons');
43+
const injectContainer = boadCardElem.querySelector(
44+
'.BoardCardLayout-actionButtons',
45+
)
4246
if (injectContainer) {
43-
injectContainer.insertAdjacentElement('afterbegin', link);
47+
injectContainer.insertAdjacentElement('afterbegin', link)
4448
}
45-
}
46-
);
49+
},
50+
)
4751

4852
// Spreadsheet view. Inserts button next to to the task name.
49-
togglbutton.render('.SpreadsheetRow .SpreadsheetTaskName:not(.toggl)', { observe: true },
53+
togglbutton.render(
54+
'.SpreadsheetRow .SpreadsheetTaskName:not(.toggl)',
55+
{ observe: true },
5056
function (taskNameCell) {
51-
const container = taskNameCell.closest('.SpreadsheetRow');
57+
const container = taskNameCell.closest('.SpreadsheetRow')
5258

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

58-
const descriptionSelector = () => taskNameCell.querySelector('textarea').textContent.trim();
64+
const descriptionSelector = () =>
65+
taskNameCell.querySelector('textarea').textContent.trim()
5966

6067
const projectSelector = () => {
61-
const projectCell = container.querySelector('.SpreadsheetTaskRow-projectsCell');
68+
const projectCell = container.querySelector(
69+
'.SpreadsheetTaskRow-projectsCell',
70+
)
6271
if (!projectCell) {
6372
// Try to look for for page project title instead.
64-
return projectHeaderSelector();
73+
return projectHeaderSelector()
6574
}
6675

6776
// There can be multiple projects, but we can't support trying to match multiple yet.
68-
const firstProject = projectCell.querySelector('.Pill');
69-
return firstProject ? firstProject.textContent.trim() : projectHeaderSelector();
70-
};
77+
const firstProject = projectCell.querySelector(
78+
'.SpreadsheetPotsCell-potPill',
79+
)
80+
return firstProject
81+
? firstProject.textContent.trim()
82+
: projectHeaderSelector()
83+
}
7184

7285
const tagsSelector = () => {
73-
const tags = container.querySelectorAll('.SpreadsheetTaskRow-tagsCell .Pill');
74-
return [...tags].map(tag => tag.textContent.trim());
75-
};
86+
const tags = container.querySelectorAll(
87+
'.SpreadsheetTaskRow-tagsCell .SpreadsheetPotsCell-potPill',
88+
)
89+
return [...tags].map((tag) => tag.textContent.trim())
90+
}
7691

7792
const link = togglbutton.createTimerLink({
7893
className: 'asana-spreadsheet',
7994
description: descriptionSelector,
8095
projectName: projectSelector,
8196
tags: tagsSelector,
82-
buttonType: 'minimal'
83-
});
97+
buttonType: 'minimal',
98+
})
8499

85-
taskNameCell.insertAdjacentElement('afterend', link);
86-
}
87-
);
100+
taskNameCell.insertAdjacentElement('afterend', link)
101+
},
102+
)
88103

89104
// 2020 My Tasks view, possibly other similar views.
90-
togglbutton.render('.MyTasksTaskRow:not(.toggl)', { observe: true },
105+
togglbutton.render(
106+
'.MyTasksTaskRow:not(.toggl)',
107+
{ observe: true },
91108
function (elem) {
92109
if (elem.querySelector('.toggl-button')) {
93110
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
94-
return;
111+
return
95112
}
96-
const descriptionSelector = () => elem.querySelector('.TaskName textarea').textContent;
113+
const descriptionSelector = () =>
114+
elem.querySelector('.TaskName textarea').textContent
97115

98116
// attempt at separating projects and tags, which are not differentiated in the dom
99117
// assume first pill is a project and any others are tags
100118
// misses tags which are in the "..." overflow, and if there is a tag without a project
101119
const pillSelector = (type) => {
102-
const pills = [...elem.querySelectorAll('.Pill')]
103-
.map(pill => pill.textContent.trim());
120+
const pills = [...elem.querySelectorAll('.Pill')].map((pill) =>
121+
pill.textContent.trim(),
122+
)
104123
if (type === 'project') {
105-
return pills.length ? pills : '';
124+
return pills.length ? pills : ''
106125
} else if (type === 'tags') {
107-
return pills.length > 1 ? pills.slice(1) : [];
126+
return pills.length > 1 ? pills.slice(1) : []
108127
}
109-
};
128+
}
110129

111130
const projectSelector = () => {
112-
return pillSelector('project');
113-
};
131+
return pillSelector('project')
132+
}
114133

115134
const tagsSelector = () => {
116-
return pillSelector('tags');
117-
};
135+
return pillSelector('tags')
136+
}
118137

119138
const link = togglbutton.createTimerLink({
120139
className: 'asana-new-ui',
121140
description: descriptionSelector,
122141
projectName: projectSelector,
123142
tags: tagsSelector,
124-
buttonType: 'minimal'
125-
});
143+
buttonType: 'minimal',
144+
})
126145

127-
const wrapper = document.createElement('div');
128-
wrapper.style.margin = '3px 0 0 4px';
129-
wrapper.appendChild(link);
146+
const wrapper = document.createElement('div')
147+
wrapper.style.margin = '3px 0 0 4px'
148+
wrapper.appendChild(link)
130149

131-
elem.appendChild(wrapper);
132-
}
133-
);
150+
elem.appendChild(wrapper)
151+
},
152+
)
134153

135154
// Task detail. My Tasks, Spreadsheet, Board, ...
136-
togglbutton.render('.TaskPane:not(.toggl)', { observe: true },
137-
taskPaneEl => {
138-
if (taskPaneEl.querySelector('.toggl-button')) {
139-
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
140-
return;
141-
}
155+
togglbutton.render('.TaskPane:not(.toggl)', { observe: true }, (taskPaneEl) => {
156+
if (taskPaneEl.querySelector('.toggl-button')) {
157+
// Due to the way this UI is rendered, we must check for existence of old buttons manually.
158+
return
159+
}
142160

143-
const descriptionSelector = () => taskPaneEl.querySelector('.TaskPaneTitle textarea').textContent.trim();
161+
const descriptionSelector = () =>
162+
taskPaneEl.querySelector('.TaskPaneTitle textarea').textContent.trim()
144163

145-
const projectSelector = () => {
146-
const projectElement = taskPaneEl.querySelector('.TokenizerPillBase-name');
147-
if (!projectElement) return '';
164+
const projectSelector = () => {
165+
const projectElement = taskPaneEl.querySelector(
166+
'.TaskProjectTokenPill-tokenPillWrapper .TaskProjects-projectTokenPill span',
167+
)
168+
if (!projectElement) return ''
148169

149-
return projectElement.textContent.trim();
150-
};
170+
return projectElement.textContent.trim()
171+
}
151172

152-
const tagsSelector = () => {
153-
const tags = taskPaneEl.querySelectorAll('.TokenizerPillBase-name');
154-
return [...tags].map(tag => tag.textContent.trim());
155-
}
173+
const tagsSelector = () => {
174+
const tags = taskPaneEl.querySelectorAll('.TaskTagTokenPills-potPill span')
175+
return [...tags].map((tag) => tag.textContent.trim())
176+
}
156177

157-
const link = togglbutton.createTimerLink({
158-
className: 'TaskPaneToolbar-button',
159-
description: descriptionSelector,
160-
projectName: projectSelector,
161-
buttonType: 'minimal',
162-
tags: tagsSelector
163-
});
178+
const link = togglbutton.createTimerLink({
179+
className: 'TaskPaneToolbar-button',
180+
description: descriptionSelector,
181+
projectName: projectSelector,
182+
buttonType: 'minimal',
183+
tags: tagsSelector,
184+
})
164185

165-
const injectContainer = taskPaneEl.querySelector('.TaskPaneExtraActionsButton');
186+
const injectContainer = taskPaneEl.querySelector(
187+
'.TaskPaneExtraActionsButton',
188+
)
166189

167-
if (injectContainer) {
168-
injectContainer.parentNode.insertBefore(link, injectContainer.nextSibling);
169-
}
190+
if (injectContainer) {
191+
injectContainer.parentNode.insertBefore(link, injectContainer.nextSibling)
170192
}
171-
);
193+
})

0 commit comments

Comments
 (0)