dashboard/shell/utils/dynamic-content/util.ts

123 lines
4.3 KiB
TypeScript

/**
*
* The code in this file provides utility functions for dynamic content
*
* First up is a helper to remove notifications that match a given prefix
* Second up is a basic logging helper than will log to the console but can also log to local storage
* so that we have a persistent log of what the dynamic content code has been doing to help with debugging
*
*/
import { randomStr } from '@shell/utils/string';
import { Configuration, Context } from './types';
import { Notification } from '@shell/types/notifications';
const MAX_LOG_MESSAGES = 50;
export const LOCAL_STORAGE_CONTENT_DEBUG_LOG = 'rancher-updates-debug-log';
/**
* Remove all notifications that have the given prefix, except the one that has the specified current id
*
* Returns whether a notification with the current id was found
*
* @param dispatch Store dispatcher
* @param getters Store getters
* @param prefix Prefix to look for and remove notifications whose IDs start with this prefix
* @param currentId Current ID of notification to keep, if present
* @returns If a notification with the current ID was found
*/
export async function removeMatchingNotifications(context: Context, prefix: string, currentId: string): Promise<boolean> {
const { dispatch, getters, logger } = context;
const id = `${ prefix }${ currentId }`;
let found = false;
let removed = 0;
const all = getters['notifications/all'] || [];
const ids = all.map((n: Notification) => n.id);
for (let i = 0; i < ids.length; i++) {
const notificationId = ids[i];
if (notificationId.startsWith(prefix)) {
if (notificationId === id) {
found = true;
} else {
await dispatch('notifications/remove', notificationId);
removed++;
logger.debug(`Remove matching notifications ${ prefix }, ${ currentId } - removed notification ${ notificationId }`);
}
}
}
if (found) {
logger.debug(`Remove matching notifications ${ prefix }, ${ currentId } - found an existing notification (removed ${ removed })`);
} else {
logger.debug(`Remove matching notifications ${ prefix }, ${ currentId } - did not find an existing notification (removed ${ removed })`);
}
return found;
}
/**
* Create a logger interface that can be used to log messages and errors appropriately
* @param config Configuration to help us determine where and when to log
* @returns Logger interface with methods to log for error, info and debug
*/
export function createLogger(config: Configuration) {
return {
error: (message: string, ...args: any[]) => log(config, 'error', message, ...args),
info: (message: string, ...args: any[]) => log(config, 'info', message, ...args),
debug: (message: string, ...args: any[]) => log(config, 'debug', message, ...args),
};
}
/**
* Actual logging function that logs appropriately
* @param config Configuration to help us determine where and when to log
* @param level Log level (error, info, debug)
* @param message Log message
* @param arg Optional argument to be logged
*/
function log(config: Configuration, level: string, message: string, ...args: any[]) {
// Log to the console when appropriate
if (level === 'error') {
console.error(message, ...args); // eslint-disable-line no-console
} else if (level === 'info' && config.log) {
console.info(message, ...args); // eslint-disable-line no-console
} else if (level === 'debug' && config.debug) {
console.debug(message, ...args); // eslint-disable-line no-console
}
// Only log to local storage if the configuration says we should
if (config.log) {
// Add the log message to the log we keep in local storage
try {
let data = [];
// If we can't parse the data in local storage, then we will reset to an emptry array
try {
data = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_CONTENT_DEBUG_LOG) || '[]');
} catch {}
const item = {
level,
message,
timestamp: new Date().toISOString(),
args,
uuid: randomStr(),
};
data.unshift(item);
// Limit the number of log messages
window.localStorage.setItem(LOCAL_STORAGE_CONTENT_DEBUG_LOG, JSON.stringify(data.slice(0, MAX_LOG_MESSAGES)));
// Send an event so the UI can update if necessary
const event = new CustomEvent('dynamicContentLog', { detail: item });
window.dispatchEvent(event);
} catch {}
}
}