Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | 5x 2466x 2466x 2466x 2466x 117x 117x 117x 117x 390x 36x 1959x 1959x 3037x 14063x 14063x 14063x 8278x 7669x 8278x 1032x 10181x 10181x 8657x 8639x 8639x 8639x 8375x 505x 505x 69x 24x 24x 45x 45x 45x 45x 5113x 105x 105x 105x 105x 105x 11786x 11741x 150x 150x 150x 150x 9162x 9162x 36x 9548x 386x 386x 368x 368x 368x 36x 36x 18x 18x 18x 18x 9162x 9162x 9126x 9126x 63x 63x 9548x 63x 63x 880x 880x 915x 915x 915x 300x 300x 300x 300x 2561x 9x 9x 2552x 2552x 15x 15x 915x 3x 3x 3x 3x 297x 9x 9x 880x 4818x 4814x 1972x 1972x 3074x | import type { ColorPaletteId } from '@ska-octopus-widget-sdk/widget-sdk';
import { canonicalAttr, numericValue } from '../utils/utils';
import {
STATE_COLOR_SCHEME_ID,
TANGO_STATE_ENUM_FALLBACK,
TANGO_STATE_FALLBACK,
TANGO_STATE_PALETTE
} from './constants';
import { mapEnumValue } from './utils/enumMapping';
import type { DataMap, EnumDisplayMode, EnumLabelsByAttr } from './types';
const BOOLEAN_ENUM_LABELS = ['False', 'True'] as const;
function normalizeStateLabelKey(label: string): string {
const normalized = String(label ?? '')
.trim()
.toUpperCase()
.replace(/[\s-]+/g, '_');
Iif (normalized === 'TRUE') return 'ON';
Iif (normalized === 'FALSE') return 'OFF';
return normalized;
}
function enumIndexForLabel(enumLabels: string[] | undefined, label: string): number | null {
Iif (!enumLabels || enumLabels.length === 0) return null;
const target = normalizeStateLabelKey(label);
Iif (!target) return null;
for (let idx = 0; idx < enumLabels.length; idx++) {
if (normalizeStateLabelKey(enumLabels[idx] ?? '') === target) return idx;
}
return null;
}
function unknownEnumIndex(enumLabels: string[] | undefined): number | null {
return enumIndexForLabel(enumLabels, 'UNKNOWN');
}
export function hasTangoStateColor(label: string): boolean {
const key = normalizeStateLabelKey(label);
return !!key && Object.prototype.hasOwnProperty.call(TANGO_STATE_PALETTE, key);
}
export function colorForTangoStateLabel(label: string): string {
const key = normalizeStateLabelKey(label);
return TANGO_STATE_PALETTE[key] ?? TANGO_STATE_FALLBACK;
}
export function shouldUseSdkStateColors(colorScheme: ColorPaletteId): boolean {
return colorScheme === STATE_COLOR_SCHEME_ID;
}
export function isTangoStateAttr(attrKey: string): boolean {
const clean = canonicalAttr(attrKey).toLowerCase();
const last = clean.split('/').pop();
return last === 'state';
}
export function defaultEnumLabelsForStateAttr(attrKey: string): string[] | undefined {
return isTangoStateAttr(attrKey) ? TANGO_STATE_ENUM_FALLBACK : undefined;
}
export function enumLabelsForAttr(
enumLabelsByAttr: EnumLabelsByAttr,
attrKey: string
): string[] | undefined {
if (isTangoStateAttr(attrKey)) return TANGO_STATE_ENUM_FALLBACK;
const fromMeta = enumLabelsByAttr[attrKey] ?? enumLabelsByAttr[attrKey.toLowerCase()];
if (fromMeta && fromMeta.length > 0) return fromMeta;
return undefined;
}
export function enumLabelForValue(
enumLabels: string[] | undefined,
value: number | null
): string | null {
Iif (value === null) return null;
return mapEnumValue(value, enumLabels);
}
export function normalizeEnumIndex(
value: number | null,
enumLabels: string[] | undefined
): number | null {
if (value === null || !Number.isFinite(value)) return null;
const idx = Math.round(value);
Iif (!Number.isFinite(idx)) return null;
if (enumLabels && enumLabels.length > 0 && (idx < 0 || idx >= enumLabels.length)) return idx;
return idx;
}
export function stateNumericValue(value: unknown): number | null {
Iif (value === null || value === undefined) return null;
if (typeof value === 'number') return Number.isFinite(value) ? value : null;
if (typeof value === 'string') {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
Eif (Array.isArray(value) && value.length >= 2) {
const a = Number(value[0]);
const b = Number(value[1]);
Eif (Number.isFinite(a) && Number.isFinite(b)) return Math.max(a, b);
}
if (typeof value === 'object') {
const min = Number((value as any).min);
const max = Number((value as any).max);
if (Number.isFinite(min) && Number.isFinite(max)) return Math.max(min, max);
if (Number.isFinite(max)) return max;
if (Number.isFinite(min)) return min;
}
return numericValue(value as any);
}
export function categoricalLabelFromValue(value: unknown): string | null {
if (typeof value !== 'string') return null;
const trimmed = value.trim();
Iif (!trimmed) return null;
const asNumber = Number(trimmed);
Iif (Number.isFinite(asNumber)) return null;
return trimmed;
}
function booleanLabelFromValue(value: unknown): (typeof BOOLEAN_ENUM_LABELS)[number] | null {
if (typeof value === 'boolean') return value ? 'True' : 'False';
if (typeof value !== 'string') return null;
const normalized = value.trim().toLowerCase();
Iif (normalized === 'true') return 'True';
Iif (normalized === 'false') return 'False';
return null;
}
function booleanEnumIndexFromValue(value: unknown): number | null {
const boolLabel = booleanLabelFromValue(value);
if (boolLabel === null) return null;
return boolLabel === 'True' ? 1 : 0;
}
export function valueForPlot(
value: unknown,
isStateAttr: boolean,
enumLabels: string[] | undefined
): number | null {
if (isStateAttr) {
const numericState = normalizeEnumIndex(stateNumericValue(value), enumLabels);
if (numericState !== null) {
Eif (enumLabels && enumLabels.length > 0) {
const inRange = numericState >= 0 && numericState < enumLabels.length;
if (inRange) return numericState;
const unknownIdx = unknownEnumIndex(enumLabels);
Eif (unknownIdx !== null) return unknownIdx;
}
return numericState;
}
const label = categoricalLabelFromValue(value);
Iif (!label) return null;
const knownIdx = enumIndexForLabel(enumLabels, label);
Eif (knownIdx !== null) return knownIdx;
const unknownIdx = unknownEnumIndex(enumLabels);
return unknownIdx;
}
const boolIdx = booleanEnumIndexFromValue(value);
if (boolIdx !== null) return boolIdx;
const numeric = numericValue(value as any);
if (numeric !== null) return numeric;
Iif (!enumLabels || enumLabels.length === 0) return null;
const label = booleanLabelFromValue(value) ?? categoricalLabelFromValue(value);
Iif (!label) return null;
const idx = enumIndexForLabel(enumLabels, label);
return idx >= 0 ? idx : null;
}
export function deriveEnumLabelsFromData(
attrs: string[],
dataMap: DataMap,
enumLabelsByAttr: EnumLabelsByAttr
): EnumLabelsByAttr {
const next: EnumLabelsByAttr = { ...enumLabelsByAttr };
attrs.forEach((attr) => {
const key = canonicalAttr(attr);
const existing = enumLabelsByAttr[key] ?? enumLabelsByAttr[key.toLowerCase()];
if (existing && existing.length > 0) return;
let hasBooleanValues = false;
const labels: string[] = [];
const seen = new Set<string>();
(dataMap[key] ?? []).forEach((pt) => {
if (booleanLabelFromValue(pt.v) !== null) {
hasBooleanValues = true;
return;
}
const label = categoricalLabelFromValue(pt.v);
if (!label || seen.has(label)) return;
seen.add(label);
labels.push(label);
});
if (hasBooleanValues) {
const boolLabels = [...BOOLEAN_ENUM_LABELS];
next[key] = boolLabels;
next[key.toLowerCase()] = boolLabels;
return;
}
if (labels.length > 0) {
next[key] = labels;
next[key.toLowerCase()] = labels;
}
});
return next;
}
export function toDisplayValue(
value: number | null,
enumLabels: string[] | undefined,
enumDisplay: EnumDisplayMode
): string {
if (value === null) return 'N/A';
if (enumDisplay === 'label') {
const label = enumLabelForValue(enumLabels, normalizeEnumIndex(value, enumLabels));
if (label) return label;
}
return String(value);
}
export function isMccsAttr(name: string): boolean {
return /^mccs:\/{1,2}/i.test(name);
}
export function stripMccsPrefix(name: string): string {
return name.replace(/^mccs:\/{1,2}(.+)$/i, '$1');
}
|