Skip to content

Instantly share code, notes, and snippets.

@SanderBreivik
Last active March 10, 2025 07:30
Show Gist options
  • Save SanderBreivik/30cfd5b378c5e8db36acf76c4e33bf1b to your computer and use it in GitHub Desktop.
Save SanderBreivik/30cfd5b378c5e8db36acf76c4e33bf1b to your computer and use it in GitHub Desktop.
Octopus App Version Cleanup
  1. Install Tampermonkey for Chrome
  2. Click here image
  3. Paste the snippet from octopuscleanup.js
  4. You also might have to go to your extension settings (often found by pasting chrome://extensions/ into your url-bar) and select Developer mode in the top right corner
// ==UserScript==
// @name Version Cleanup for Octopus
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Remove equal versions from AcosSky production and preproduction rows
// @author You
// @match https://octopus.acos.no/app
// @icon https://www.google.com/s2/favicons?sz=64&domain=acos.no
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Create and style the wrapper element
function createWrapper() {
const wrapper = document.createElement('div');
wrapper.classList.add("tm-wrapper");
wrapper.style.cssText = 'width: 100%; padding: 0 1.5rem; position: fixed; display: flex; gap: 1rem; top: 0px; justify-content: flex-end; align-items: center; height: 35px; background: #1f303f;';
document.body.appendChild(wrapper);
return wrapper;
}
// Create the range input for opacity control
function createOpacityControl(wrapper, defaultValue = 0.3) {
const rangeContainer = document.createElement("div");
rangeContainer.id = 'tm-range-container';
rangeContainer.style.display = 'none';
rangeContainer.style.justifyContent = 'center';
rangeContainer.style.gap = "0.5rem";
const range = document.createElement('input');
const label = document.createElement('label');
range.type = 'range';
range.id = 'opacity-range';
range.min = 0;
range.max = 1;
range.step = 0.1;
range.value = defaultValue;
label.innerText = "Opacity:";
label.htmlFor = range.id;
rangeContainer.appendChild(label);
rangeContainer.appendChild(range);
wrapper.appendChild(rangeContainer);
return range;
}
// Create the checkbox for toggling visibility
function createVisibilityToggle(wrapper, defaultValue = true) {
const container = document.createElement('div');
container.style.display = "flex";
container.style.justifyContent = "center";
container.style.alignItems = "center";
container.style.gap = "0.5rem";
const checkbox = document.createElement('input');
const slider = document.createElement('label');
const label = document.createElement('label');
label.htmlFor = 'tm-checkbox';
label.textContent = 'Hide deployed versions';
checkbox.type = 'checkbox';
checkbox.id = 'tm-checkbox';
checkbox.className = ''
checkbox.checked = defaultValue;
slider.className = 'switch'
const span = document.createElement('span');
span.className = 'slider round';
slider.appendChild(checkbox);
slider.appendChild(span);
container.appendChild(slider);
container.appendChild(label);
wrapper.appendChild(container);
return checkbox;
}
function createShowInProgressToggle(wrapper, defaultValue = true) {
const container = document.createElement('div');
container.id = 'tm-progress-toggle';
container.style.display = "flex";
container.style.justifyContent = "center";
container.style.alignItems = "center";
container.style.gap = "0.5rem";
const checkbox = document.createElement('input');
const slider = document.createElement('label');
const label = document.createElement('label');
label.htmlFor = 'tm-checkbox-2';
label.textContent = 'Show in progress processes';
checkbox.type = 'checkbox';
checkbox.id = 'tm-checkbox-2';
checkbox.className = ''
checkbox.checked = defaultValue;
slider.className = 'switch'
const span = document.createElement('span');
span.className = 'slider round';
slider.appendChild(checkbox);
slider.appendChild(span);
container.appendChild(slider);
container.appendChild(label);
wrapper.appendChild(container);
return checkbox;
}
// Update elements' visibility based on the current filter settings
function updateElementsVisibility(opacity, isChecked, showInProgress) {
console.log('updating');
var opacityRangeContainer = document.getElementById("tm-range-container");
opacityRangeContainer.style.display = isChecked ? 'flex' : 'none';
var showProgressToggle = document.getElementById("tm-progress-toggle");
showProgressToggle.style.display = isChecked ? 'flex' : 'none';
const containerElements = document.querySelectorAll('[class^="style-module_internalLink"]');
const spans = Array.from(containerElements).map(c => c.querySelectorAll('span'))
const versionSpans = spans.filter(s => s.length >= 3);
const elements = Array.from(versionSpans.map(v => v.length == 3 ? v[1] : v[3]));
const uniqueVersions = new Set();
const duplicateVersions = [];
elements.forEach(element => {
const versionText = element.innerText;
if (uniqueVersions.has(versionText)) {
duplicateVersions.push(versionText);
} else {
uniqueVersions.add(versionText);
}
});
elements.forEach(element => {
const isDuplicate = duplicateVersions.includes(element.innerText);
const isPossiblyAFakePositive = isDuplicate && duplicateVersions.filter(x => element.innerText == x).length > 1;
const tableParent = element.closest('[class^="style-module_internalLink"]');
const isFailed = tableParent.querySelectorAll('[class^="fa-solid fa-xmark"]').length != 0;
const isInProgress = tableParent.querySelectorAll('[class^="fa-solid fa-spinner"]').length != 0;
if (tableParent) {
tableParent.style.opacity = isDuplicate && isChecked ? opacity : '1';
}
if (tableParent && isPossiblyAFakePositive) {
tableParent.style.opacity = isChecked ? '0.5' : '1';
tableParent.style.background = 'rebeccapurple'
}
if (tableParent && isFailed ) {
tableParent.style.opacity = isChecked ? '0.5' : '1';
tableParent.style.background = 'blue'
}
if (tableParent && isInProgress && showInProgress) {
tableParent.style.opacity = isChecked ? '0.5' : '1';
tableParent.style.background = 'orange'
}
});
}
function saveSettings(opacity, visibility, showInProgress) {
localStorage.setItem('opacity', opacity.toString());
localStorage.setItem('visibility', visibility.toString());
localStorage.setItem('showInProgress', showInProgress)
}
function getSavedSettings() {
return {
opacity: localStorage.getItem('opacity') || '0.3', // Default value
visibility: localStorage.getItem('visibility') === 'true', // Convert string to boolean
showInProgress: localStorage.getItem('showInProgress') === 'true'
};
}
function init() {
const app = document.getElementById("app");
if (!app) {
console.error("App element not found");
return;
}
app.style.transform = 'translateY(35px)';
const wrapper = createWrapper();
const savedSettings = getSavedSettings();
addSliderStyles();
const opacityRange = createOpacityControl(wrapper, savedSettings.opacity);
const showInProgressToggle = createShowInProgressToggle(wrapper, savedSettings.showInProgress);
const visibilityCheckbox = createVisibilityToggle(wrapper, savedSettings.visibility);
// Update elements immediately based on saved settings
updateElementsVisibility(savedSettings.opacity, savedSettings.visibility);
// Save new settings when they change
opacityRange.addEventListener('input', () => {
saveSettings(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked);
updateElementsVisibility(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked);
});
visibilityCheckbox.addEventListener('change', () => {
saveSettings(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked);
updateElementsVisibility(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked);
});
showInProgressToggle.addEventListener('change', () => {
saveSettings(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked);
updateElementsVisibility(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked);
});
observeRouteChanges(() => updateElementsVisibility(opacityRange.value, visibilityCheckbox.checked, showInProgressToggle.checked));
}
function addSliderStyles() {
const style = document.createElement("style");
style.textContent = '.switch { position: relative; display: inline-block; width: 30px; height: 17px;}.switch input { opacity: 0; width: 0; height: 0;}.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: .4s; transition: .4s;}.slider:before { position: absolute; content: ""; height: 13px; width: 13px; left: 2px; bottom: 2px; background-color: white; -webkit-transition: .4s; transition: .4s;}input:checked + .slider { background-color: #2196F3;}input:focus + .slider { box-shadow: 0 0 1px #2196F3;}input:checked + .slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(13px); transform: translateX(13px);}/* Rounded sliders */.slider.round { border-radius: 34px;}.slider.round:before { border-radius: 50%;}'
document.body.appendChild(style);
}
function observeRouteChanges(onRouteChange) {
const observer = new MutationObserver((mutations, obs) => {
// Assuming route change will cause relevant mutations, adjust as necessary
onRouteChange();
});
observer.observe(document, {
childList: true,
subtree: true
});
}
init();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment