Skip to content

Commit

Permalink
Merge Chrome into firefox (#24)
Browse files Browse the repository at this point in the history
* chrome 1.3 and update readme with video

* New Tab Checkbox (#17)

* Add files via upload

* Add files via upload

* New Checkbox, Save Shaded

* add new site url for manifest

* Removed workspace. Updated readme to add Jen and review her changes.

* Update readme and fixed typo in contentjs for storage and added placeholders

* readme

* Create LICENSE (#19)

* Update LICENSE (#21)

* update manifest version

---------

Co-authored-by: Jennifer Olson <[email protected]>
  • Loading branch information
walters954 and knuckles4ever authored Nov 25, 2024
1 parent b3f6f44 commit 842547f
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 60 deletions.
28 changes: 28 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
BSD 3-Clause License

Copyright (c) 2024, Warren Walters

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
# why-salesforce

This extension allows users to create custom tabs in Setup for their most-used settings

[Demo Video](https://youtu.be/BtlKRvac9ZQ)

[Install on Chrome Web Store](https://chrome.google.com/webstore/detail/why-salesforce/ghakkjfjpnhpggbkfkeplbefkipfoaod)

### Roadmap

- [x] Ability to customize tab
- [x] Salesforce SLDS
- Feedback on save and delete
- Update tabs onSave without refresh
- Disable save button if tabs list empty
- [x] Salesforce SLDS
- [ ] Feedback on save and delete
- [ ] Update tabs onSave without refresh
- [x] Disable save button if tabs list empty
- [ ] Reorder tabs
- [x] Minify SLDS files
- Dark mode for flows
- Org specific tab customization
- Highlight tab when user is on that url
- Open full urls in new tab
- Better solutions for waiting until Salesforce setup is completely loaded
- Utils class for templates or other shared code
- [ ] Dark mode for flows
- [ ] Org specific tab customization
- [ ] Highlight tab when user is on that url
- [x] Open full urls in new tab
- [ ] Better solutions for waiting until Salesforce setup is completely loaded
- [ ] Utils class for templates or other shared code

Contributors

- [Warren Walters](https://www.linkedin.com/in/walters954/)
- [Chris Rouse (Firefox port)](https://www.linkedin.com/in/chris-rouse/)
- [Chris Rouse (Firefox port)](https://www.linkedin.com/in/chris-rouse/)
- [Jennifer Olson](https://www.linkedin.com/in/olsonjenn05/)
65 changes: 44 additions & 21 deletions content.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,84 @@
const storageKey = 'sfmWhySF';

function init(setupTabUl){
if (setupTabUl){
function init(setupTabUl) {
if (setupTabUl) {
let rows = [];

browser.storage.sync.get([storageKey], function(items) {
let rowObj = items[storageKey];
const rowObj = items[storageKey] || [];

if (!rowObj) { //Did not find data inside browser storage
rowObj = initTabs();
}

for (const rowId in rowObj) {
let row = rowObj[rowId];
rows.push(generateRowTemplate(row.tabTitle,row.url))
rows.push(generateRowTemplate(row.tabTitle, row.url, row.openInNewTab));
}
setupTabUl.insertAdjacentHTML('beforeend', rows.join(''));

// Add click event listeners after rows are inserted
addClickEventListeners();
});

}
}

function delayLoadSetupTabs(count) {
const setupTabUl = document.getElementsByClassName("tabBarItems slds-grid")[0];
const setupTabUl = document.getElementsByClassName("tabBarItems slds-grid")[0];
count++;

if (count > 5){
if (count > 5) {
console.log('Why Salesforce - failed to find setup tab.');
return;
}

if (!setupTabUl) {
setTimeout(function() { delayLoadSetupTabs(0); }, 3000);
setTimeout(function() { delayLoadSetupTabs(count); }, 3000); // Fixed to pass count correctly
} else {
init(setupTabUl);
}
}

setTimeout(function() { delayLoadSetupTabs(0); }, 3000);


function generateRowTemplate(tabTitle, url){
return `<li role="presentation" style="" class="oneConsoleTabItem tabItem slds-context-bar__item borderRight navexConsoleTabItem" data-aura-class="navexConsoleTabItem">
<a role="tab" tabindex="-1" title="${tabTitle}" aria-selected="false" href="${url}" class="tabHeader slds-context-bar__label-action " >
<span class="title slds-truncate" >${tabTitle}</span>
</a>
</li>`
function generateRowTemplate(tabTitle, url, openInNewTab) {
const target = openInNewTab ? '_blank' : '_self';
return `<li role="presentation" class="oneConsoleTabItem tabItem slds-context-bar__item borderRight navexConsoleTabItem" data-aura-class="navexConsoleTabItem" data-url="${url}">
<a role="tab" tabindex="-1" title="${tabTitle}" aria-selected="false" href="${url}" target="${target}" class="tabHeader slds-context-bar__label-action">
<span class="title slds-truncate">${tabTitle}</span>
</a>
</li>`;
}

function initTabs(){
function initTabs() {
let tabs = [
{tabTitle : 'Flow', url: '/lightning/setup/Flows/home'},
{tabTitle : 'User', url: '/lightning/setup/ManageUsers/home'}
]
{ tabTitle: 'Home', url: '/', openInNewTab: false },
{ tabTitle: 'Flow', url: '/lightning/setup/Flows/home', openInNewTab: true },
{ tabTitle: 'User', url: '/lightning/setup/ManageUsers/home', openInNewTab: false }
];

browser.storage.sync.set({ storageKey: tabs }, function() {

browser.storage.sync.set({storageKey: tabs}, function() {
//TODO combine with popup.js with background service
});

return tabs;
}
}

function addClickEventListeners() {
chrome.storage.sync.get([storageKey], function(items) {
const rowObj = items[storageKey] || [];
for (const rowId in rowObj) {
let tab = rowObj[rowId];
document.querySelectorAll(`a[href="${tab.url}"]`).forEach(link => {
link.addEventListener('click', function(event) {
if (tab.openInNewTab) {
event.preventDefault();
window.open(tab.url, '_blank');
}
});
});
}
});
}

2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Why Salesforce",
"version": "1.0",
"version": "1.4",
"permissions": ["storage"],
"description": "Stuff that Salesforce should have added already... Adding flow and user tabs into setup.",
"homepage_url": "https://github.com/walters954/why-salesforce/tree/firefox",
Expand Down
45 changes: 22 additions & 23 deletions popup.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./popup.css"/>
<link rel="stylesheet" href="./assets/salesforce-lightning-design-system.min.css"/>
</head>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./popup.css">
<link rel="stylesheet" href="./assets/salesforce-lightning-design-system.min.css">
<title>Tab Manager</title>
</head>
<body class="slds-p-around_none">
<article class="slds-card">
<div class="slds-card__header slds-grid">
<header class="slds-media slds-media_center slds-has-flexi-truncate">
<div class="slds-media__figure">
<span class="slds-icon_container" title="Why Salesforce">
<img src="./images/whysf32.png"/>
<img src="./images/whysf32.png" alt="Why Salesforce">
<span class="slds-assistive-text">Why Salesforce</span>
</span>
</div>
Expand All @@ -32,18 +33,22 @@ <h2 class="slds-card__header-title">
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<thead>
<tr>
<th class="" scope="col">
<th scope="col">
<div title="Tab Name">Tab Name</div>
</th>
<th scope="col">
<div title="Tab URL">Tab URL</div>
</th>
<th scope="col" style="width: 3.25rem">
<div title="Open in New Tab">New Tab</div>
</th>
<th scope="col" style="width: 3.25rem">
<div class="slds-assistive-text" title="Actions">Actions</div>
</th>
</tr>
</thead>
<tbody class="tabs">
<!-- Rows will be dynamically added here -->
</tbody>
</table>
</div>
Expand All @@ -53,24 +58,18 @@ <h2 class="slds-card__header-title">
<tr class="tab">
<td data-label="Tab Name" scope="row">
<div class="slds-form-element__control">
<input
type="text"
name="tabTitle"
class="tabTitle slds-input"
placeholder="Flow"
/>
</div>
<input type="text" name="tabTitle" class="tabTitle slds-input" placeholder="Flow">
</div>
</td>
<td data-label="Tab URL">
<div class="slds-form-element__control">
<input
type="url"
name="url"
class="url slds-input"
placeholder="/lightning/setup/Flows/home"
/>
<input type="url" name="url" class="url slds-input" placeholder="/lightning/setup/Flows/home">
</div>
</td>
<td data-label="New Tab">
<div class="slds-form-element__control">
<input type="checkbox" name="openInNewTab" class="openInNewTab slds-checkbox">
</div>

</td>
<td>
<button class="delete slds-button slds-button_destructive">Delete</button>
Expand Down
20 changes: 16 additions & 4 deletions popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,28 @@ function loadTabs(){
const elements = new Set();

browser.storage.sync.get(['sfmWhySF'], function(items) {
const rowObj = items['sfmWhySF'];
const rowObj = items['sfmWhySF'] || [];

for (const rowId in rowObj) {
let tab = rowObj[rowId];
const element = template.content.firstElementChild.cloneNode(true);
element.querySelector(".tabTitle").value = tab.tabTitle;
element.querySelector(".url").value = tab.url;
element.querySelector(".openInNewTab").checked = tab.openInNewTab || false;
element.querySelector(".delete").addEventListener("click", deleteTab);
elements.add(element);
}
document.querySelector(tabAppendElement).append(...elements);
updateSaveButtonState();
});

}

function addTab(){
const template = document.getElementById(tabTemplate);
const element = template.content.firstElementChild.cloneNode(true);
element.querySelector(".delete").addEventListener("click", deleteTab);
document.querySelector(tabAppendElement).append(element);
updateSaveButtonState();
}

function saveTab(){
Expand All @@ -40,9 +43,10 @@ function processTabs(){
Array.from(tabElements).forEach(function (tab) {
let tabTitle = tab.querySelector('.tabTitle').value;
let url = tab.querySelector('.url').value;
let openInNewTab = tab.querySelector('.openInNewTab').checked;

if (tabTitle && url){
tabs.push({tabTitle, url});
tabs.push({tabTitle, url, openInNewTab});
}
});
return tabs;
Expand All @@ -51,6 +55,7 @@ function processTabs(){
function deleteTab(){
this.closest(".tab").remove();
saveTab();
updateSaveButtonState();
}

function setBrowserStorage(tabs){
Expand All @@ -60,14 +65,18 @@ function setBrowserStorage(tabs){
});
}

function updateSaveButtonState() {
const saveButton = document.querySelector(".save");
const tabElements = document.getElementsByClassName('tab');
saveButton.disabled = tabElements.length === 0;
}

const saveButton = document.querySelector(".save");
saveButton.addEventListener("click", saveTab);

const addButton = document.querySelector(".add");
addButton.addEventListener("click", addTab);


function clearBrowserStorage(){
browser.storage.sync.remove(["sfmWhySF"],function(){
var error = browser.runtime.lastError;
Expand All @@ -76,3 +85,6 @@ function clearBrowserStorage(){
}
})
}

// Initial check to set the state of the save button
updateSaveButtonState();

0 comments on commit 842547f

Please sign in to comment.