Skip to content

Instantly share code, notes, and snippets.

@mtib
Last active April 19, 2023 12:56
Show Gist options
  • Select an option

  • Save mtib/b64391657cab1cffdb6447e0de76caf1 to your computer and use it in GitHub Desktop.

Select an option

Save mtib/b64391657cab1cffdb6447e0de76caf1 to your computer and use it in GitHub Desktop.

Revisions

  1. mtib revised this gist Apr 19, 2023. 1 changed file with 135 additions and 0 deletions.
    135 changes: 135 additions & 0 deletions AsanaAdditionsTampermonkey.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,135 @@
    // ==UserScript==
    // @name AsanaAdditions
    // @namespace http://tampermonkey.net/
    // @version 0.1
    // @description try to take over the world!
    // @author [email protected]
    // @match https://app.asana.com/*
    // @icon https://www.google.com/s2/favicons?sz=64&domain=asana.com
    // @grant none
    // ==/UserScript==

    (function() {
    'use strict';

    /**
    * @param {object} options
    * @param {string} options.key
    * @param {({ title, taskId }: { title: string; taskId: string; }) => { label: string; value: string; onClick?: () => void; }} options.toRow
    */
    const updateAsanaRow = (options) => {
    const { key } = options;
    const taskRegex = /^\/\d+(\/\S+)?\/(\d+|inbox)\/(\d+)/
    const taskMatch = taskRegex.exec(window.location.pathname);

    if (!taskMatch) {
    return;
    }

    const taskId = taskMatch[3];
    const tableElement = document.querySelector('.TaskPaneFields');
    const titleElement = document.querySelector('div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');

    if (!tableElement) {
    throw new Error('Cannot find required DOM elements: tableElement');
    }

    if (!titleElement) {
    throw new Error('Cannot find required DOM elements: titleElement');
    }

    const title = titleElement.innerHTML;

    const { label, value, onClick } = options.toRow({ title, taskId });

    const rootElementId = `boost-watched-${key}`;
    const existingRoot = document.getElementById(rootElementId);
    if (existingRoot && existingRoot.dataset.label === label && existingRoot.dataset.value === value) {
    return;
    } else if (existingRoot && existingRoot.parentElement) {
    existingRoot.parentElement.removeChild(existingRoot);
    }

    const addedRowElement = document.createElement('div');
    addedRowElement.id = rootElementId;
    addedRowElement.dataset.value = value;
    addedRowElement.dataset.label = label;
    addedRowElement.classList.add('LabeledRowStructure');

    const labelDiv1 = document.createElement('div');
    labelDiv1.classList.add('LabeledRowStructure-left');
    labelDiv1.style.width = '120px';
    addedRowElement.appendChild(labelDiv1);
    const labelDiv2 = document.createElement('div');
    labelDiv2.classList.add('LabeledRowStructure-labelContainer');
    labelDiv1.appendChild(labelDiv2);
    const labelLabel = document.createElement('label');
    labelLabel.classList.add('LabeledRowStructure-label');
    labelLabel.innerHTML = label;
    labelDiv2.appendChild(labelLabel);

    const valueDiv1 = document.createElement('div');
    valueDiv1.classList.add('LabeledRowStructure-right');
    addedRowElement.appendChild(valueDiv1);
    const valueDiv2 = document.createElement('div');
    valueDiv2.classList.add('LabeledRowStructure-content');
    valueDiv2.style.display = 'flex';
    valueDiv2.style.gap = '10px';
    valueDiv1.appendChild(valueDiv2);

    const follower = document.createElement('span');
    follower.style.color = '#272';

    const clickableBranchNameElement = document.createElement('span');
    clickableBranchNameElement.style.minWidth = '0px';
    clickableBranchNameElement.style.flexShrink = '1';
    clickableBranchNameElement.style.textOverflow = 'ellipsis';
    clickableBranchNameElement.style.whiteSpace = 'nowrap';
    clickableBranchNameElement.style.overflow = 'hidden';
    clickableBranchNameElement.innerHTML = value;
    if (onClick) {
    clickableBranchNameElement.style.cursor = 'pointer';
    clickableBranchNameElement.onclick = () => {
    onClick();
    follower.innerHTML = 'clicked!';
    }
    }
    valueDiv2.appendChild(clickableBranchNameElement);
    valueDiv2.appendChild(follower);

    tableElement.insertBefore(addedRowElement, tableElement.childNodes[tableElement.childNodes.length -1]);
    }

    const updateBranchName = () => {
    updateAsanaRow({
    key: 'boost-branch-id',
    toRow: ({ title, taskId }) => {
    const branchName = [...(title.toLocaleLowerCase().replace(/[^a-z0-9 ]/ig, '').split(' ').slice(0, 8)), taskId].join('-');
    return {
    label: 'Canonical branch',
    value: branchName,
    onClick: () => {
    navigator.clipboard.writeText(branchName);
    }
    }
    }
    })
    }

    const updateCatsay = () => {
    updateAsanaRow({ key: 'cat', toRow: ({title}) => {
    const url = new URL(`https://cataas.com/cat/says/${encodeURIComponent(title)}`);
    const imgElement = document.createElement('img');
    imgElement.src = url.href;
    imgElement.style.width = '100%';
    console.log(imgElement.outerHTML);
    return { label: 'Cat', value: imgElement.outerHTML };
    }});
    }

    window.setInterval(() => {
    updateBranchName();
    updateAsanaRow({ key: 'numberwang', toRow: () => ({ label: 'Numberwang', value: Math.random() })});
    updateCatsay();
    }, 1000);
    })();
  2. mtib revised this gist Apr 19, 2023. 1 changed file with 57 additions and 20 deletions.
    77 changes: 57 additions & 20 deletions annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,10 @@
    const addedElementRootIdentifier = 'boost-branch-id-row';

    const addBranchName = () => {
    // Example URL
    // https://app.asana.com/0/1201323259943344/1203874541847641
    // https://app.asana.com/0/1201323259943344/1203874541847641/f
    /**
    * @param {object} options
    * @param {string} options.key
    * @param {({ title, taskId }: { title: string; taskId: string; }) => { label: string; value: string; onClick?: () => void; }} options.toRow
    */
    const updateAsanaRow = (options) => {
    const { key } = options;
    const taskRegex = /^\/\d+(\/\S+)?\/(\d+|inbox)\/(\d+)/
    const taskMatch = taskRegex.exec(window.location.pathname);

    @@ -24,19 +25,21 @@ const addBranchName = () => {
    }

    const title = titleElement.innerHTML;
    const branchName = [...(title.toLocaleLowerCase().replace(/[^a-z0-9 ]/ig, '').split(' ').slice(0, 8)), taskId].join('-');

    const existingRoot = document.getElementById(addedElementRootIdentifier);
    if (existingRoot && existingRoot.dataset.title === title && existingRoot.dataset.branch === branchName) {
    const { label, value, onClick } = options.toRow({ title, taskId });

    const rootElementId = `boost-watched-${key}`;
    const existingRoot = document.getElementById(rootElementId);
    if (existingRoot && existingRoot.dataset.label === label && existingRoot.dataset.value === value) {
    return;
    } else if (existingRoot && existingRoot.parentElement) {
    existingRoot.parentElement.removeChild(existingRoot);
    }

    const addedRowElement = document.createElement('div');
    addedRowElement.id = addedElementRootIdentifier;
    addedRowElement.dataset.title = title;
    addedRowElement.dataset.branch = branchName;
    addedRowElement.id = rootElementId;
    addedRowElement.dataset.value = value;
    addedRowElement.dataset.label = label;
    addedRowElement.classList.add('LabeledRowStructure');

    const labelDiv1 = document.createElement('div');
    @@ -48,7 +51,7 @@ const addBranchName = () => {
    labelDiv1.appendChild(labelDiv2);
    const labelLabel = document.createElement('label');
    labelLabel.classList.add('LabeledRowStructure-label');
    labelLabel.innerHTML = 'Canonical branch';
    labelLabel.innerHTML = label;
    labelDiv2.appendChild(labelLabel);

    const valueDiv1 = document.createElement('div');
    @@ -64,23 +67,57 @@ const addBranchName = () => {
    follower.style.color = '#272';

    const clickableBranchNameElement = document.createElement('span');
    clickableBranchNameElement.style.cursor = 'pointer';
    clickableBranchNameElement.style.minWidth = '0px';
    clickableBranchNameElement.style.flexShrink = '1';
    clickableBranchNameElement.style.textOverflow = 'ellipsis';
    clickableBranchNameElement.style.whiteSpace = 'nowrap';
    clickableBranchNameElement.style.overflow = 'hidden';
    clickableBranchNameElement.innerHTML = branchName;
    clickableBranchNameElement.onclick = () => {
    navigator.clipboard.writeText(branchName);
    follower.innerHTML = 'copied!';
    clickableBranchNameElement.innerHTML = value;
    if (onClick) {
    clickableBranchNameElement.style.cursor = 'pointer';
    clickableBranchNameElement.onclick = () => {
    onClick();
    follower.innerHTML = 'clicked!';
    }
    }
    valueDiv2.appendChild(clickableBranchNameElement);
    valueDiv2.appendChild(follower);

    tableElement.insertBefore(addedRowElement, tableElement.childNodes[tableElement.childNodes.length -1]);
    }

    const updateBranchName = () => {
    updateAsanaRow({
    key: 'boost-branch-id',
    toRow: ({ title, taskId }) => {
    const branchName = [...(title.toLocaleLowerCase().replace(/[^a-z0-9 ]/ig, '').split(' ').slice(0, 8)), taskId].join('-');
    return {
    label: 'Canonical branch',
    value: branchName,
    onClick: () => {
    navigator.clipboard.writeText(branchName);
    }
    }
    }
    })
    }

    const updateCatsay = () => {
    updateAsanaRow({ key: 'cat', toRow: ({title}) => {
    const url = new URL(`https://cataas.com/cat/says/${encodeURIComponent(title)}`);
    const imgElement = document.createElement('img');
    imgElement.src = url.href;
    imgElement.style.width = '100%';
    console.log(imgElement.outerHTML);
    return { label: 'Cat', value: imgElement.outerHTML };
    }});
    }

    window.setInterval(() => {
    addBranchName();
    }, 1000);
    updateBranchName();
    updateAsanaRow({ key: 'numberwang', toRow: () => ({ label: 'Numberwang', value: Math.random() })});
    updateCatsay();
    }, 1000);



  3. mtib revised this gist Apr 18, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -4,14 +4,14 @@ const addBranchName = () => {
    // Example URL
    // https://app.asana.com/0/1201323259943344/1203874541847641
    // https://app.asana.com/0/1201323259943344/1203874541847641/f
    const taskRegex = /^\/\d+\/\d+\/(\d+)/
    const taskRegex = /^\/\d+(\/\S+)?\/(\d+|inbox)\/(\d+)/
    const taskMatch = taskRegex.exec(window.location.pathname);

    if (!taskMatch) {
    return;
    }

    const taskId = taskMatch[1];
    const taskId = taskMatch[3];
    const tableElement = document.querySelector('.TaskPaneFields');
    const titleElement = document.querySelector('div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');

  4. mtib revised this gist Apr 18, 2023. 1 changed file with 8 additions and 5 deletions.
    13 changes: 8 additions & 5 deletions annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -11,10 +11,6 @@ const addBranchName = () => {
    return;
    }

    if (document.getElementById(addedElementRootIdentifier)) {
    return;
    }

    const taskId = taskMatch[1];
    const tableElement = document.querySelector('.TaskPaneFields');
    const titleElement = document.querySelector('div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');
    @@ -28,7 +24,14 @@ const addBranchName = () => {
    }

    const title = titleElement.innerHTML;
    const branchName = [...(title.toLocaleLowerCase().replace(/[^a-z0-9 ]/ig, '').split(' ')), taskId].join('-');
    const branchName = [...(title.toLocaleLowerCase().replace(/[^a-z0-9 ]/ig, '').split(' ').slice(0, 8)), taskId].join('-');

    const existingRoot = document.getElementById(addedElementRootIdentifier);
    if (existingRoot && existingRoot.dataset.title === title && existingRoot.dataset.branch === branchName) {
    return;
    } else if (existingRoot && existingRoot.parentElement) {
    existingRoot.parentElement.removeChild(existingRoot);
    }

    const addedRowElement = document.createElement('div');
    addedRowElement.id = addedElementRootIdentifier;
  5. mtib revised this gist Apr 18, 2023. 1 changed file with 45 additions and 32 deletions.
    77 changes: 45 additions & 32 deletions annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -16,14 +16,11 @@ const addBranchName = () => {
    }

    const taskId = taskMatch[1];
    const titleElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea')
    || document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');
    const containerElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer');
    if (!containerElement) {
    throw new Error('Cannot find required DOM elements: containerElement');
    const tableElement = document.querySelector('.TaskPaneFields');
    const titleElement = document.querySelector('div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');

    if (!tableElement) {
    throw new Error('Cannot find required DOM elements: tableElement');
    }

    if (!titleElement) {
    @@ -35,34 +32,50 @@ const addBranchName = () => {

    const addedRowElement = document.createElement('div');
    addedRowElement.id = addedElementRootIdentifier;
    addedRowElement.style.marginBottom = '10px';
    addedRowElement.style.display = 'flex';
    addedRowElement.style.gap = '10px';
    addedRowElement.style.alignItems = 'center';
    addedRowElement.dataset.title = title;
    addedRowElement.dataset.branch = branchName;
    addedRowElement.classList.add('LabeledRowStructure');

    const buttonElement = document.createElement('button');
    const buttonElementBg = '#336';
    buttonElement.onmouseenter = () => {
    buttonElement.style.backgroundColor = '#447';
    }
    buttonElement.onmouseleave = () => {
    buttonElement.style.backgroundColor = buttonElementBg;
    }
    buttonElement.innerHTML = branchName;
    buttonElement.style.border = '1px solid #338';
    buttonElement.style.borderRadius = '4px';
    buttonElement.style.backgroundColor = buttonElementBg;
    buttonElement.style.padding = '3px 5px';
    buttonElement.onclick = () => {
    const labelDiv1 = document.createElement('div');
    labelDiv1.classList.add('LabeledRowStructure-left');
    labelDiv1.style.width = '120px';
    addedRowElement.appendChild(labelDiv1);
    const labelDiv2 = document.createElement('div');
    labelDiv2.classList.add('LabeledRowStructure-labelContainer');
    labelDiv1.appendChild(labelDiv2);
    const labelLabel = document.createElement('label');
    labelLabel.classList.add('LabeledRowStructure-label');
    labelLabel.innerHTML = 'Canonical branch';
    labelDiv2.appendChild(labelLabel);

    const valueDiv1 = document.createElement('div');
    valueDiv1.classList.add('LabeledRowStructure-right');
    addedRowElement.appendChild(valueDiv1);
    const valueDiv2 = document.createElement('div');
    valueDiv2.classList.add('LabeledRowStructure-content');
    valueDiv2.style.display = 'flex';
    valueDiv2.style.gap = '10px';
    valueDiv1.appendChild(valueDiv2);

    const follower = document.createElement('span');
    follower.style.color = '#272';

    const clickableBranchNameElement = document.createElement('span');
    clickableBranchNameElement.style.cursor = 'pointer';
    clickableBranchNameElement.style.minWidth = '0px';
    clickableBranchNameElement.style.flexShrink = '1';
    clickableBranchNameElement.style.textOverflow = 'ellipsis';
    clickableBranchNameElement.style.whiteSpace = 'nowrap';
    clickableBranchNameElement.style.overflow = 'hidden';
    clickableBranchNameElement.innerHTML = branchName;
    clickableBranchNameElement.onclick = () => {
    navigator.clipboard.writeText(branchName);
    follower.innerHTML = 'copied!';
    }
    valueDiv2.appendChild(clickableBranchNameElement);
    valueDiv2.appendChild(follower);

    const spanElement = document.createElement('span');
    spanElement.innerHTML = 'Recommended branch name:';

    addedRowElement.appendChild(spanElement);
    addedRowElement.appendChild(buttonElement);
    containerElement.appendChild(addedRowElement);
    tableElement.insertBefore(addedRowElement, tableElement.childNodes[tableElement.childNodes.length -1]);
    }

    window.setInterval(() => {
  6. mtib revised this gist Apr 18, 2023. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,8 @@ const addBranchName = () => {

    const taskId = taskMatch[1];
    const titleElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea')
    || document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');
    const containerElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer');
  7. mtib revised this gist Apr 18, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -19,8 +19,8 @@ const addBranchName = () => {
    const titleElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');
    const containerElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer');

    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer');
    if (!containerElement) {
    throw new Error('Cannot find required DOM elements: containerElement');
    }
  8. mtib created this gist Apr 18, 2023.
    69 changes: 69 additions & 0 deletions annotateAsanaTaskId.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    const addedElementRootIdentifier = 'boost-branch-id-row';

    const addBranchName = () => {
    // Example URL
    // https://app.asana.com/0/1201323259943344/1203874541847641
    // https://app.asana.com/0/1201323259943344/1203874541847641/f
    const taskRegex = /^\/\d+\/\d+\/(\d+)/
    const taskMatch = taskRegex.exec(window.location.pathname);

    if (!taskMatch) {
    return;
    }

    if (document.getElementById(addedElementRootIdentifier)) {
    return;
    }

    const taskId = taskMatch[1];
    const titleElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer > div.ObjectTitleInput.TaskPane-titleRow.TaskPane-titleRowInput > div > textarea');
    const containerElement = document.querySelector('#asana_full_page > div.FocusModePage > div > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer')
    || document.querySelector('#asana_main_page > div.ProjectPage > div.ProjectPage-board > div > div > div > div.FullWidthPageStructureWithDetailsOverlay-detailsOverlay.FullWidthPageStructureWithDetailsOverlay-detailsOverlay--visible > article > div.UploadDropTargetAttachmentWrappingTextEditor.TaskPane-attachmentDropTarget > div.DynamicBorderScrollable.DynamicBorderScrollable--canScrollDown.TaskPane-scrollable > div > div > div.TaskPane-resizeListenerContainer');

    if (!containerElement) {
    throw new Error('Cannot find required DOM elements: containerElement');
    }

    if (!titleElement) {
    throw new Error('Cannot find required DOM elements: titleElement');
    }

    const title = titleElement.innerHTML;
    const branchName = [...(title.toLocaleLowerCase().replace(/[^a-z0-9 ]/ig, '').split(' ')), taskId].join('-');

    const addedRowElement = document.createElement('div');
    addedRowElement.id = addedElementRootIdentifier;
    addedRowElement.style.marginBottom = '10px';
    addedRowElement.style.display = 'flex';
    addedRowElement.style.gap = '10px';
    addedRowElement.style.alignItems = 'center';

    const buttonElement = document.createElement('button');
    const buttonElementBg = '#336';
    buttonElement.onmouseenter = () => {
    buttonElement.style.backgroundColor = '#447';
    }
    buttonElement.onmouseleave = () => {
    buttonElement.style.backgroundColor = buttonElementBg;
    }
    buttonElement.innerHTML = branchName;
    buttonElement.style.border = '1px solid #338';
    buttonElement.style.borderRadius = '4px';
    buttonElement.style.backgroundColor = buttonElementBg;
    buttonElement.style.padding = '3px 5px';
    buttonElement.onclick = () => {
    navigator.clipboard.writeText(branchName);
    }

    const spanElement = document.createElement('span');
    spanElement.innerHTML = 'Recommended branch name:';

    addedRowElement.appendChild(spanElement);
    addedRowElement.appendChild(buttonElement);
    containerElement.appendChild(addedRowElement);
    }

    window.setInterval(() => {
    addBranchName();
    }, 1000);