fix: various fixes to things + simply app proxy sentry setup

This commit is contained in:
Hampus Kraft committed 2026-02-19 01:23:38 +00:00
1 parent ff1d15f7aa
commit 528e4e0d7f
44 files changed
+441 -1042

No files matched your search

-4
View File
@@ -310,10 +310,6 @@ class AccountStorage {
sso: instance.sso,
publicPushVapidKey: instance.publicPushVapidKey,
sentryDsn: instance.sentryDsn ?? '',
sentryProxyPath: instance.sentryProxyPath ?? '',
sentryReportHost: instance.sentryReportHost ?? '',
sentryProjectId: instance.sentryProjectId ?? '',
sentryPublicKey: instance.sentryPublicKey ?? '',
limits:
instance.limits !== undefined && instance.limits !== null
? JSON.parse(JSON.stringify(instance.limits))
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {
MarkdownContext,
type MarkdownRenderOptions,
type RendererProps,
} from '@app/lib/markdown/renderers/RendererTypes';
import {TimestampRenderer} from '@app/lib/markdown/renderers/TimestampRenderer';
import {NodeType, TimestampStyle} from '@fluxer/markdown_parser/src/types/Enums';
import type {TimestampNode} from '@fluxer/markdown_parser/src/types/Nodes';
import {setupI18n} from '@lingui/core';
import React from 'react';
import {renderToStaticMarkup} from 'react-dom/server';
import {describe, expect, test} from 'vitest';
const i18n = setupI18n({locale: 'en-US', messages: {'en-US': {}}});
function createRendererProps(node: TimestampNode): RendererProps<TimestampNode> {
const options: MarkdownRenderOptions = {
context: MarkdownContext.STANDARD_WITHOUT_JUMBO,
shouldJumboEmojis: false,
i18n,
};
return {
node,
id: 'test-timestamp',
renderChildren: () => null,
options,
};
}
describe('TimestampRenderer', () => {
test('renders a non-throwing fallback for invalid timestamps', () => {
const props = createRendererProps({
type: NodeType.Timestamp,
timestamp: Number.POSITIVE_INFINITY,
style: TimestampStyle.ShortDateTime,
});
const renderFn = () => renderToStaticMarkup(React.createElement(TimestampRenderer, props));
expect(renderFn).not.toThrow();
const markup = renderFn();
expect(markup).toContain('Infinity');
expect(markup).not.toContain('<time');
});
test('renders a semantic time element for valid timestamps', () => {
const props = createRendererProps({
type: NodeType.Timestamp,
timestamp: 1618953630,
style: TimestampStyle.ShortDateTime,
});
const markup = renderToStaticMarkup(React.createElement(TimestampRenderer, props));
expect(markup).toContain('<time');
expect(markup).toContain('dateTime="2021-04-20T21:20:30.000Z"');
});
});
@@ -20,6 +20,7 @@
import {Tooltip} from '@app/components/uikit/tooltip/Tooltip';
import type {RendererProps} from '@app/lib/markdown/renderers/RendererTypes';
import {formatTimestamp} from '@app/lib/markdown/utils/DateFormatter';
import {getDateFromUnixTimestampSeconds} from '@app/lib/markdown/utils/TimestampValidation';
import WindowStore from '@app/stores/WindowStore';
import markupStyles from '@app/styles/Markup.module.css';
import timestampRendererStyles from '@app/styles/TimestampRenderer.module.css';
@@ -32,8 +33,7 @@ import {ClockIcon} from '@phosphor-icons/react';
import {clsx} from 'clsx';
import {DateTime} from 'luxon';
import {observer} from 'mobx-react-lite';
import type {ReactElement} from 'react';
import {useEffect, useState} from 'react';
import React, {type ReactElement, useEffect, useState} from 'react';
export const TimestampRenderer = observer(function TimestampRenderer({
node,
@@ -43,25 +43,26 @@ export const TimestampRenderer = observer(function TimestampRenderer({
const {timestamp, style} = node;
const i18n = options.i18n;
const totalMillis = timestamp * 1000;
const date = new Date(totalMillis);
const date = getDateFromUnixTimestampSeconds(timestamp);
const isValidTimestamp = date !== null;
const now = new Date();
const isPast = date < now;
const isFuture = date > now;
const isTodayDate = isSameDay(date);
const isPast = date !== null && date < now;
const isFuture = date !== null && date > now;
const isTodayDate = date !== null && isSameDay(date);
const locale = getCurrentLocale();
const fullDateTime = getFormattedDateTimeWithSeconds(date, locale);
const fullDateTime = date !== null ? getFormattedDateTimeWithSeconds(date, locale) : null;
const isRelativeStyle = style === TimestampStyle.RelativeTime;
const isWindowFocused = WindowStore.focused;
const [relativeDisplayTime, setRelativeDisplayTime] = useState(() => formatTimestamp(timestamp, style, i18n));
const luxonDate = DateTime.fromMillis(totalMillis);
const relativeTime = luxonDate.toRelative();
const [relativeDisplayTime, setRelativeDisplayTime] = useState(() =>
isValidTimestamp ? formatTimestamp(timestamp, style, i18n) : '',
);
const relativeTime = date !== null ? DateTime.fromJSDate(date).toRelative() : null;
useEffect(() => {
if (!isRelativeStyle || !isWindowFocused) {
if (!isValidTimestamp || !isRelativeStyle || !isWindowFocused) {
return;
}
@@ -75,7 +76,11 @@ export const TimestampRenderer = observer(function TimestampRenderer({
refreshDisplay();
const intervalId = setInterval(refreshDisplay, 1000);
return () => clearInterval(intervalId);
}, [isRelativeStyle, isWindowFocused, style, timestamp, i18n]);
}, [isValidTimestamp, isRelativeStyle, isWindowFocused, style, timestamp, i18n]);
if (date === null || fullDateTime === null) {
return React.createElement('span', {className: markupStyles.timestamp}, String(timestamp));
}
const tooltipContent = (
<div className={timestampRendererStyles.tooltipContainer}>
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {formatTimestamp} from '@app/lib/markdown/utils/DateFormatter';
import {TimestampStyle} from '@fluxer/markdown_parser/src/types/Enums';
import {setupI18n} from '@lingui/core';
import {afterEach, describe, expect, test, vi} from 'vitest';
const i18n = setupI18n({locale: 'en-US', messages: {'en-US': {}}});
describe('formatTimestamp', () => {
afterEach(() => {
vi.useRealTimers();
});
test('returns the raw numeric value for non-finite timestamps', () => {
const output = formatTimestamp(Number.POSITIVE_INFINITY, TimestampStyle.ShortDateTime, i18n);
expect(output).toBe('Infinity');
});
test('returns the raw numeric value for out-of-range timestamps', () => {
const output = formatTimestamp(8640000000001, TimestampStyle.ShortDateTime, i18n);
expect(output).toBe('8640000000001');
});
test('still formats valid relative timestamps', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-02-18T12:00:00.000Z'));
const oneMinuteAgoTimestamp = Math.floor(new Date('2026-02-18T11:59:00.000Z').getTime() / 1000);
const output = formatTimestamp(oneMinuteAgoTimestamp, TimestampStyle.RelativeTime, i18n);
expect(output.length).toBeGreaterThan(0);
});
});
@@ -17,6 +17,7 @@
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {getDateFromUnixTimestampSeconds} from '@app/lib/markdown/utils/TimestampValidation';
import {shouldUse12HourFormat} from '@app/utils/DateUtils';
import {getCurrentLocale} from '@app/utils/LocaleUtils';
import {
@@ -33,9 +34,8 @@ import {TimestampStyle} from '@fluxer/markdown_parser/src/types/Enums';
import type {I18n} from '@lingui/core';
import {msg} from '@lingui/core/macro';
function formatRelativeTime(timestamp: number, i18n: I18n): string {
function formatRelativeTime(date: Date, i18n: I18n): string {
const locale = getCurrentLocale();
const date = new Date(timestamp * 1000);
const now = new Date();
if (isSameDay(date, now)) {
@@ -142,9 +142,14 @@ function formatRelativeTime(timestamp: number, i18n: I18n): string {
export function formatTimestamp(timestamp: number, style: TimestampStyle, i18n: I18n): string {
const locale = getCurrentLocale();
const hour12 = shouldUse12HourFormat(locale);
const date = getDateFromUnixTimestampSeconds(timestamp);
if (date == null) {
return String(timestamp);
}
if (style === TimestampStyle.RelativeTime) {
return formatRelativeTime(timestamp, i18n);
return formatRelativeTime(date, i18n);
}
return formatTimestampWithStyle(timestamp, style, locale, hour12);
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {getDateFromUnixTimestampSeconds} from '@app/lib/markdown/utils/TimestampValidation';
import {describe, expect, test} from 'vitest';
describe('getDateFromUnixTimestampSeconds', () => {
test('returns a valid date for normal unix timestamps', () => {
const result = getDateFromUnixTimestampSeconds(1618953630);
expect(result).toBeInstanceOf(Date);
expect(result?.toISOString()).toBe('2021-04-20T21:20:30.000Z');
});
test('returns null for infinity', () => {
expect(getDateFromUnixTimestampSeconds(Number.POSITIVE_INFINITY)).toBeNull();
});
test('returns null for NaN', () => {
expect(getDateFromUnixTimestampSeconds(Number.NaN)).toBeNull();
});
test('returns null when timestamp is beyond js date range', () => {
expect(getDateFromUnixTimestampSeconds(8640000000001)).toBeNull();
});
});
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
const MILLISECONDS_PER_SECOND = 1000;
export function getDateFromUnixTimestampSeconds(timestamp: number): Date | null {
if (!Number.isFinite(timestamp)) {
return null;
}
const timestampMillis = timestamp * MILLISECONDS_PER_SECOND;
if (!Number.isFinite(timestampMillis)) {
return null;
}
const date = new Date(timestampMillis);
if (Number.isNaN(date.getTime())) {
return null;
}
return date;
}