Olympus Timesheet Reminder Hider v1.0.2
This version improves the logging to make it easier to debug the script's behaviour. The "Script initialized" message is now logged with console.log instead of console.debug for better visibility, and the script now explicitly logs whether it's hiding the reminder, not hiding it, or if there's no reminder to hide.
Script Content
// ==UserScript==
// @name Olympus: Timesheet Reminder Hider
// @namespace https://www.timhilton.xyz/user-scripts
// @version 1.0.2
// @description Hide missing timesheet badges for specific dates or today's date
// @author Tim Hilton using Claude
// @match https://olympus.audacia.co.uk/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const LOG_PREFIX = '[Olympus: Timesheet Reminder Hider]';
const STORAGE_KEY = 'olympus-timesheet-reminder-hider-ignored-dates';
const API_URL = 'https://olympus-api.audacia.co.uk/api/timesheets/missing';
const STYLE_ID = 'timesheet-reminder-hider-style';
console.log(`${LOG_PREFIX} Script initialized`);
/**
* Get today's date in YYYY-MM-DD format
*/
function getTodayDate() {
const today = new Date();
return today.toISOString().split('T')[0];
}
/**
* Get the list of ignored dates from localStorage
*/
function getIgnoredDates() {
const stored = localStorage.getItem(STORAGE_KEY);
return stored ? JSON.parse(stored) : [];
}
/**
* Save the list of ignored dates to localStorage
*/
function saveIgnoredDates(dates) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(dates));
}
/**
* Add a date to the ignore list
*/
function ignoreDate(date) {
const dates = getIgnoredDates();
if (!dates.includes(date)) {
dates.push(date);
saveIgnoredDates(dates);
console.log(`${LOG_PREFIX} ✅ Added ${date} to ignore list`);
} else {
console.debug(`${LOG_PREFIX} ${date} already in ignore list`);
}
}
/**
* Remove a date from the ignore list
*/
function unignoreDate(date) {
const dates = getIgnoredDates();
const index = dates.indexOf(date);
if (index > -1) {
dates.splice(index, 1);
saveIgnoredDates(dates);
console.log(`${LOG_PREFIX} ✅ Removed ${date} from ignore list`);
} else {
console.debug(`${LOG_PREFIX} ${date} not in ignore list`);
}
}
/**
* List all ignored dates
*/
function listIgnoredDates() {
const dates = getIgnoredDates();
if (dates.length === 0) {
console.log(`${LOG_PREFIX} No dates in ignore list`);
} else {
console.log(`${LOG_PREFIX} Ignored dates: ${dates.join(', ')}`);
}
return dates;
}
/**
* Clear all ignored dates
*/
function clearIgnoredDates() {
saveIgnoredDates([]);
console.log(`${LOG_PREFIX} ✅ Cleared all ignored dates`);
}
/**
* Inject CSS to hide the badge
*/
function hideBadge() {
if (document.getElementById(STYLE_ID)) {
return; // Already hidden
}
const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = `
span.mud-badge-wrapper span.missing-timesheet-badge {
display: none;
}
`;
document.head.appendChild(style);
console.log(`${LOG_PREFIX} 🎉 Badge hidden`);
}
/**
* Remove the CSS that hides the badge
*/
function showBadge() {
const style = document.getElementById(STYLE_ID);
if (style) {
style.remove();
console.log(`${LOG_PREFIX} ✅ Badge shown`);
}
}
/**
* Filter missing dates and update badge visibility
*/
function processMissingDates(dates) {
const today = getTodayDate();
const ignoredDates = getIgnoredDates();
// Categorise dates
const filteredToday = [];
const filteredIgnored = [];
const visibleDates = [];
dates.forEach(date => {
if (date === today) {
filteredToday.push(date);
} else if (ignoredDates.includes(date)) {
filteredIgnored.push(date);
} else {
visibleDates.push(date);
}
});
// Log the categorised dates
console.debug(`${LOG_PREFIX} Original dates: [${dates.join(', ')}]`);
if (filteredToday.length > 0) {
console.debug(`${LOG_PREFIX} Filtered (today): [${filteredToday.join(', ')}]`);
}
if (filteredIgnored.length > 0) {
console.debug(`${LOG_PREFIX} Filtered (ignored): [${filteredIgnored.join(', ')}]`);
}
if (visibleDates.length > 0) {
console.debug(`${LOG_PREFIX} Visible: [${visibleDates.join(', ')}]`);
}
if (dates.length === 0) {
console.log(`${LOG_PREFIX} No missing timesheet reminder to hide`);
} else if (visibleDates.length === 0) {
console.log(`${LOG_PREFIX} Hiding reminder (all ${dates.length} dates filtered out)`);
hideBadge();
} else {
console.log(`${LOG_PREFIX} Not hiding reminder (${visibleDates.length} visible dates: [${visibleDates.join(', ')}])`);
showBadge();
}
}
/**
* Override fetch to intercept API responses
*/
const originalFetch = window.fetch;
window.fetch = async function(...args) {
const response = await originalFetch.apply(this, args);
// Check if this is the missing timesheets API
const url = args[0]?.url || args[0];
if (typeof url === 'string' && url.includes('/api/timesheets/missing')) {
console.debug(`${LOG_PREFIX} Intercepted missing timesheets API call`);
// Clone the response so we can read it without consuming it
const clonedResponse = response.clone();
try {
const data = await clonedResponse.json();
if (Array.isArray(data)) {
processMissingDates(data);
}
} catch (e) {
console.log(`${LOG_PREFIX} ❌ Error parsing fetch response: ${e.message}`);
}
}
return response;
};
/**
* Override XMLHttpRequest to intercept API responses
*/
const originalXHROpen = XMLHttpRequest.prototype.open;
const originalXHRSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
this._timesheetHiderUrl = url;
return originalXHROpen.apply(this, [method, url, ...rest]);
};
XMLHttpRequest.prototype.send = function(...args) {
if (this._timesheetHiderUrl && this._timesheetHiderUrl.includes('/api/timesheets/missing')) {
console.debug(`${LOG_PREFIX} Intercepted missing timesheets XHR call`);
this.addEventListener('load', function() {
try {
const data = JSON.parse(this.responseText);
if (Array.isArray(data)) {
processMissingDates(data);
}
} catch (e) {
console.log(`${LOG_PREFIX} ❌ Error parsing XHR response: ${e.message}`);
}
});
}
return originalXHRSend.apply(this, args);
};
// Expose functions globally for console access
window.timesheetHider = {
ignore: ignoreDate,
unignore: unignoreDate,
list: listIgnoredDates,
clear: clearIgnoredDates,
help: function() {
console.log(`${LOG_PREFIX} Console Commands:
timesheetHider.ignore('YYYY-MM-DD') - Add a date to the ignore list
timesheetHider.unignore('YYYY-MM-DD') - Remove a date from the ignore list
timesheetHider.list() - Show all ignored dates
timesheetHider.clear() - Clear all ignored dates
timesheetHider.help() - Show this help message
Note: Today's date is always ignored automatically.`);
}
};
console.debug(`${LOG_PREFIX} Ready. Type timesheetHider.help() for commands`);
})();