helpers.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. import linkifyStr from 'linkify-string'
  3. export { htmlCleanup } from './htmlCleanup'
  4. type Falsy = false | 0 | '' | null | undefined
  5. type IsTruthy<T> = T extends Falsy ? never : T
  6. export const truthy = <T>(value: Maybe<T>): value is IsTruthy<T> => {
  7. return !!value
  8. }
  9. export const edgesToArray = <T>(
  10. object?: Maybe<{ edges?: { node: T }[] }>,
  11. ): T[] => {
  12. return object?.edges?.map((edge) => edge.node) || []
  13. }
  14. export const normalizeEdges = <T>(
  15. object?: Maybe<{ edges?: { node: T }[]; totalCount?: number }>,
  16. ): { array: T[]; totalCount: number } => {
  17. const array = edgesToArray(object)
  18. return {
  19. array,
  20. totalCount: object?.totalCount ?? array.length,
  21. }
  22. }
  23. export const mergeArray = <T extends unknown[]>(a: T, b: T) => {
  24. return [...new Set([...a, ...b])]
  25. }
  26. export const waitForAnimationFrame = () => {
  27. return new Promise((resolve) => requestAnimationFrame(resolve))
  28. }
  29. export const textCleanup = (ascii: string) => {
  30. if (!ascii) return ''
  31. return ascii
  32. .trim()
  33. .replace(/(\r\n|\n\r)/g, '\n') // cleanup
  34. .replace(/\r/g, '\n') // cleanup
  35. .replace(/[ ]\n/g, '\n') // remove tailing spaces
  36. .replace(/\n{3,20}/g, '\n\n') // remove multiple empty lines
  37. }
  38. // taken from App.Utils.text2html for consistency
  39. export const textToHtml = (text: string) => {
  40. text = textCleanup(text)
  41. text = linkifyStr(text)
  42. text = text.replace(/(\n\r|\r\n|\r)/g, '\n')
  43. text = text.replace(/ {2}/g, ' &nbsp;')
  44. text = `<div>${text.replace(/\n/g, '</div><div>')}</div>`
  45. return text.replace(/<div><\/div>/g, '<div><br></div>')
  46. }
  47. export const humanizeFileSize = (size: number) => {
  48. if (size > 1024 * 1024) {
  49. return `${Math.round((size * 10) / (1024 * 1024)) / 10} MB`
  50. }
  51. if (size > 1024) {
  52. return `${Math.round(size / 1024)} KB`
  53. }
  54. return `${size} Bytes`
  55. }
  56. export const debouncedQuery = <A extends unknown[], R>(
  57. fn: (...args: A) => Promise<R>,
  58. defaultValue: R,
  59. delay = 200,
  60. ) => {
  61. let timeout: number | undefined
  62. let lastResolve: (() => void) | null = null
  63. let lastResult = defaultValue
  64. return (...args: A): Promise<R> => {
  65. if (timeout) {
  66. lastResolve?.()
  67. clearTimeout(timeout)
  68. }
  69. return new Promise<R>((resolve, reject) => {
  70. lastResolve = () => resolve(lastResult)
  71. timeout = window.setTimeout(() => {
  72. fn(...args).then((result) => {
  73. lastResult = result
  74. resolve(result)
  75. }, reject)
  76. }, delay)
  77. })
  78. }
  79. }