MDK Logo

Utilities

Helper functions exported by @tetherto/mdk-core-ui (formatting, validation, conversions) and @tetherto/mdk-foundation-ui (settings persistence)

This page documents helper functions exported by the MDK packages.

  • Core utilities ships 15 utility modules with functions for formatting, dates, validation, conversions, class-name merging, and more
  • Foundation utilities currently ships a single public utility module (settings-utils) for parsing, validating, and exporting settings JSON

Core utilities

Helper functions exported by @tetherto/mdk-core-ui for formatting, dates, validation, conversions, and class-name merging.

Prerequisites

Import

@tetherto/mdk-core-ui
import {
  formatNumber,
  formatHashrate,
  formatDate,
  formatRelativeTime,
  cn,
  isEmpty,
  isValidEmail,
} from '@tetherto/mdk-core-ui'

Formatting utilities

formatNumber

@tetherto/mdk-core-ui

Format numbers with locale formatting and configurable options.

import { formatNumber, FALLBACK } from '@tetherto/mdk-core-ui'

formatNumber(1234.567)                          // "1,234.57"
formatNumber(null)                              // "-"
formatNumber(1234, { minimumFractionDigits: 2 }) // "1,234.00"
formatNumber(undefined, {}, 'N/A')              // "N/A"

formatHashrate

@tetherto/mdk-core-ui

Format hashrate values with rounding.

import { formatHashrate } from '@tetherto/mdk-core-ui'

formatHashrate(150.456)  // "150.46"
formatHashrate(null)     // "-"

formatCurrency

@tetherto/mdk-core-ui

Format currency values.

import { formatCurrency } from '@tetherto/mdk-core-ui'

formatCurrency(1234.56, 'USD')      // "$1,234.56"
formatCurrency(0.00012345, 'BTC')   // "₿0.00012345"

getPercentFormattedNumber

@tetherto/mdk-core-ui

Format numbers as percentages.

import { getPercentFormattedNumber } from '@tetherto/mdk-core-ui'

getPercentFormattedNumber(0.75)      // "75%"
getPercentFormattedNumber(0.1234, 1) // "12.3%"

formatValueUnit

@tetherto/mdk-core-ui

Format value-unit objects.

import { formatValueUnit } from '@tetherto/mdk-core-ui'

formatValueUnit(150, 'TH/s')  // "150 TH/s"

Date utilities

formatDate

@tetherto/mdk-core-ui

Format dates with customizable patterns.

import { formatDate } from '@tetherto/mdk-core-ui'

formatDate(new Date())                              // "Jan 15, 2025"
formatDate(1705334400000, { format: 'yyyy-MM-dd' }) // "2025-01-15"

formatRelativeTime

@tetherto/mdk-core-ui

Format dates as relative time strings.

import { formatRelativeTime } from '@tetherto/mdk-core-ui'

formatRelativeTime(new Date(Date.now() - 3600000))  // "1h ago"
formatRelativeTime(new Date(Date.now() - 86400000)) // "1d ago"

formatChartDate

@tetherto/mdk-core-ui

Format timestamps for chart display.

import { formatChartDate } from '@tetherto/mdk-core-ui'

formatChartDate(1705334400)        // "Jan 15"
formatChartDate(1705334400, true)  // "Jan 15, 2025"

isValidTimestamp

@tetherto/mdk-core-ui

Check if a timestamp is valid.

import { isValidTimestamp } from '@tetherto/mdk-core-ui'

isValidTimestamp(1705334400000)  // true
isValidTimestamp('invalid')      // false

parseMonthLabelToDate

@tetherto/mdk-core-ui

Parse month labels to Date objects.

import { parseMonthLabelToDate } from '@tetherto/mdk-core-ui'

parseMonthLabelToDate('01-26')    // Date(2026, 0, 1)
parseMonthLabelToDate('03-2025')  // Date(2025, 2, 1)

getPastDateFromDate

@tetherto/mdk-core-ui

Get a date in the past.

import { getPastDateFromDate } from '@tetherto/mdk-core-ui'

getPastDateFromDate({ dateTs: Date.now(), days: 7 })  // 7 days ago

Validation utilities

isEmpty

@tetherto/mdk-core-ui

Check if a value is empty.

import { isEmpty } from '@tetherto/mdk-core-ui'

isEmpty(null)       // true
isEmpty('')         // true
isEmpty([])         // true
isEmpty({})         // true
isEmpty('hello')    // false
isEmpty([1, 2, 3])  // false

isValidEmail

@tetherto/mdk-core-ui

Validate email addresses.

import { isValidEmail } from '@tetherto/mdk-core-ui'

isValidEmail('user@example.com')  // true
isValidEmail('invalid')           // false

isValidUrl

@tetherto/mdk-core-ui

Validate URLs.

import { isValidUrl } from '@tetherto/mdk-core-ui'

isValidUrl('https://example.com')  // true
isValidUrl('not-a-url')            // false

isNil

@tetherto/mdk-core-ui

Check if value is null or undefined.

import { isNil } from '@tetherto/mdk-core-ui'

isNil(null)       // true
isNil(undefined)  // true
isNil(0)          // false
isNil('')         // false

isPlainObject

@tetherto/mdk-core-ui

Check if value is a plain object.

import { isPlainObject } from '@tetherto/mdk-core-ui'

isPlainObject({})           // true
isPlainObject({ a: 1 })     // true
isPlainObject([])           // false
isPlainObject(new Date())   // false

Class name utilities

cn

@tetherto/mdk-core-ui

Merge class names using clsx and tailwind-merge.

import { cn } from '@tetherto/mdk-core-ui'

cn('px-4', 'py-2')                    // "px-4 py-2"
cn('text-red', isError && 'bg-red')   // conditional classes
cn('p-4', { 'hidden': !visible })     // object syntax

Conversion utilities

toMW / toMWh

@tetherto/mdk-core-ui

Convert watts to megawatts.

import { toMW, toMWh } from '@tetherto/mdk-core-ui'

toMW(1000000)   // 1
toMWh(1000000)  // 1

toPHS

@tetherto/mdk-core-ui

Convert raw hashrate to PH/s.

import { toPHS } from '@tetherto/mdk-core-ui'

toPHS(1000000000000000)  // 1

convertMpaToBar

@tetherto/mdk-core-ui

Convert pressure units.

import { convertMpaToBar } from '@tetherto/mdk-core-ui'

convertMpaToBar(0.1)  // 1

unitToKilo

@tetherto/mdk-core-ui

Convert to kilo units.

import { unitToKilo } from '@tetherto/mdk-core-ui'

unitToKilo(1000)  // 1

Number utilities

percentage

@tetherto/mdk-core-ui

Calculate percentage.

import { percentage } from '@tetherto/mdk-core-ui'

percentage(25, 100)  // 25
percentage(1, 4)     // 25

getPercentChange

@tetherto/mdk-core-ui

Calculate percentage change.

import { getPercentChange } from '@tetherto/mdk-core-ui'

getPercentChange(110, 100)  // 10
getPercentChange(90, 100)   // -10

convertUnits

@tetherto/mdk-core-ui

Convert between SI-prefix units.

import { convertUnits } from '@tetherto/mdk-core-ui'

convertUnits(1, 'k', 'M')           // 0.001
convertUnits(1000, 'decimal', 'k')  // 1

safeNumber

@tetherto/mdk-core-ui

Safely convert to number.

import { safeNumber } from '@tetherto/mdk-core-ui'

safeNumber('123')      // 123
safeNumber('invalid')  // 0
safeNumber(null)       // 0

String utilities

toTitleCase

@tetherto/mdk-core-ui

Convert string to Title Case.

import { toTitleCase } from '@tetherto/mdk-core-ui'

toTitleCase('hello world')  // "Hello World"

formatMacAddress

@tetherto/mdk-core-ui

Format MAC addresses.

import { formatMacAddress } from '@tetherto/mdk-core-ui'

formatMacAddress('aa:bb:cc:dd:ee:ff')  // "AA:BB:CC:DD:EE:FF"

safeString

@tetherto/mdk-core-ui

Safely convert to string.

import { safeString } from '@tetherto/mdk-core-ui'

safeString(123)    // "123"
safeString(null)   // ""

Time utilities

secondsToMs

@tetherto/mdk-core-ui

Convert seconds to milliseconds.

import { secondsToMs } from '@tetherto/mdk-core-ui'

secondsToMs(60)  // 60000

breakTimeIntoIntervals

@tetherto/mdk-core-ui

Split time range into intervals.

import { breakTimeIntoIntervals } from '@tetherto/mdk-core-ui'

breakTimeIntoIntervals(start, end, 3600000)  // Array of 1-hour intervals

timeRangeWalker

@tetherto/mdk-core-ui

Generator for iterating through time ranges.

import { timeRangeWalker } from '@tetherto/mdk-core-ui'

for (const interval of timeRangeWalker(start, end, duration)) {
  // Process each interval
}

Color utilities

hexToRgba

@tetherto/mdk-core-ui

Convert hex color to rgba.

import { hexToRgba } from '@tetherto/mdk-core-ui'

hexToRgba('#72F59E', 0.5)  // "rgba(114, 245, 158, 0.5)"

Array utilities

getNestedValue

@tetherto/mdk-core-ui

Get nested value by dot-path.

import { getNestedValue } from '@tetherto/mdk-core-ui'

getNestedValue({ a: { b: 1 } }, 'a.b')  // 1

getWeightedAverage

@tetherto/mdk-core-ui

Calculate weighted average.

import { getWeightedAverage } from '@tetherto/mdk-core-ui'

getWeightedAverage(items, 'value', 'weight')

circularArrayAccess

@tetherto/mdk-core-ui

Create infinite cycling generator.

import { circularArrayAccess } from '@tetherto/mdk-core-ui'

const colors = circularArrayAccess(['red', 'green', 'blue'])
colors.next().value  // 'red'
colors.next().value  // 'green'
colors.next().value  // 'blue'
colors.next().value  // 'red' (cycles)

Foundation utilities

Helpers exported by @tetherto/mdk-foundation-ui for filtering, formatting, validating, parsing, and exporting settings data.

Prerequisites

Import

@tetherto/mdk-foundation-ui
import {
  filterUsers,
  formatRoleLabel,
  formatLastActive,
  validateSettingsJson,
  parseSettingsFile,
  exportSettingsToFile,
} from '@tetherto/mdk-foundation-ui'

Settings utilities

filterUsers

@tetherto/mdk-foundation-ui

Filter a SettingsUser[] list by email substring (case-insensitive) and exact role match. Used by the user-management table search.

import { filterUsers } from '@tetherto/mdk-foundation-ui'

filterUsers({
  users,
  email: 'alice',   // partial, case-insensitive match on user.email
  role: 'admin',    // exact match on user.role; pass null to skip
})
ParameterTypeDescription
usersSettingsUser[]Source list
emailstring | null | undefinedSubstring filter on email (case-insensitive). Skipped when falsy.
rolestring | null | undefinedExact role match. Skipped when falsy.

formatRoleLabel

@tetherto/mdk-foundation-ui

Convert a snake case role identifier to a human-readable Title Case label.

import { formatRoleLabel } from '@tetherto/mdk-foundation-ui'

formatRoleLabel('site_manager')           // "Site Manager"
formatRoleLabel('reporting_tool_manager') // "Reporting Tool Manager"
formatRoleLabel('admin')                  // "Admin"

formatLastActive

@tetherto/mdk-foundation-ui

Format a timestamp string as MM/DD/YYYY - HH:MM. Returns '-' when the input is missing or invalid.

import { formatLastActive } from '@tetherto/mdk-foundation-ui'

formatLastActive('2025-01-15T14:30:00Z')  // "01/15/2025 - 14:30"
formatLastActive(undefined)               // "-"
formatLastActive('not-a-date')            // "-"

validateSettingsJson

@tetherto/mdk-foundation-ui

Type-guard that checks whether an unknown value is a valid SettingsExportData. Returns true if the value is an object that contains at least one of headerControls, featureFlags, or timestamp.

import { validateSettingsJson } from '@tetherto/mdk-foundation-ui'

if (validateSettingsJson(parsed)) {
  // parsed is now narrowed to SettingsExportData
}

parseSettingsFile

@tetherto/mdk-foundation-ui

Read a File containing settings JSON, validate it, and resolve to SettingsExportData. Rejects on invalid JSON, an invalid format, or a file read error.

import { parseSettingsFile } from '@tetherto/mdk-foundation-ui'

try {
  const settings = await parseSettingsFile(file)
  applySettings(settings)
} catch (err) {
  notifyError('Could not import settings', err.message)
}
ThrowsReason
`Invalid settings file format. Please ensure the file is a valid ${WEBAPP_NAME} settings export.`The JSON parsed but didn't match the SettingsExportData shape. The literal interpolates WEBAPP_NAME.
Failed to parse JSON file. Please ensure the file is valid JSON.The file contents weren't valid JSON.
Failed to read file.The browser couldn't read the file.

exportSettingsToFile

@tetherto/mdk-foundation-ui

Serialize SettingsExportData to JSON, package it as a downloadable Blob, and trigger a browser download. Returns the generated filename (e.g., miningos-settings-2025-01-15T14-30-00-000Z.json). The filename prefix is fixed in the foundation kit and does not interpolate WEBAPP_NAME.

import { exportSettingsToFile } from '@tetherto/mdk-foundation-ui'

const filename = exportSettingsToFile({
  headerControls: { poolMiners: true, consumption: false },
  featureFlags: { betaCharts: true },
  timestamp: new Date().toISOString(),
  version: '1.0.0',
})

On this page