From 35ae97d54a6214927704dde59c78701cddc85f7f Mon Sep 17 00:00:00 2001 From: sharevb Date: Fri, 6 Sep 2024 19:00:38 +0200 Subject: [PATCH 1/5] feat(new tools): Data Storage/Transfer Units Converter Fix #539 #785 #1160 #848 --- ...ata-storage-unit-converter.service.test.ts | 36 ++++++++++ .../data-storage-unit-converter.service.ts | 24 +++++++ .../data-storage-unit-converter.vue | 70 +++++++++++++++++++ .../data-storage-unit-converter/index.ts | 16 +++++ src/tools/index.ts | 2 + 5 files changed, 148 insertions(+) create mode 100644 src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts create mode 100644 src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts create mode 100644 src/tools/data-storage-unit-converter/data-storage-unit-converter.vue create mode 100644 src/tools/data-storage-unit-converter/index.ts diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts new file mode 100644 index 00000000..c145140f --- /dev/null +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'vitest'; +import { convertStorageAndRateUnits } from './data-storage-unit-converter.service'; + +describe('data-storage-unit-converter', () => { + describe('convertStorageAndRateUnits', () => { + it('convert from same base units', () => { + expect(convertStorageAndRateUnits({ value: 1024 * 1024, fromUnit: 'B', toUnit: 'MiB' })).toBe('1'); + expect(convertStorageAndRateUnits({ value: 1024, fromUnit: 'KiB', toUnit: 'MiB' })).toBe('1'); + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'MiB', toUnit: 'KiB' })).toBe('1,024'); + expect(convertStorageAndRateUnits({ value: 1000, fromUnit: 'MB', toUnit: 'GB' })).toBe('1'); + expect(convertStorageAndRateUnits({ value: 1024, fromUnit: 'MB', toUnit: 'MB' })).toBe('1,024'); + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'MB', toUnit: 'KB' })).toBe('1,000'); + expect(convertStorageAndRateUnits({ value: 1024, fromUnit: 'MiB', toUnit: 'GiB' })).toBe('1'); + expect(convertStorageAndRateUnits({ value: 1000, fromUnit: 'MB', toUnit: 'GB' })).toBe('1'); + expect(convertStorageAndRateUnits({ value: 1000, fromUnit: 'Mb', toUnit: 'Gb' })).toBe('1'); + }); + + it('convert between base units', () => { + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'MB', toUnit: 'MiB' })).toBe('0.954'); + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1.049'); + expect(convertStorageAndRateUnits({ value: 1000 * 1000, fromUnit: 'B', toUnit: 'MiB' })).toBe('0.954'); + expect(convertStorageAndRateUnits({ value: 1024, fromUnit: 'KB', toUnit: 'MiB' })).toBe('0.977'); + expect(convertStorageAndRateUnits({ value: 1000, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1,048.576'); + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'MB', toUnit: 'Mb' })).toBe('8'); + expect(convertStorageAndRateUnits({ value: 1000, fromUnit: 'KB', toUnit: 'Kb' })).toBe('8,000'); + expect(convertStorageAndRateUnits({ value: 1000, fromUnit: 'KiB', toUnit: 'Kb' })).toBe('8,192'); + expect(convertStorageAndRateUnits({ value: 8, fromUnit: 'Mb', toUnit: 'MB' })).toBe('1'); + + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'Mb', toUnit: 'KB' })).toBe('125'); + expect(convertStorageAndRateUnits({ value: 125, fromUnit: 'KB', toUnit: 'Mb' })).toBe('1'); + + expect(convertStorageAndRateUnits({ value: 1, fromUnit: 'MiB', toUnit: 'Kb' })).toBe('8,388.608'); + expect(convertStorageAndRateUnits({ value: 8388.608, fromUnit: 'Kb', toUnit: 'MiB' })).toBe('1'); + }); + }); +}); diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts new file mode 100644 index 00000000..39d836d2 --- /dev/null +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts @@ -0,0 +1,24 @@ +export function convertStorageAndRateUnits( + { value, fromUnit, toUnit, precision = 3 }: + { value: number; fromUnit: string; toUnit: string; precision?: number }): string { + const units = [ + 'iB', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', + 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', + 'b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb', + ]; + + const fromIndex = units.indexOf(fromUnit); + const fromFactor = fromIndex / 9 > 1 ? 1000 : 1024; + const fromDivisor = fromIndex / 9 > 2 ? 8 : 1; + const toIndex = units.indexOf(toUnit); + const toFactor = toIndex / 9 > 1 ? 1000 : 1024; + const toDivisor = toIndex / 9 > 2 ? 8 : 1; + + const fromBase = (fromFactor ** (fromIndex % 9)) / fromDivisor; + const toBase = (toFactor ** (toIndex % 9)) / toDivisor; + + const result = value * fromBase / toBase; + return result.toLocaleString(undefined, { + maximumFractionDigits: precision, + }); +} diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue b/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue new file mode 100644 index 00000000..ef82702f --- /dev/null +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue @@ -0,0 +1,70 @@ + + + diff --git a/src/tools/data-storage-unit-converter/index.ts b/src/tools/data-storage-unit-converter/index.ts new file mode 100644 index 00000000..b1ccc2a9 --- /dev/null +++ b/src/tools/data-storage-unit-converter/index.ts @@ -0,0 +1,16 @@ +import { ArrowsLeftRight } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Data Storage Unit converter', + path: '/data-storage-unit-converter', + description: 'Convert data storage or transfer units (bytes, bibytes, bits, kilobytes...)', + keywords: ['data', 'storage', 'unit', 'conversion', + 'bits', 'bytes', 'bibytes', 'binary', + 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', + 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', + 'b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb'], + component: () => import('./data-storage-unit-converter.vue'), + icon: ArrowsLeftRight, + createdAt: new Date('2024-08-15'), +}); diff --git a/src/tools/index.ts b/src/tools/index.ts index c9003fe8..ca7b0a87 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -2,6 +2,8 @@ import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64StringConverter } from './base64-string-converter'; import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as emailNormalizer } from './email-normalizer'; +import { tool as dataTransferRate } from './data-transfer-rate'; +import { tool as dataStorageUnitConverter } from './data-storage-unit-converter'; import { tool as asciiTextDrawer } from './ascii-text-drawer'; From 49aa769bb816ed99ff281ef8f26f126fbc467795 Mon Sep 17 00:00:00 2001 From: sharevb Date: Fri, 6 Sep 2024 19:00:38 +0200 Subject: [PATCH 2/5] feat(new tools): Data Storage Units Converter and Data Transfer Rate Converter New Tool: Data Transfer Rate Converter New Tool: Data Storage Units Converter (with MB, MiB and Mb) Fix #539 #785 #1160 #848 Data Storage Units Converter inspired by #948 by @utf26 --- ...ata-storage-unit-converter.service.test.ts | 54 +++++ .../data-storage-unit-converter.service.ts | 47 ++++ .../data-storage-unit-converter.vue | 71 ++++++ .../data-storage-unit-converter/index.ts | 16 ++ ...ta-transfer-rate-converter.service.test.ts | 39 ++++ .../data-transfer-rate-converter.service.ts | 57 +++++ .../data-transfer-rate-converter.vue | 217 ++++++++++++++++++ .../data-transfer-rate-converter/index.ts | 12 + src/tools/index.ts | 10 +- 9 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts create mode 100644 src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts create mode 100644 src/tools/data-storage-unit-converter/data-storage-unit-converter.vue create mode 100644 src/tools/data-storage-unit-converter/index.ts create mode 100644 src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts create mode 100644 src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts create mode 100644 src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue create mode 100644 src/tools/data-transfer-rate-converter/index.ts diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts new file mode 100644 index 00000000..d65385e4 --- /dev/null +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from 'vitest'; +import { convertStorageAndRateUnitsDisplay, displayStorageAndRateUnits } from './data-storage-unit-converter.service'; + +describe('data-storage-unit-converter', () => { + describe('convertStorageAndRateUnitsDisplay', () => { + it('convert from same base units', () => { + expect(convertStorageAndRateUnitsDisplay({ value: 1024 * 1024, fromUnit: 'B', toUnit: 'MiB' })).toBe('1'); + expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'KiB', toUnit: 'MiB' })).toBe('1'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'KiB' })).toBe('1,024'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MB', toUnit: 'GB' })).toBe('1'); + expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'MB', toUnit: 'MB' })).toBe('1,024'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MB', toUnit: 'KB' })).toBe('1,000'); + expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'MiB', toUnit: 'GiB' })).toBe('1'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MB', toUnit: 'GB' })).toBe('1'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'Mb', toUnit: 'Gb' })).toBe('1'); + }); + + it('convert between base units', () => { + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MB', toUnit: 'MiB' })).toBe('0.954'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1.049'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000 * 1000, fromUnit: 'B', toUnit: 'MiB' })).toBe('0.954'); + expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'KB', toUnit: 'MiB' })).toBe('0.977'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1,048.576'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MB', toUnit: 'Mb' })).toBe('8'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'KB', toUnit: 'Kb' })).toBe('8,000'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'KiB', toUnit: 'Kb' })).toBe('8,192'); + expect(convertStorageAndRateUnitsDisplay({ value: 8, fromUnit: 'Mb', toUnit: 'MB' })).toBe('1'); + + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'Mb', toUnit: 'KB' })).toBe('125'); + expect(convertStorageAndRateUnitsDisplay({ value: 125, fromUnit: 'KB', toUnit: 'Mb' })).toBe('1'); + + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'Kb' })).toBe('8,388.608'); + expect(convertStorageAndRateUnitsDisplay({ value: 8388.608, fromUnit: 'Kb', toUnit: 'MiB' })).toBe('1'); + }); + it('convert with unit display', () => { + expect(convertStorageAndRateUnitsDisplay({ value: 1024 * 1024, fromUnit: 'B', toUnit: 'MiB', appendUnit: true })).toBe('1MiB'); + }); + + // + }); + describe('displayStorageAndRateUnits', () => { + it('convert to correct display value', () => { + expect(displayStorageAndRateUnits({ + value: 1.234567, unit: 'MB', appendUnit: false, + })).toBe('1.235'); + expect(displayStorageAndRateUnits({ + value: 1.234567, unit: 'MB', appendUnit: true, + })).toBe('1.235MB'); + expect(displayStorageAndRateUnits({ + value: 1.234567, unit: 'MB', appendUnit: true, precision: 5, + })).toBe('1.23457MB'); + }); + }); +}); diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts new file mode 100644 index 00000000..f9363496 --- /dev/null +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts @@ -0,0 +1,47 @@ +export type BibytesUnits = 'iB' | 'KiB' | 'MiB' | 'GiB' | 'TiB' | 'PiB' | 'EiB' | 'ZiB' | 'YiB'; +export type BytesUnits = 'B' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'; +export type BitsUnits = 'b' | 'Kb' | 'Mb' | 'Gb' | 'Tb' | 'Pb' | 'Eb' | 'Zb' | 'Yb'; +export type AllSupportedUnits = BibytesUnits | BytesUnits | BitsUnits; + +export function displayStorageAndRateUnits( + { value, unit, precision = 3, appendUnit = false }: + { value: number; unit: AllSupportedUnits; precision?: number ; appendUnit?: boolean }): string { + return value.toLocaleString(undefined, { + maximumFractionDigits: precision, + }) + (appendUnit ? unit : ''); +} + +export function convertStorageAndRateUnitsDisplay( + { value, fromUnit, toUnit, precision = 3, appendUnit = false }: + { value: number; fromUnit: AllSupportedUnits; toUnit: AllSupportedUnits; precision?: number; appendUnit?: boolean }): string { + return displayStorageAndRateUnits({ + precision, + unit: toUnit, + appendUnit, + value: convertStorageAndRateUnits({ + value, fromUnit, toUnit, + }), + }); +} + +export function convertStorageAndRateUnits( + { value, fromUnit, toUnit }: + { value: number; fromUnit: AllSupportedUnits; toUnit: AllSupportedUnits }): number { + const units = [ + 'iB', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', + 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', + 'b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb', + ]; + + const fromIndex = units.indexOf(fromUnit); + const fromFactor = fromIndex / 9 > 1 ? 1000 : 1024; + const fromDivisor = fromIndex / 9 > 2 ? 8 : 1; + const toIndex = units.indexOf(toUnit); + const toFactor = toIndex / 9 > 1 ? 1000 : 1024; + const toDivisor = toIndex / 9 > 2 ? 8 : 1; + + const fromBase = (fromFactor ** (fromIndex % 9)) / fromDivisor; + const toBase = (toFactor ** (toIndex % 9)) / toDivisor; + + return value * fromBase / toBase; +} diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue b/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue new file mode 100644 index 00000000..457c8b6c --- /dev/null +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/tools/data-storage-unit-converter/index.ts b/src/tools/data-storage-unit-converter/index.ts new file mode 100644 index 00000000..b1ccc2a9 --- /dev/null +++ b/src/tools/data-storage-unit-converter/index.ts @@ -0,0 +1,16 @@ +import { ArrowsLeftRight } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Data Storage Unit converter', + path: '/data-storage-unit-converter', + description: 'Convert data storage or transfer units (bytes, bibytes, bits, kilobytes...)', + keywords: ['data', 'storage', 'unit', 'conversion', + 'bits', 'bytes', 'bibytes', 'binary', + 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', + 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', + 'b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb'], + component: () => import('./data-storage-unit-converter.vue'), + icon: ArrowsLeftRight, + createdAt: new Date('2024-08-15'), +}); diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts new file mode 100644 index 00000000..9e6b9e86 --- /dev/null +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest'; +import { amountTransferable, neededRate, transferTimeSeconds } from './data-transfer-rate-converter.service'; + +describe('data-transfer-converter', () => { + describe('transferTimeSeconds', () => { + it('compute transfer time in seconds', () => { + expect(transferTimeSeconds({ + dataSize: 100, + dataSizeUnit: 'MB', + bitRate: 10, + bitRateUnit: 'Mb', + })).toBe(80); + }); + }); + describe('neededRate', () => { + it('compute neededRate', () => { + expect(neededRate({ + dataSize: 100, + dataSizeUnit: 'MB', + hours: 0, + minutes: 1, + seconds: 20, + bitRateUnit: 'Mb', + })).toBe(10); + }); + }); + describe('amountTransferable', () => { + it('compute amount transfered', () => { + expect(amountTransferable({ + bitRate: 10, + bitRateUnit: 'Mb', + hours: 1, + minutes: 0, + seconds: 0, + dataSizeUnit: 'MB', + })).toBe(4500); + }); + }); +}); diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts new file mode 100644 index 00000000..3ef1b7bd --- /dev/null +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts @@ -0,0 +1,57 @@ +import { type AllSupportedUnits, type BitsUnits, convertStorageAndRateUnits } from '../data-storage-unit-converter/data-storage-unit-converter.service'; + +export function transferTimeSeconds({ + dataSize, + dataSizeUnit, + bitRate, + bitRateUnit, +}: { + dataSize: number + dataSizeUnit: AllSupportedUnits + bitRate: number + bitRateUnit: BitsUnits +}): number { + const dataSizeInBytes = convertStorageAndRateUnits({ value: dataSize, fromUnit: dataSizeUnit, toUnit: 'B' }); + const bitRateInBytes = convertStorageAndRateUnits({ value: bitRate, fromUnit: bitRateUnit, toUnit: 'B' }); + return bitRateInBytes > 0 ? dataSizeInBytes / bitRateInBytes : 0; +} + +export function neededRate({ + dataSize, + dataSizeUnit, + hours, + minutes, + seconds, + bitRateUnit, +}: { + dataSize: number + dataSizeUnit: AllSupportedUnits + hours: number + minutes: number + seconds: number + bitRateUnit: BitsUnits +}): number { + const dataSizeInBits = convertStorageAndRateUnits({ value: dataSize, fromUnit: dataSizeUnit, toUnit: 'b' }); + const timeInSeconds = hours * 3600 + minutes * 60 + seconds; + return convertStorageAndRateUnits({ value: timeInSeconds > 0 ? dataSizeInBits / timeInSeconds : 0, fromUnit: 'b', toUnit: bitRateUnit }); +} + +export function amountTransferable({ + bitRate, + bitRateUnit, + hours, + minutes, + seconds, + dataSizeUnit, +}: { + bitRate: number + bitRateUnit: BitsUnits + hours: number + minutes: number + seconds: number + dataSizeUnit: AllSupportedUnits +}): number { + const bitRateInBytes = convertStorageAndRateUnits({ value: bitRate, fromUnit: bitRateUnit, toUnit: 'B' }); + const timeInSeconds = hours * 3600 + minutes * 60 + seconds; + return convertStorageAndRateUnits({ value: bitRateInBytes * timeInSeconds, fromUnit: 'B', toUnit: dataSizeUnit }); +} diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue new file mode 100644 index 00000000..b4e492be --- /dev/null +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue @@ -0,0 +1,217 @@ + + + diff --git a/src/tools/data-transfer-rate-converter/index.ts b/src/tools/data-transfer-rate-converter/index.ts new file mode 100644 index 00000000..cf3f520a --- /dev/null +++ b/src/tools/data-transfer-rate-converter/index.ts @@ -0,0 +1,12 @@ +import { TransferIn } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Data Transfer Rate Calculator', + path: '/data-transfer-rate-converter', + description: 'Compute Data Transfer times, rates and amount of data', + keywords: ['data', 'transfer', 'rate', 'convert', 'time'], + component: () => import('./data-transfer-rate-converter.vue'), + icon: TransferIn, + createdAt: new Date('2024-08-15'), +}); diff --git a/src/tools/index.ts b/src/tools/index.ts index c9003fe8..498e8abe 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -2,6 +2,8 @@ import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64StringConverter } from './base64-string-converter'; import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as emailNormalizer } from './email-normalizer'; +import { tool as dataTransferRateConverter } from './data-transfer-rate-converter'; +import { tool as dataStorageUnitConverter } from './data-storage-unit-converter'; import { tool as asciiTextDrawer } from './ascii-text-drawer'; @@ -164,7 +166,13 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Math', - components: [mathEvaluator, etaCalculator, percentageCalculator], + components: [ + mathEvaluator, + etaCalculator, + percentageCalculator, + dataTransferRateConverter, + dataStorageUnitConverter, + ], }, { name: 'Measurement', From 66dd351d4820bd6af0f736789c1ac5d17857d732 Mon Sep 17 00:00:00 2001 From: ShareVB Date: Wed, 11 Sep 2024 23:30:37 +0200 Subject: [PATCH 3/5] fix: display numbers always with dot --- components.d.ts | 2 ++ .../data-storage-unit-converter.service.test.ts | 14 +++++++------- .../data-storage-unit-converter.service.ts | 4 +--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components.d.ts b/components.d.ts index 8e59366a..96649b11 100644 --- a/components.d.ts +++ b/components.d.ts @@ -64,6 +64,8 @@ declare module '@vue/runtime-core' { 'CTextCopyable.demo': typeof import('./src/ui/c-text-copyable/c-text-copyable.demo.vue')['default'] CTooltip: typeof import('./src/ui/c-tooltip/c-tooltip.vue')['default'] 'CTooltip.demo': typeof import('./src/ui/c-tooltip/c-tooltip.demo.vue')['default'] + DataStorageUnitConverter: typeof import('./src/tools/data-storage-unit-converter/data-storage-unit-converter.vue')['default'] + DataTransferRateConverter: typeof import('./src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue')['default'] DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default'] 'DemoHome.page': typeof import('./src/ui/demo/demo-home.page.vue')['default'] DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default'] diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts index d65385e4..32786478 100644 --- a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.test.ts @@ -6,10 +6,10 @@ describe('data-storage-unit-converter', () => { it('convert from same base units', () => { expect(convertStorageAndRateUnitsDisplay({ value: 1024 * 1024, fromUnit: 'B', toUnit: 'MiB' })).toBe('1'); expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'KiB', toUnit: 'MiB' })).toBe('1'); - expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'KiB' })).toBe('1,024'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'KiB' })).toBe('1024'); expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MB', toUnit: 'GB' })).toBe('1'); - expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'MB', toUnit: 'MB' })).toBe('1,024'); - expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MB', toUnit: 'KB' })).toBe('1,000'); + expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'MB', toUnit: 'MB' })).toBe('1024'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MB', toUnit: 'KB' })).toBe('1000'); expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'MiB', toUnit: 'GiB' })).toBe('1'); expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MB', toUnit: 'GB' })).toBe('1'); expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'Mb', toUnit: 'Gb' })).toBe('1'); @@ -20,16 +20,16 @@ describe('data-storage-unit-converter', () => { expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1.049'); expect(convertStorageAndRateUnitsDisplay({ value: 1000 * 1000, fromUnit: 'B', toUnit: 'MiB' })).toBe('0.954'); expect(convertStorageAndRateUnitsDisplay({ value: 1024, fromUnit: 'KB', toUnit: 'MiB' })).toBe('0.977'); - expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1,048.576'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'MiB', toUnit: 'MB' })).toBe('1048.576'); expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MB', toUnit: 'Mb' })).toBe('8'); - expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'KB', toUnit: 'Kb' })).toBe('8,000'); - expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'KiB', toUnit: 'Kb' })).toBe('8,192'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'KB', toUnit: 'Kb' })).toBe('8000'); + expect(convertStorageAndRateUnitsDisplay({ value: 1000, fromUnit: 'KiB', toUnit: 'Kb' })).toBe('8192'); expect(convertStorageAndRateUnitsDisplay({ value: 8, fromUnit: 'Mb', toUnit: 'MB' })).toBe('1'); expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'Mb', toUnit: 'KB' })).toBe('125'); expect(convertStorageAndRateUnitsDisplay({ value: 125, fromUnit: 'KB', toUnit: 'Mb' })).toBe('1'); - expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'Kb' })).toBe('8,388.608'); + expect(convertStorageAndRateUnitsDisplay({ value: 1, fromUnit: 'MiB', toUnit: 'Kb' })).toBe('8388.608'); expect(convertStorageAndRateUnitsDisplay({ value: 8388.608, fromUnit: 'Kb', toUnit: 'MiB' })).toBe('1'); }); it('convert with unit display', () => { diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts index f9363496..e5e19a29 100644 --- a/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.service.ts @@ -6,9 +6,7 @@ export type AllSupportedUnits = BibytesUnits | BytesUnits | BitsUnits; export function displayStorageAndRateUnits( { value, unit, precision = 3, appendUnit = false }: { value: number; unit: AllSupportedUnits; precision?: number ; appendUnit?: boolean }): string { - return value.toLocaleString(undefined, { - maximumFractionDigits: precision, - }) + (appendUnit ? unit : ''); + return value.toFixed(precision).replace(/0+$/, '').replace(/\.$/, '') + (appendUnit ? unit : ''); // NOSONAR } export function convertStorageAndRateUnitsDisplay( From 7856df391889647209c944fe0bf5905df3e72d93 Mon Sep 17 00:00:00 2001 From: ShareVB Date: Sat, 21 Sep 2024 10:06:54 +0200 Subject: [PATCH 4/5] feat: add label for units --- components.d.ts | 3 ++ .../data-storage-unit-converter.vue | 33 ++++++++++++++++--- .../data-transfer-rate-converter.vue | 33 +++++++++++++++++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/components.d.ts b/components.d.ts index 96649b11..8b46352f 100644 --- a/components.d.ts +++ b/components.d.ts @@ -133,15 +133,18 @@ declare module '@vue/runtime-core' { MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] NButton: typeof import('naive-ui')['NButton'] + NCheckbox: typeof import('naive-ui')['NCheckbox'] NCode: typeof import('naive-ui')['NCode'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] + NDivider: typeof import('naive-ui')['NDivider'] NEllipsis: typeof import('naive-ui')['NEllipsis'] NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] NH1: typeof import('naive-ui')['NH1'] NH3: typeof import('naive-ui')['NH3'] NIcon: typeof import('naive-ui')['NIcon'] + NInput: typeof import('naive-ui')['NInput'] NInputNumber: typeof import('naive-ui')['NInputNumber'] NLayout: typeof import('naive-ui')['NLayout'] NLayoutSider: typeof import('naive-ui')['NLayoutSider'] diff --git a/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue b/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue index 457c8b6c..44233734 100644 --- a/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue +++ b/src/tools/data-storage-unit-converter/data-storage-unit-converter.vue @@ -6,9 +6,34 @@ const input = ref<{ size: string; unit: string }>({ size: '0', unit: 'KB' }); const output = ref<{ unit: string; precision: number; appendUnit: boolean }>({ unit: 'MB', precision: 3, appendUnit: false }); const allUnits = [ - 'iB', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', - 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', - 'b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb']; + { value: 'B', label: 'Bytes (B)' }, + { value: 'b', label: 'Bits (bit)' }, + { value: 'iB', label: 'Bibytes (iB)' }, + { value: 'KB', label: 'Kilobytes (KB)' }, + { value: 'Kb', label: 'Kilobits (Kbit)' }, + { value: 'KiB', label: 'Kibibytes (KiB)' }, + { value: 'MB', label: 'Megabytes (MB)' }, + { value: 'Mb', label: 'Megabits (Mbit)' }, + { value: 'MiB', label: 'Mebibytes (MiB)' }, + { value: 'GB', label: 'Gigabytes (GB)' }, + { value: 'Gb', label: 'Gigabits (Gbit)' }, + { value: 'GiB', label: 'Gibibytes (GiB)' }, + { value: 'TB', label: 'Terabytes (TB)' }, + { value: 'Tb', label: 'Terabits (Tbit)' }, + { value: 'TiB', label: 'Tebibytes (TiB)' }, + { value: 'PB', label: 'Petabytes (PB)' }, + { value: 'Pb', label: 'Petabits (Pbit)' }, + { value: 'PiB', label: 'Pebibytes (PiB)' }, + { value: 'EB', label: 'Exabytes (EB)' }, + { value: 'Eb', label: 'Exabits (Ebit)' }, + { value: 'EiB', label: 'Exbibytes (EiB)' }, + { value: 'ZB', label: 'Zettabytes (ZB)' }, + { value: 'Zb', label: 'Zettabits (Zbit)' }, + { value: 'ZiB', label: 'Zebibytes (ZiB)' }, + { value: 'YB', label: 'Yottabytes (YB)' }, + { value: 'Yb', label: 'Yottabits (Ybit)' }, + { value: 'YiB', label: 'Yobibytes (YiB)' }, +]; const convertedValue = computed(() => { try { @@ -51,7 +76,7 @@ const convertedValue = computed(() => { /> - + diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue index b4e492be..2be19cbb 100644 --- a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue @@ -4,9 +4,36 @@ import { type AllSupportedUnits, type BitsUnits, displayStorageAndRateUnits } fr import { amountTransferable, neededRate, transferTimeSeconds } from './data-transfer-rate-converter.service'; const allStorateUnits = [ - 'iB', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', - 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; -const allBitsUnits = ['b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb']; + { value: 'B', label: 'Bytes (B)' }, + { value: 'iB', label: 'Bibytes (iB)' }, + { value: 'KB', label: 'Kilobytes (KB)' }, + { value: 'KiB', label: 'Kibibytes (KiB)' }, + { value: 'MB', label: 'Megabytes (MB)' }, + { value: 'MiB', label: 'Mebibytes (MiB)' }, + { value: 'GB', label: 'Gigabytes (GB)' }, + { value: 'GiB', label: 'Gibibytes (GiB)' }, + { value: 'TB', label: 'Terabytes (TB)' }, + { value: 'TiB', label: 'Tebibytes (TiB)' }, + { value: 'PB', label: 'Petabytes (PB)' }, + { value: 'PiB', label: 'Pebibytes (PiB)' }, + { value: 'EB', label: 'Exabytes (EB)' }, + { value: 'EiB', label: 'Exbibytes (EiB)' }, + { value: 'ZB', label: 'Zettabytes (ZB)' }, + { value: 'ZiB', label: 'Zebibytes (ZiB)' }, + { value: 'YB', label: 'Yottabytes (YB)' }, + { value: 'YiB', label: 'Yobibytes (YiB)' }, +]; +const allBitsUnits = [ + { value: 'b', label: 'Bits (bit)' }, + { value: 'Kb', label: 'Kilobits (Kbit)' }, + { value: 'Mb', label: 'Megabits (Mbit)' }, + { value: 'Gb', label: 'Gigabits (Gbit)' }, + { value: 'Tb', label: 'Terabits (Tbit)' }, + { value: 'Pb', label: 'Petabits (Pbit)' }, + { value: 'Eb', label: 'Exabits (Ebit)' }, + { value: 'Zb', label: 'Zettabits (Zbit)' }, + { value: 'Yb', label: 'Yottabits (Ybit)' }, +]; function convertToTimeDisplay(seconds: number) { if (seconds === 0) { From edfb3f575be10f2021350ed4d84e98c606785eb3 Mon Sep 17 00:00:00 2001 From: ShareVB Date: Thu, 2 Jan 2025 00:18:38 +0100 Subject: [PATCH 5/5] fix: allow all units for bitrate ie, in case of download speed in MB/s --- .eslintrc-auto-import.json | 5 +- auto-imports.d.ts | 9 +++ ...ta-transfer-rate-converter.service.test.ts | 16 ++++-- .../data-transfer-rate-converter.service.ts | 10 ++-- .../data-transfer-rate-converter.vue | 56 ++++++++++--------- 5 files changed, 59 insertions(+), 37 deletions(-) diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json index 4084d922..d4fd5aac 100644 --- a/.eslintrc-auto-import.json +++ b/.eslintrc-auto-import.json @@ -286,6 +286,9 @@ "watchTriggerable": true, "watchWithFilter": true, "whenever": true, - "toValue": true + "toValue": true, + "injectLocal": true, + "provideLocal": true, + "useClipboardItems": true } } diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 186963f1..35bda113 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -36,6 +36,7 @@ declare global { const h: typeof import('vue')['h'] const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] const inject: typeof import('vue')['inject'] + const injectLocal: typeof import('@vueuse/core')['injectLocal'] const isDefined: typeof import('@vueuse/core')['isDefined'] const isProxy: typeof import('vue')['isProxy'] const isReactive: typeof import('vue')['isReactive'] @@ -65,6 +66,7 @@ declare global { const onUpdated: typeof import('vue')['onUpdated'] const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] const provide: typeof import('vue')['provide'] + const provideLocal: typeof import('@vueuse/core')['provideLocal'] const reactify: typeof import('@vueuse/core')['reactify'] const reactifyObject: typeof import('@vueuse/core')['reactifyObject'] const reactive: typeof import('vue')['reactive'] @@ -128,6 +130,7 @@ declare global { const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] const useCached: typeof import('@vueuse/core')['useCached'] const useClipboard: typeof import('@vueuse/core')['useClipboard'] + const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems'] const useCloned: typeof import('@vueuse/core')['useCloned'] const useColorMode: typeof import('@vueuse/core')['useColorMode'] const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] @@ -326,6 +329,7 @@ declare module 'vue' { readonly h: UnwrapRef readonly ignorableWatch: UnwrapRef readonly inject: UnwrapRef + readonly injectLocal: UnwrapRef readonly isDefined: UnwrapRef readonly isProxy: UnwrapRef readonly isReactive: UnwrapRef @@ -355,6 +359,7 @@ declare module 'vue' { readonly onUpdated: UnwrapRef readonly pausableWatch: UnwrapRef readonly provide: UnwrapRef + readonly provideLocal: UnwrapRef readonly reactify: UnwrapRef readonly reactifyObject: UnwrapRef readonly reactive: UnwrapRef @@ -418,6 +423,7 @@ declare module 'vue' { readonly useBrowserLocation: UnwrapRef readonly useCached: UnwrapRef readonly useClipboard: UnwrapRef + readonly useClipboardItems: UnwrapRef readonly useCloned: UnwrapRef readonly useColorMode: UnwrapRef readonly useConfirmDialog: UnwrapRef @@ -610,6 +616,7 @@ declare module '@vue/runtime-core' { readonly h: UnwrapRef readonly ignorableWatch: UnwrapRef readonly inject: UnwrapRef + readonly injectLocal: UnwrapRef readonly isDefined: UnwrapRef readonly isProxy: UnwrapRef readonly isReactive: UnwrapRef @@ -639,6 +646,7 @@ declare module '@vue/runtime-core' { readonly onUpdated: UnwrapRef readonly pausableWatch: UnwrapRef readonly provide: UnwrapRef + readonly provideLocal: UnwrapRef readonly reactify: UnwrapRef readonly reactifyObject: UnwrapRef readonly reactive: UnwrapRef @@ -702,6 +710,7 @@ declare module '@vue/runtime-core' { readonly useBrowserLocation: UnwrapRef readonly useCached: UnwrapRef readonly useClipboard: UnwrapRef + readonly useClipboardItems: UnwrapRef readonly useCloned: UnwrapRef readonly useColorMode: UnwrapRef readonly useConfirmDialog: UnwrapRef diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts index 9e6b9e86..860ed096 100644 --- a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { amountTransferable, neededRate, transferTimeSeconds } from './data-transfer-rate-converter.service'; +import { amountTransferable, transferSpeedRate, transferTimeSeconds } from './data-transfer-rate-converter.service'; describe('data-transfer-converter', () => { describe('transferTimeSeconds', () => { @@ -12,9 +12,9 @@ describe('data-transfer-converter', () => { })).toBe(80); }); }); - describe('neededRate', () => { - it('compute neededRate', () => { - expect(neededRate({ + describe('transferSpeedRate', () => { + it('compute transferSpeedRate', () => { + expect(transferSpeedRate({ dataSize: 100, dataSizeUnit: 'MB', hours: 0, @@ -22,6 +22,14 @@ describe('data-transfer-converter', () => { seconds: 20, bitRateUnit: 'Mb', })).toBe(10); + expect(transferSpeedRate({ + dataSize: 100, + dataSizeUnit: 'MB', + hours: 0, + minutes: 1, + seconds: 20, + bitRateUnit: 'MB', + })).toBe(1.25); }); }); describe('amountTransferable', () => { diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts index 3ef1b7bd..0ececcc1 100644 --- a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.service.ts @@ -1,4 +1,4 @@ -import { type AllSupportedUnits, type BitsUnits, convertStorageAndRateUnits } from '../data-storage-unit-converter/data-storage-unit-converter.service'; +import { type AllSupportedUnits, convertStorageAndRateUnits } from '../data-storage-unit-converter/data-storage-unit-converter.service'; export function transferTimeSeconds({ dataSize, @@ -9,14 +9,14 @@ export function transferTimeSeconds({ dataSize: number dataSizeUnit: AllSupportedUnits bitRate: number - bitRateUnit: BitsUnits + bitRateUnit: AllSupportedUnits }): number { const dataSizeInBytes = convertStorageAndRateUnits({ value: dataSize, fromUnit: dataSizeUnit, toUnit: 'B' }); const bitRateInBytes = convertStorageAndRateUnits({ value: bitRate, fromUnit: bitRateUnit, toUnit: 'B' }); return bitRateInBytes > 0 ? dataSizeInBytes / bitRateInBytes : 0; } -export function neededRate({ +export function transferSpeedRate({ dataSize, dataSizeUnit, hours, @@ -29,7 +29,7 @@ export function neededRate({ hours: number minutes: number seconds: number - bitRateUnit: BitsUnits + bitRateUnit: AllSupportedUnits }): number { const dataSizeInBits = convertStorageAndRateUnits({ value: dataSize, fromUnit: dataSizeUnit, toUnit: 'b' }); const timeInSeconds = hours * 3600 + minutes * 60 + seconds; @@ -45,7 +45,7 @@ export function amountTransferable({ dataSizeUnit, }: { bitRate: number - bitRateUnit: BitsUnits + bitRateUnit: AllSupportedUnits hours: number minutes: number seconds: number diff --git a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue index 2be19cbb..a8128dcb 100644 --- a/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue +++ b/src/tools/data-transfer-rate-converter/data-transfer-rate-converter.vue @@ -1,7 +1,7 @@