github.com/argoproj/argo-cd/v3@v3.2.1/ui/src/app/shared/utils.ts (about) 1 import React from 'react'; 2 import {Cluster} from './models'; 3 4 export function hashCode(str: string) { 5 let hash = 0; 6 for (let i = 0; i < str.length; i++) { 7 // tslint:disable-next-line:no-bitwise 8 hash = ~~((hash << 5) - hash + str.charCodeAt(i)); 9 } 10 return hash; 11 } 12 13 // concatMaps merges two maps. Later args take precedence where there's a key conflict. 14 export function concatMaps(...maps: (Map<string, string> | null)[]): Map<string, string> { 15 const newMap = new Map<string, string>(); 16 for (const map of maps) { 17 if (map) { 18 for (const entry of Object.entries(map)) { 19 newMap.set(entry[0], entry[1]); 20 } 21 } 22 } 23 return newMap; 24 } 25 26 export function isValidURL(url: string): boolean { 27 try { 28 const parsedUrl = new URL(url); 29 return parsedUrl.protocol !== 'javascript:' && parsedUrl.protocol !== 'data:' && parsedUrl.protocol !== 'vbscript:'; 30 } catch (TypeError) { 31 try { 32 // Try parsing as a relative URL. 33 const parsedUrl = new URL(url, window.location.origin); 34 return parsedUrl.protocol !== 'javascript:' && parsedUrl.protocol !== 'data:' && parsedUrl.protocol !== 'vbscript:'; 35 } catch (TypeError) { 36 return false; 37 } 38 } 39 } 40 41 export const colorSchemes = { 42 light: '(prefers-color-scheme: light)', 43 dark: '(prefers-color-scheme: dark)' 44 }; 45 46 /** 47 * quick method to check system theme 48 * @param theme auto, light, dark 49 * @returns dark or light 50 */ 51 export function getTheme(theme: string) { 52 if (theme !== 'auto') { 53 return theme; 54 } 55 56 const dark = window.matchMedia(colorSchemes.dark); 57 58 return dark.matches ? 'dark' : 'light'; 59 } 60 61 /** 62 * create a listener for system theme 63 * @param cb callback for theme change 64 * @returns destroy listener 65 */ 66 export const useSystemTheme = (cb: (theme: string) => void) => { 67 const dark = window.matchMedia(colorSchemes.dark); 68 const light = window.matchMedia(colorSchemes.light); 69 70 const listener = () => { 71 cb(dark.matches ? 'dark' : 'light'); 72 }; 73 74 dark.addEventListener('change', listener); 75 light.addEventListener('change', listener); 76 77 return () => { 78 dark.removeEventListener('change', listener); 79 light.removeEventListener('change', listener); 80 }; 81 }; 82 83 export const useTheme = (props: {theme: string}) => { 84 const [theme, setTheme] = React.useState(getTheme(props.theme)); 85 86 React.useEffect(() => { 87 let destroyListener: (() => void) | undefined; 88 89 // change theme by system, only register listener when theme is auto 90 if (props.theme === 'auto') { 91 destroyListener = useSystemTheme(systemTheme => { 92 setTheme(systemTheme); 93 }); 94 } 95 96 // change theme manually 97 if (props.theme !== theme) { 98 setTheme(getTheme(props.theme)); 99 } 100 101 return () => { 102 destroyListener?.(); 103 }; 104 }, [props.theme]); 105 106 return [theme]; 107 }; 108 109 export const formatClusterQueryParam = (cluster: Cluster) => { 110 if (cluster.name === cluster.server) { 111 return cluster.name; 112 } 113 return `${cluster.name} (${cluster.server})`; 114 };