This commit is contained in:
2024-04-21 14:42:52 +02:00
parent 4b69674ede
commit 8a25f53c99
10700 changed files with 55767 additions and 14201 deletions

View File

@ -0,0 +1,15 @@
export function stringArraysIdentical(a: string[], b: string[]): boolean {
if (a.length !== b.length) {
return false // Different lengths, not identical
}
/* Sort the arrays to make sure the elements are in the same order */
const sortedA = a.slice().sort()
const sortedB = b.slice().sort()
/* Compare each element in both arrays */
for (let i = 0; i < sortedA.length; i++) {
if (sortedA[i] !== sortedB[i]) {
return false // Different elements, not identical
}
}
return true // Identical arrays
}

View File

@ -0,0 +1,9 @@
export function getSizeWithAspectRatio(
srcWidth: number,
srcHeight: number,
maxWidth: number,
maxHeight: number,
) {
const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight)
return { width: srcWidth * ratio, height: srcHeight * ratio }
}

View File

@ -0,0 +1,23 @@
export function byteToMegabyte(value: number): number {
return value / 1e6
}
export function byteToGigabyte(value: number): number {
return value / 1e9
}
export function byteToTerabyte(value: number): number {
return value / 1e12
}
export function terabyteToByte(value: number): number {
return value * 1e12
}
export function gigabyteToByte(value: number): number {
return value * 1e9
}
export function megabyteToByte(value: number): number {
return value * 1e6
}

View File

@ -0,0 +1,20 @@
import { File } from '@/client/api/file'
import { getAccessTokenOrRedirect } from '@/infra/token'
export default async function downloadFile(file: File) {
if (!file.original || file.type !== 'file') {
return
}
const a: HTMLAnchorElement = document.createElement('a')
a.href = `/proxy/api/v1/files/${file.id}/original${
file.original.extension
}?${new URLSearchParams({
access_token: getAccessTokenOrRedirect(),
download: 'true',
})}`
a.download = file.name
a.style.display = 'none'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}

View File

@ -0,0 +1,186 @@
export function isPDF(ext?: string | null) {
if (!ext) {
return false
}
return ext === '.pdf'
}
export function isImage(ext?: string | null) {
if (!ext) {
return false
}
return (
[
'.xpm',
'.png',
'.jpg',
'.jpeg',
'.jp2',
'.gif',
'.webp',
'.tiff',
'.bmp',
'.ico',
'.heif',
'.xcf',
'.svg',
].findIndex((e) => e === ext) !== -1
)
}
export function isText(ext?: string | null) {
if (!ext) {
return false
}
return ext === '.txt'
}
export function isRichText(ext?: string | null) {
if (!ext) {
return false
}
return ['.rtf'].findIndex((e) => e === ext) !== -1
}
export function isWord(ext?: string | null) {
if (!ext) {
return false
}
return ['.docx', '.doc'].findIndex((e) => e === ext) !== -1
}
export function isPowerPoint(ext?: string | null) {
if (!ext) {
return false
}
return ['.pptx', '.ppt'].findIndex((e) => e === ext) !== -1
}
export function isExcel(ext?: string | null) {
if (!ext) {
return false
}
return ['.xlsx', '.xls'].findIndex((e) => e === ext) !== -1
}
export function isDocument(ext?: string | null) {
if (!ext) {
return false
}
return ['.odt', '.ott', '.gdoc', '.pages'].findIndex((e) => e === ext) !== -1
}
export function isSpreadsheet(ext?: string | null) {
if (!ext) {
return false
}
return ['.ods', '.ots', '.gsheet'].findIndex((e) => e === ext) !== -1
}
export function isSlides(ext?: string | null) {
if (!ext) {
return false
}
return ['.odp', '.otp', '.key', '.gslides'].findIndex((e) => e === ext) !== -1
}
export function isVideo(ext?: string | null) {
if (!ext) {
return false
}
return (
[
'.ogv',
'.mpeg',
'.mov',
'.mqv',
'.mp4',
'.webm',
'.3gp',
'.3g2',
'.avi',
'.flv',
'.mkv',
'.asf',
'.m4v',
].findIndex((e) => e === ext) !== -1
)
}
export function isAudio(ext?: string | null) {
if (!ext) {
return false
}
return (
[
'.oga',
'.ogg',
'.mp3',
'.flac',
'.midi',
'.ape',
'.mpc',
'.amr',
'.wav',
'.aiff',
'.au',
'.aac',
'voc',
'.m4a',
'.qcp',
].findIndex((e) => e === ext) !== -1
)
}
export function isArchive(ext?: string | null) {
if (!ext) {
return false
}
return (
['.zip', '.tar', '.7z', '.bz2', '.gz', '.rar'].findIndex(
(e) => e === ext,
) !== -1
)
}
export function isFont(ext?: string | null) {
if (!ext) {
return false
}
return ['.ttf', '.woff'].findIndex((e) => e === ext) !== -1
}
export function isCode(ext?: string | null) {
return (
[
'.html',
'.js',
'jsx',
'.ts',
'.tsx',
'.css',
'.sass',
'.scss',
'.go',
'.py',
'.rb',
'.java',
'.c',
'.h',
'.cpp',
'.hpp',
'.json',
'.yml',
'.yaml',
'.toml',
'.md',
].findIndex((e) => e === ext) !== -1
)
}
export function isCSV(ext?: string | null) {
if (!ext) {
return false
}
return ['.csv'].findIndex((e) => e === ext) !== -1
}

View File

@ -0,0 +1,10 @@
export default function mapFileList(fileList: FileList | null): File[] {
if (!fileList || fileList.length === 0) {
return []
}
const files = []
for (let i = 0; i < fileList.length; i++) {
files.push(fileList[i])
}
return files
}

View File

@ -0,0 +1,23 @@
import * as Yup from 'yup'
export default function parseEmailList(value: string): string[] {
return [...new Set(value.split(',').map((e: string) => e.trim()))].filter(
(e) => {
if (e.length === 0) {
return false
}
try {
Yup.string()
.email()
.matches(
/.+(\.[A-Za-z]{2,})$/,
'Email must end with a valid top-level domain',
)
.validateSync(e)
return true
} catch {
return false
}
},
)
}

View File

@ -0,0 +1,3 @@
export function percentageOf(value: number, percentage: number) {
return (value / 100) * percentage
}

View File

@ -0,0 +1,19 @@
export default function prettyBytes(value: number) {
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
if (!Number.isFinite(value)) {
throw new TypeError(
`Expected a finite number, got ${typeof value}: ${value}`,
)
}
const isNegative = value < 0
if (isNegative) {
value = -value
}
if (value < 1) {
return (isNegative ? '-' : '') + value + ' B'
}
const exponent = Math.min(Math.floor(Math.log10(value) / 3), UNITS.length - 1)
const number = Number((value / Math.pow(1000, exponent)).toPrecision(3))
const unit = UNITS[exponent]
return (isNegative ? '-' : '') + number + ' ' + unit
}

View File

@ -0,0 +1,3 @@
export default function prettyDate(date: any): string {
return new Date(date).toLocaleString()
}

View File

@ -0,0 +1,12 @@
import { encode, decode } from 'js-base64'
export function encodeQuery(value: string) {
return encode(value, true)
}
export function decodeQuery(value: string): string | undefined {
if (!value) {
return undefined
}
return decode(value)
}

View File

@ -0,0 +1,28 @@
import dateFormat from 'dateformat'
import TimeAgo from 'javascript-time-ago'
import en from 'javascript-time-ago/locale/en'
let timeAgo: TimeAgo
export default function relativeDate(date: Date): string {
if (!timeAgo) {
TimeAgo.addDefaultLocale(en)
timeAgo = new TimeAgo('en-US')
}
const hoursDiff = Math.abs(new Date().getTime() - date.getTime()) / 3600000
const isToday =
new Date(date).setHours(0, 0, 0, 0) === new Date().setHours(0, 0, 0, 0)
const isYesterday = new Date().getDate() - date.getDate() === 1
const isThisYear = date.getFullYear() === new Date().getFullYear()
if (hoursDiff <= 12 && isToday) {
return timeAgo.format(date)
} else if (isToday) {
return 'Today'
} else if (isYesterday) {
return 'Yesterday'
} else if (isThisYear) {
return dateFormat(new Date(date), 'd mmm')
} else {
return dateFormat(new Date(date), 'd mmm yyyy')
}
}

View File

@ -0,0 +1,5 @@
import { User } from '@/client/idp/user'
export default function userToString(user: User) {
return `${user.fullName} (${user.email})`
}