From f33588e9e14387e07c654297cf0723bfb7d9e68f Mon Sep 17 00:00:00 2001 From: Dennis Oelkers Date: Tue, 21 Jan 2025 11:08:46 +0100 Subject: [PATCH 1/2] Fixing highlighting of message in message table by id. (#21389) * Fixing highlighting of message in message table by id. * Typing improvements. * Adding changelog snippet. --- changelog/unreleased/issue-19058.toml | 5 +++++ .../messagelist/MessageTableEntry.tsx | 22 +++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 changelog/unreleased/issue-19058.toml diff --git a/changelog/unreleased/issue-19058.toml b/changelog/unreleased/issue-19058.toml new file mode 100644 index 000000000000..b673bf48a302 --- /dev/null +++ b/changelog/unreleased/issue-19058.toml @@ -0,0 +1,5 @@ +type = "fixed" +message = "Fixing highlighting of message in message table by id." + +issues = ["19058"] +pulls = ["21389"] diff --git a/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx b/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx index 87ba2e523c2f..af76310a8508 100644 --- a/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx +++ b/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx @@ -17,7 +17,7 @@ import * as React from 'react'; import { useCallback, useContext, useMemo } from 'react'; import * as Immutable from 'immutable'; -import styled, { css } from 'styled-components'; +import styled from 'styled-components'; import { AdditionalContext } from 'views/logic/ActionContext'; import { useStore } from 'stores/connect'; @@ -51,11 +51,11 @@ export const TableBody = styled.tbody<{ $expanded?: boolean, $highlighted?: bool && { border-top: 0; - ${$expanded ? css` + ${$expanded ? ` border-left: 7px solid ${theme.colors.variant.light.info}; ` : ''} - ${$highlighted ? css` + ${$highlighted ? ` border-left: 7px solid ${theme.colors.variant.light.success}; ` : ''} } @@ -99,19 +99,19 @@ type Props = { message: Message, selectedFields?: Immutable.OrderedSet, showMessageRow?: boolean, - toggleDetail: (string) => void, + toggleDetail: (messageId: string) => void, }; -const isDecoratedField = (field, decorationStats) => decorationStats +const isDecoratedField = (field: string | number, decorationStats: Message['decoration_stats']) => decorationStats && (decorationStats.added_fields[field] !== undefined || decorationStats.changed_fields[field] !== undefined); -const fieldType = (fieldName, { decoration_stats: decorationStats }: { - decoration_stats?: any -}, fields) => (isDecoratedField(fieldName, decorationStats) - ? FieldType.Decorated - : ((fields && fields.find((f) => f.name === fieldName)) || { type: FieldType.Unknown }).type); +const fieldType = (fieldName: string, { decoration_stats: decorationStats }: Message, fields: FieldTypeMappingsList) => ( + isDecoratedField(fieldName, decorationStats) + ? FieldType.Decorated + : ((fields?.find((f) => f.name === fieldName)) ?? { type: FieldType.Unknown }).type +); -const Strong = ({ children, strong = false }: React.PropsWithChildren<{ strong: boolean }>) => (strong +const Strong = ({ children = undefined, strong }: React.PropsWithChildren<{ strong: boolean }>) => (strong ? {children} : <>{children}); From 8b91f4ffff945e1ef5e3950cbf6df40e1185f35b Mon Sep 17 00:00:00 2001 From: Dennis Oelkers Date: Tue, 21 Jan 2025 11:13:29 +0100 Subject: [PATCH 2/2] Fix display of very small percentage values. (#21368) * Fix display of very small percentage values. * Adding license headers & changelog snippet. * Defaulting to 2 fraction digits for percentages. --- changelog/unreleased/issue-21185.toml | 5 ++ .../src/util/NumberFormatting.test.ts | 65 +++++++++++++++++++ .../src/util/NumberFormatting.ts | 39 +++++++++++ .../fieldtypes/PercentageField.test.tsx | 27 ++++++++ .../components/fieldtypes/PercentageField.tsx | 5 +- .../components/messagelist/FormatNumber.ts | 4 +- 6 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 changelog/unreleased/issue-21185.toml create mode 100644 graylog2-web-interface/src/util/NumberFormatting.test.ts create mode 100644 graylog2-web-interface/src/util/NumberFormatting.ts create mode 100644 graylog2-web-interface/src/views/components/fieldtypes/PercentageField.test.tsx diff --git a/changelog/unreleased/issue-21185.toml b/changelog/unreleased/issue-21185.toml new file mode 100644 index 000000000000..e937b69565f6 --- /dev/null +++ b/changelog/unreleased/issue-21185.toml @@ -0,0 +1,5 @@ +type = "f" +message = "Fix displaying very small percentages." + +issues = ["21185"] +pulls = ["21368"] diff --git a/graylog2-web-interface/src/util/NumberFormatting.test.ts b/graylog2-web-interface/src/util/NumberFormatting.test.ts new file mode 100644 index 000000000000..dacc4b74e3c6 --- /dev/null +++ b/graylog2-web-interface/src/util/NumberFormatting.test.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 Graylog, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + */ +import { formatNumber, formatPercentage, formatTrend } from './NumberFormatting'; + +describe('NumberFormatting', () => { + describe('formatNumber', () => { + it('formats with 2 fraction digits by default', () => { + expect(formatNumber(42.23)).toEqual('42.23'); + expect(formatNumber(42)).toEqual('42'); + expect(formatNumber(137.991)).toEqual('137.99'); + expect(formatNumber(137.999)).toEqual('138'); + expect(formatNumber(137.111)).toEqual('137.11'); + expect(formatNumber(137.115)).toEqual('137.12'); + }); + }); + + describe('formatTrend', () => { + it('does show sign', () => { + expect(formatTrend(42.23)).toEqual('+42.23'); + expect(formatTrend(-42)).toEqual('-42'); + expect(formatTrend(-137.991)).toEqual('-137.99'); + expect(formatTrend(137.999)).toEqual('+138'); + expect(formatTrend(-137.111)).toEqual('-137.11'); + expect(formatTrend(137.115)).toEqual('+137.12'); + expect(formatTrend(0)).toEqual('0'); + }); + + it('does show percentage', () => { + const options = { percentage: true }; + + expect(formatTrend(42.23 / 100, options)).toEqual('+42.23%'); + expect(formatTrend(-42 / 100, options)).toEqual('-42.00%'); + expect(formatTrend(-137.991 / 100, options)).toEqual('-137.99%'); + expect(formatTrend(137.999 / 100, options)).toEqual('+138.00%'); + expect(formatTrend(-137.111 / 100, options)).toEqual('-137.11%'); + expect(formatTrend(137.115 / 100, options)).toEqual('+137.12%'); + expect(formatTrend(0 / 100, options)).toEqual('0.00%'); + }); + }); + + describe('formatPercentage', () => { + it('formats with 2 fraction digits by default', () => { + expect(formatPercentage(42.23 / 100)).toEqual('42.23%'); + expect(formatPercentage(42 / 100)).toEqual('42.00%'); + expect(formatPercentage(137.991 / 100)).toEqual('137.99%'); + expect(formatPercentage(137.999 / 100)).toEqual('138.00%'); + expect(formatPercentage(137.111 / 100)).toEqual('137.11%'); + expect(formatPercentage(137.115 / 100)).toEqual('137.12%'); + }); + }); +}); diff --git a/graylog2-web-interface/src/util/NumberFormatting.ts b/graylog2-web-interface/src/util/NumberFormatting.ts new file mode 100644 index 000000000000..bc04bcd899e2 --- /dev/null +++ b/graylog2-web-interface/src/util/NumberFormatting.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 Graylog, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + */ +type Options = { + signDisplay?: 'auto' | 'always' | 'exceptZero', + maximumFractionDigits?: number, + minimumFractionDigits?: number, +}; + +const defaultOptions = { + maximumFractionDigits: 2, +} as const; + +const defaultPercentageOptions = { + ...defaultOptions, + minimumFractionDigits: 2, + style: 'percent', +} as const; + +export const formatNumber = (num: number, options: Options = {}) => new Intl.NumberFormat(undefined, { ...defaultOptions, ...options }).format(num); +export const formatPercentage = (num: number, options: Options = {}) => new Intl.NumberFormat(undefined, { ...defaultPercentageOptions, ...options }).format(num); + +type TrendOptions = { + percentage?: boolean, +} +export const formatTrend = (num: number, options: TrendOptions = {}) => (options.percentage === true ? formatPercentage : formatNumber)(num, { signDisplay: 'exceptZero' }); diff --git a/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.test.tsx b/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.test.tsx new file mode 100644 index 000000000000..e18d10fc5361 --- /dev/null +++ b/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 Graylog, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + */ +import * as React from 'react'; +import { render, screen } from 'wrappedTestingLibrary'; + +import PercentageField from './PercentageField'; + +describe('PercentageField', () => { + it('does not show very small values as `NaN%`', async () => { + render(); + await screen.findByText('0.00%'); + }); +}); diff --git a/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.tsx b/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.tsx index fe1ba3963c57..83f597e77b11 100644 --- a/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.tsx +++ b/graylog2-web-interface/src/views/components/fieldtypes/PercentageField.tsx @@ -16,9 +16,10 @@ */ import * as React from 'react'; import { useMemo } from 'react'; -import numeral from 'numeral'; import styled from 'styled-components'; +import { formatPercentage } from 'util/NumberFormatting'; + type Props = { value: number, } @@ -28,7 +29,7 @@ const NumberCell = styled.span` `; const PercentageField = ({ value }: Props) => { - const formatted = useMemo(() => numeral(value).format('0.00%'), [value]); + const formatted = useMemo(() => formatPercentage(value), [value]); return {formatted}; }; diff --git a/graylog2-web-interface/src/views/components/messagelist/FormatNumber.ts b/graylog2-web-interface/src/views/components/messagelist/FormatNumber.ts index 10fb6c852654..9a52e25a84d7 100644 --- a/graylog2-web-interface/src/views/components/messagelist/FormatNumber.ts +++ b/graylog2-web-interface/src/views/components/messagelist/FormatNumber.ts @@ -14,8 +14,8 @@ * along with this program. If not, see * . */ -import numeral from 'numeral'; +import { formatNumber as _formatNumber } from 'util/NumberFormatting'; -const formatNumber = (value: number): string => numeral(value).format('0,0.[0000000]'); +const formatNumber = (value: number): string => _formatNumber(value, { maximumFractionDigits: 7 }); export default formatNumber;