mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
new selfhosted version
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
import type { MetricsTimeline } from "~/server/api/metrics/[project_id]/timeline/generic";
|
||||
|
||||
import { type Slice } from '../shared/services/DateService';
|
||||
|
||||
export const hoursOffset = -(new Date().getTimezoneOffset() / 60);
|
||||
|
||||
function matchDateWithSlice(a: Date, b: Date, slice: Slice): boolean {
|
||||
if (a.getFullYear() != b.getFullYear()) return false;
|
||||
if (a.getMonth() != b.getMonth()) return false;
|
||||
if (slice === 'month') return true;
|
||||
if (a.getDate() != b.getDate()) return false;
|
||||
if (slice === 'day') return true;
|
||||
if (a.getHours() != b.getHours()) return false;
|
||||
if (slice === 'hour') return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
type FixMetricsOptions = {
|
||||
advanced?: boolean,
|
||||
advancedGroupKey?: string,
|
||||
timeLabels?: boolean
|
||||
}
|
||||
export function fixMetrics(result: { data: MetricsTimeline[], from: string, to: string }, slice: Slice, _options?: FixMetricsOptions) {
|
||||
|
||||
const options = {
|
||||
advanced: false,
|
||||
advancedGroupKey: 'default',
|
||||
timeLabels: false,
|
||||
..._options
|
||||
}
|
||||
|
||||
const allDates: Date[] = [];
|
||||
|
||||
let currentDate = new Date(result.from);
|
||||
while (currentDate <= new Date(result.to)) {
|
||||
allDates.push(new Date(currentDate));
|
||||
if (slice == 'hour') {
|
||||
currentDate.setHours(currentDate.getHours() + 1);
|
||||
} else if (slice == 'day') {
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
} else if (slice == 'month') {
|
||||
currentDate.setMonth(currentDate.getMonth() + 1);
|
||||
} else if (slice == 'year') {
|
||||
currentDate.setFullYear(currentDate.getFullYear() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const allKeys = !options.advanced ? [] : Array.from(new Set(result.data.map((e: any) => e[options.advancedGroupKey])).values());
|
||||
|
||||
console.log({ allKeys, allDates })
|
||||
|
||||
const fixed: any[] = allDates.map(matchDate => {
|
||||
|
||||
if (!options.advanced) {
|
||||
const target = result.data.find(e => matchDateWithSlice(new Date(e._id), matchDate, slice));
|
||||
return { _id: target ? new Date(target._id) : matchDate, count: target?.count || 0 }
|
||||
}
|
||||
|
||||
const targets = result.data.filter(e => matchDateWithSlice(new Date(e._id), matchDate, slice));
|
||||
|
||||
const returnObject: any = {
|
||||
_id: targets.length == 0 ? matchDate : new Date(targets[0]._id),
|
||||
count: allKeys.map(e => {
|
||||
return {
|
||||
key: e,
|
||||
value: targets.find((k: any) => k[options.advancedGroupKey] == e)?.count || 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
});
|
||||
|
||||
|
||||
if (slice === 'day' || slice == 'hour') fixed.pop();
|
||||
|
||||
const data = fixed.map(e => e.count);
|
||||
const avgTrend = data.slice(0, -1).reduce((a, e) => a + e, 0) / (data.length - 1);
|
||||
const t = data.at(-1) || 0;
|
||||
const trend = (100 / avgTrend * t) - 100;
|
||||
|
||||
return {
|
||||
labels: options.timeLabels ?
|
||||
fixed.map(e => {
|
||||
return e._id;
|
||||
}) : fixed.map(e => {
|
||||
if (slice == 'hour') {
|
||||
return `${e._id.getHours().toString().padStart(2, '0')}:00`
|
||||
} else if (slice == 'day') {
|
||||
return `${e._id.getDate().toString().padStart(2, '0')}/${(e._id.getMonth() + 1).toString().padStart(2, '0')}`
|
||||
} else if (slice == 'month') {
|
||||
return `${(e._id.getMonth() + 1).toString().padStart(2, '0')}/${e._id.getFullYear().toString()}`
|
||||
} else if (slice == 'year') {
|
||||
return `${e._id.getFullYear().toString()}`
|
||||
} else {
|
||||
return '???'
|
||||
}
|
||||
}),
|
||||
data,
|
||||
trend,
|
||||
allKeys
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
|
||||
export const debounce = <F extends (...args: any) => any>(func: F, waitFor: number,) => {
|
||||
let timeout: any;
|
||||
const debounced = (...args: any) => {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => func(...args), waitFor)
|
||||
}
|
||||
return debounced as (...args: Parameters<F>) => ReturnType<F>
|
||||
}
|
||||
33598
dashboard/utils/geolocation.ts
Normal file
33598
dashboard/utils/geolocation.ts
Normal file
File diff suppressed because it is too large
Load Diff
15
dashboard/utils/isSelfhosted.ts
Normal file
15
dashboard/utils/isSelfhosted.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
function truthy(value: any, ifNull: boolean) {
|
||||
if (value === undefined || value === null || value === '') return ifNull;
|
||||
return value === 'true' || value === true || value === '1' || value === 1;
|
||||
}
|
||||
|
||||
export function isSelfhosted() {
|
||||
const config = useRuntimeConfig();
|
||||
return truthy(config.public.SELFHOSTED, false);
|
||||
}
|
||||
|
||||
export function isAiEnabled() {
|
||||
const config = useRuntimeConfig();
|
||||
return truthy(config.public.AI_ENABLED, true);
|
||||
}
|
||||
34
dashboard/utils/numberFormatter.ts
Normal file
34
dashboard/utils/numberFormatter.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export function prettyNumber000(value: number | string) {
|
||||
return Math.floor(parseInt(value.toString())).toLocaleString('en-EN').replace(/,/g, '.');
|
||||
}
|
||||
|
||||
export function formatNumberK(value: string | number, decimals: number = 1) {
|
||||
const num = parseInt(value.toString());
|
||||
|
||||
if (num > 1_000_000) return (num / 1_000_000).toFixed(decimals) + ' M';
|
||||
if (num > 1_000) return (num / 1_000).toFixed(decimals) + ' K';
|
||||
|
||||
return isNaN(num) ? '0' : num.toFixed();
|
||||
|
||||
}
|
||||
|
||||
export function formatTime(ms: number, includeNotUsedHours: boolean = true): string {
|
||||
const totalSeconds = Math.floor(ms / 1000);
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
const seconds = totalSeconds % 60;
|
||||
|
||||
const pad = (num: number) => num.toString().padStart(2, '0');
|
||||
if (includeNotUsedHours === false && hours == 0) {
|
||||
return `${pad(minutes)}m ${pad(seconds)}s`;
|
||||
} else {
|
||||
return `${pad(hours)}h ${pad(minutes)}m ${pad(seconds)}s`;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatBytes(bytes: number, decimals: number = 2) {
|
||||
if (bytes > 1024 * 1024 * 1024) return (bytes / (1024 * 1024 * 1024)).toFixed(decimals) + ' GB';
|
||||
if (bytes > 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(decimals) + ' MB';
|
||||
if (bytes > 1024) return (bytes / 1024).toFixed(decimals) + ' KB';
|
||||
return bytes.toFixed(decimals) + ' B'
|
||||
}
|
||||
8
dashboard/utils/parseNumber.ts
Normal file
8
dashboard/utils/parseNumber.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
export function parseNumberInt(value: any, defaultValue: number) {
|
||||
const int = parseInt(value);
|
||||
if (!int) return defaultValue;
|
||||
if (isNaN(int)) return defaultValue;
|
||||
return int;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export function parseText(text: string) {
|
||||
const entityRegex = /&#(\d+);/g;
|
||||
return text.replace(entityRegex, (match, dec) => {
|
||||
return String.fromCharCode(dec);
|
||||
}).replace(/&/g, '&');
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
|
||||
export function prettyNumber000(value: number | string) {
|
||||
return Math.floor(parseInt(value.toString())).toLocaleString('en-EN').replace(/,/g, '.');
|
||||
}
|
||||
|
||||
export function formatNumberK(value: string | number, decimals: number = 1) {
|
||||
const num = parseInt(value.toString());
|
||||
|
||||
if (num > 1_000_000) return (num / 1_000_000).toFixed(decimals) + ' M';
|
||||
if (num > 1_000) return (num / 1_000).toFixed(decimals) + ' K';
|
||||
|
||||
return isNaN(num) ? '0' : num.toFixed();
|
||||
|
||||
}
|
||||
12
dashboard/utils/truncateText.ts
Normal file
12
dashboard/utils/truncateText.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
|
||||
export function truncateText(input: string, maxLength: number) {
|
||||
|
||||
if (input.length > maxLength) {
|
||||
return input.substring(0, maxLength) + '...'
|
||||
}
|
||||
|
||||
return input;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user