{"version":3,"file":"TableStockCritico-CHsl8IJn.cjs","sources":["../src/dashboard/utils/tableColumns.ts","../src/dashboard/widgets/TableStockCritico.tsx"],"sourcesContent":["import { formatDate, formatExact, formatPercent } from './formatNumber';\nimport { matchesHint } from './fieldHints';\nimport type { SchemaField } from '../types';\n\n/**\n * Metadatos de columna de un widget de tabla.\n *\n * <b>La tabla no se deriva del resultado SQL.</b> Ese es el origen del problema que\n * se corrige: hoy los encabezados son el nombre crudo de la columna de base de\n * datos — `STOCK_ACTUAL`, `DIAS_SIN_ENTRADA` — así que el widget habla el idioma\n * del esquema y no el del gerente que lo lee.\n *\n * Se declaran en `config_schema.columns`.\n */\nexport type ColumnType = 'text' | 'number' | 'currency' | 'percent' | 'date' | 'badge';\n\nexport interface TableColumn {\n  /** Nombre real del campo en el resultado. */\n  key: string;\n  /** Lo que ve el usuario. Obligatorio en columnas declaradas. */\n  label: string;\n  type: ColumnType;\n  /** Por defecto: `right` para number/currency/percent. */\n  align?: 'left' | 'right';\n  /** Peso relativo del ancho, no píxeles. */\n  width?: number;\n  /** Una sola por tabla: la que identifica la fila. */\n  primary?: boolean;\n  /** Contra qué campo se compara para el énfasis semántico. */\n  compare?: { against: string; direction: 'below' | 'above' };\n  /** Se oculta en el widget compacto y reaparece al ampliar. */\n  hideOnCompact?: boolean;\n  /** Si la columna se dedujo del dato en vez de declararse. */\n  derived?: boolean;\n}\n\n/**\n * Nombres que delatan una fecha. Se comparan como PALABRA (ver `fieldHints`), no como substring.\n *\n * `dias` NO está en la lista a propósito: en plural es un conteo (`DIAS_SIN_ENTRADA`,\n * `dias_vencido`), no una fecha. `dia` en singular sí lo es.\n */\nconst DATE_HINTS = ['fecha', 'date', 'dia', 'creado', 'created', 'actualizado', 'updated', 'emision', 'vencimiento'] as const;\n/** Nombres que delatan un importe. */\nconst MONEY_HINTS = ['valor', 'total', 'precio', 'costo', 'importe', 'monto', 'saldo', 'amount', 'price'] as const;\n/**\n * Nombres que delatan un porcentaje.\n *\n * `tasa` NO está: una tasa de cambio (la TRM) es un importe, no un porcentaje, y con `tasa` en la\n * lista `tasa_cambio` se pintaba como «3.118,0 %».\n */\nconst PERCENT_HINTS = ['porcentaje', 'percent', 'pct', 'margen'] as const;\n/**\n * Nombres que delatan un CONTEO, y que ganan a las pistas de importe.\n *\n * Sin esto, `total_registros` casaba con `total` y un conteo de veinte documentos se pintaba\n * como «$ 20».\n */\nconst COUNT_HINTS = ['cantidad', 'cantidades', 'conteo', 'registros', 'documentos', 'items', 'lineas', 'unidades', 'numero', 'count', 'qty', 'quantity'] as const;\n\n/** Una cadena que empieza por una fecha ISO (`2026-08-19`, `2026-08-19T10:00:00Z`). */\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}/;\n\n/**\n * Convierte `STOCK_ACTUAL` en `Stock actual`.\n *\n * <b>Es un último recurso, no la solución.</b> Funciona hasta que aparece\n * `NIT_TERCERO_FACT`, que no hay heurística que arregle. Existe porque los widgets\n * ya sembrados no declaran columnas y no pueden quedarse mostrando el esquema en\n * pantalla; los nuevos deben declarar su `label` en el Widget Builder.\n */\nexport function humanizeKey(key: string): string {\n  const words = key\n    .replace(/[_-]+/g, ' ')\n    .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n    .trim()\n    .toLowerCase();\n  return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\n/**\n * Deduce el tipo de una columna a partir de su nombre y de una muestra de valores.\n *\n * <b>El DATO manda sobre el NOMBRE, y ese orden es el arreglo.</b> Antes se miraba primero el\n * nombre por substring, así que `DIAS_SIN_ENTRADA` casaba con `dia`, se tipaba como fecha y la\n * celda pintaba <b>«1 ene 1970»</b> para un conteo de días — en el widget que se llama «Stock\n * crítico», y justo en la columna que el ejemplo de este archivo cita.\n *\n * Un valor numérico no es una fecha se llame como se llame el campo. El nombre solo decide\n * cuando el dato no es concluyente.\n */\nexport function inferColumnType(key: string, sampleValues: unknown[]): ColumnType {\n  const firstDefined = sampleValues.find(v => v != null);\n\n  const esCadenaNumerica = typeof firstDefined === 'string'\n    && firstDefined.trim() !== ''\n    && !ISO_DATE.test(firstDefined)\n    && !Number.isNaN(Number(firstDefined));\n\n  // Numérico (incluida la cadena numérica de los endpoints que serializan todo como string).\n  if (typeof firstDefined === 'number' || esCadenaNumerica) {\n    // Los conteos ganan a las pistas de importe: `total_registros` es un número, no `$ 20`.\n    if (matchesHint(key, COUNT_HINTS)) return 'number';\n    if (matchesHint(key, PERCENT_HINTS)) return 'percent';\n    if (matchesHint(key, MONEY_HINTS)) return 'currency';\n    return 'number';\n  }\n\n  if (typeof firstDefined === 'boolean') return 'badge';\n\n  // Sin dato numérico, decide el nombre; y una cadena ISO es fecha aunque el campo no se llame así.\n  if (matchesHint(key, DATE_HINTS)) return 'date';\n  if (typeof firstDefined === 'string' && ISO_DATE.test(firstDefined)) return 'date';\n  if (matchesHint(key, PERCENT_HINTS)) return 'percent';\n  if (matchesHint(key, MONEY_HINTS)) return 'currency';\n\n  return 'text';\n}\n\n/** Alineación por defecto: los números a la derecha, para poder comparar magnitudes. */\nexport function defaultAlign(type: ColumnType): 'left' | 'right' {\n  return type === 'number' || type === 'currency' || type === 'percent' ? 'right' : 'left';\n}\n\n/** Traduce el `format` del envelope al tipo de columna de la tabla. */\nfunction typeFromSchemaField(field: SchemaField): ColumnType {\n  if (field.format === 'currency') return 'currency';\n  if (field.format === 'percent') return 'percent';\n  if (field.type === 'date') return 'date';\n  if (field.type === 'boolean') return 'badge';\n  if (field.type === 'number') return 'number';\n  return 'text';\n}\n\n/**\n * Las columnas de una tabla, resueltas en tres capas de prioridad.\n *\n * ```\n * 1. config_schema.columns   lo que declara el widget — manda siempre\n * 2. schema.fields           lo que declara el ENDPOINT en su envelope\n * 3. deducción del dato      último recurso: humanizar el nombre del campo\n * ```\n *\n * <b>La capa 2 es la que resuelve el problema de verdad, y estaba ahí sin usarse.</b>\n * El envelope estándar ya trae `label`, `type` y `format` por campo — el endpoint de\n * stock crítico declara \"Existencia\", \"Mínimo\" y \"Días sin entrada\" — pero la tabla\n * los ignoraba y pintaba el nombre crudo de la columna de base de datos.\n *\n * Consumirlos tiene dos ventajas sobre sembrar `config_schema` en cada host: las\n * etiquetas viven junto a la consulta que las produce, y funciona para <b>cualquier\n * host</b> que devuelva el envelope, sin configurar nada.\n *\n * `visibleColumns` del Widget Builder se sigue respetando como filtro y orden, para\n * no cambiarle la tabla a nadie que ya la haya configurado.\n */\nexport function resolveTableColumns(\n  declared: TableColumn[] | undefined,\n  rows: Record<string, unknown>[],\n  visibleColumns?: string[],\n  schemaFields?: SchemaField[],\n): TableColumn[] {\n  const availableKeys = rows.length > 0 ? Object.keys(rows[0]) : [];\n\n  // Capa 1 — lo que declara el widget.\n  if (declared && declared.length > 0) {\n    const disponibles: TableColumn[] = declared\n      .filter(col => availableKeys.length === 0 || availableKeys.includes(col.key))\n      .map(col => ({ ...col, align: col.align ?? defaultAlign(col.type) }));\n\n    /**\n     * `visibleColumns` filtra y ordena TAMBIÉN sobre las columnas declaradas.\n     *\n     * Es lo que el JSDoc de esta función promete —\"se sigue respetando como filtro y orden, para\n     * no cambiarle la tabla a nadie que ya la haya configurado\"— y la capa 1 lo estaba ignorando:\n     * un usuario que había elegido 3 de 8 columnas volvía a ver las 8 en cuanto el widget\n     * declaraba `config_schema.columns`.\n     */\n    if (!visibleColumns?.length) return disponibles;\n    const porClave = new Map(disponibles.map(c => [c.key, c]));\n    return visibleColumns\n      .map(k => porClave.get(k))\n      .filter((c): c is TableColumn => Boolean(c));\n  }\n\n  const keys = visibleColumns?.length\n    ? visibleColumns.filter(k => availableKeys.includes(k))\n    : availableKeys;\n\n  const byName = new Map((schemaFields ?? []).map(field => [field.name, field]));\n\n  return keys.map(key => {\n    // Capa 2 — lo que declara el endpoint.\n    const field = byName.get(key);\n    if (field) {\n      const type = typeFromSchemaField(field);\n      return { key, label: field.label || humanizeKey(key), type, align: defaultAlign(type) };\n    }\n\n    // Capa 3 — deducción.\n    const type = inferColumnType(key, rows.slice(0, 5).map(row => row[key]));\n    return { key, label: humanizeKey(key), type, align: defaultAlign(type), derived: true };\n  });\n}\n\n/**\n * Si una celda cumple la condición que da nombre al widget.\n *\n * Una tabla llamada \"Stock crítico\" tiene que mostrar QUÉ está crítico: hoy un `3`\n * contra un mínimo de `10` se ve igual que cualquier otro número.\n */\nexport function meetsCompare(\n  column: TableColumn,\n  row: Record<string, unknown>,\n): boolean {\n  if (!column.compare) return false;\n  const value = Number(row[column.key]);\n  const threshold = Number(row[column.compare.against]);\n  if (!Number.isFinite(value) || !Number.isFinite(threshold)) return false;\n  return column.compare.direction === 'below' ? value < threshold : value > threshold;\n}\n\n/**\n * Etiquetas de un valor booleano, ya traducidas por quien tiene el hook.\n *\n * `formatCellValue` es una función pura y no puede llamar a `useDashboardTranslation`, así que\n * las recibe. Antes devolvía `'Sí'`/`'No'` cableados en español, y una tabla con una columna\n * booleana los mostraba tal cual en un host en inglés.\n */\nexport interface CellLabels {\n  yes: string;\n  no: string;\n}\n\n/** El texto de una celda, según el tipo declarado de su columna. */\nexport function formatCellValue(\n  value: unknown,\n  type: ColumnType,\n  currency: string | null,\n  labels?: CellLabels,\n): string {\n  if (value == null || value === '') return '—';\n\n  switch (type) {\n    case 'currency':\n      // Sin abreviar: una tabla existe para comparar cifras exactas.\n      return formatExact(Number(value), { currency });\n    case 'number':\n      return formatExact(Number(value));\n    case 'percent':\n      return formatPercent(Number(value));\n    case 'date':\n      return formatDate(value as string);\n    case 'badge':\n      // Los respaldos son el comportamiento anterior, para un consumidor que aún no pase labels.\n      if (typeof value === 'boolean') return value ? (labels?.yes ?? 'Sí') : (labels?.no ?? 'No');\n      return String(value);\n    default:\n      return typeof value === 'object' ? JSON.stringify(value) : String(value);\n  }\n}\n","import React, { useState, useEffect, useMemo } from 'react';\nimport { ChevronUp, ChevronDown } from 'lucide-react';\nimport { WidgetDataGuard } from '../components/WidgetDataGuard';\nimport { DndContext, closestCenter, PointerSensor, KeyboardSensor, useSensor, useSensors, type DragEndEvent } from '@dnd-kit/core';\nimport { SortableContext, horizontalListSortingStrategy, useSortable, arrayMove, sortableKeyboardCoordinates } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport type { WidgetProps, MappingConfig } from '../types';\nimport { useWidgetFetch } from '../hooks/useWidgetFetch';\nimport { useDashboardTranslation } from '../i18n';\nimport { DASHBOARD_LOCALE, resolveCurrency } from '../utils/formatNumber';\nimport { readColumns, readString } from '../utils/widgetConfig';\nimport {\n  resolveTableColumns, formatCellValue, meetsCompare, type TableColumn, type CellLabels,\n} from '../utils/tableColumns';\n\n/** Ancho de widget por debajo del cual se ocultan las columnas secundarias. */\nconst COMPACT_WIDTH = 520;\n\ntype SortState = { key: string; dir: 'asc' | 'desc' } | null;\n\n/** Comparación estable: numérica cuando ambos lados lo son, alfabética con locale si no. */\nfunction compareValues(a: unknown, b: unknown): number {\n  if (typeof a === 'number' && typeof b === 'number') return a - b;\n  const na = Number(a), nb = Number(b);\n  if (Number.isFinite(na) && Number.isFinite(nb)) return na - nb;\n  return String(a ?? '').localeCompare(String(b ?? ''), DASHBOARD_LOCALE);\n}\n\ninterface HeaderProps {\n  column: TableColumn;\n  isDraggable: boolean;\n  sort: SortState;\n  onSort: (key: string) => void;\n}\n\nconst SortableHeader: React.FC<HeaderProps> = ({ column, isDraggable, sort, onSort }) => {\n  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: column.key });\n  const style = isDraggable ? { transform: CSS.Transform.toString(transform), transition } : undefined;\n  const isSorted = sort?.key === column.key;\n\n  return (\n    <th\n      ref={isDraggable ? setNodeRef : undefined}\n      style={{ ...style, color: 'var(--dash-text-secondary)', borderColor: 'var(--dash-border)' }}\n      {...(isDraggable ? { ...attributes, ...listeners } : {})}\n      onPointerDown={isDraggable ? e => e.stopPropagation() : undefined}\n      // Sentence case y sin negrita: el encabezado orienta, no compite con el dato.\n      className={`group/th px-3 py-2 font-normal border-b text-[11px] whitespace-nowrap ${\n        column.align === 'right' ? 'text-right' : 'text-left'\n      } ${isDraggable ? 'cursor-grab select-none' : ''} ${isDragging ? 'shadow-md z-10' : ''}`}\n      title={column.label}\n    >\n      <button\n        type=\"button\"\n        onClick={() => onSort(column.key)}\n        className={`inline-flex items-center gap-1 hover:opacity-80 ${column.align === 'right' ? 'flex-row-reverse' : ''}`}\n      >\n        {column.label}\n        {/* El chevron sólo se ve en la columna activa; en las demás asoma al pasar\n            el mouse, para que se sepa que son ordenables sin llenar la fila de flechas. */}\n        <span className={isSorted ? 'opacity-100' : 'opacity-0 group-hover/th:opacity-40'}>\n          {isSorted && sort?.dir === 'desc'\n            ? <ChevronDown className=\"w-3 h-3\" />\n            : <ChevronUp className=\"w-3 h-3\" />}\n        </span>\n      </button>\n    </th>\n  );\n};\n\n/**\n * Widget de tabla.\n *\n * Las columnas se declaran en `config_schema.columns` con etiqueta y tipo. Si el\n * widget no las declara —el caso de todo lo ya sembrado— se deducen del dato,\n * humanizando el nombre del campo; ver `tableColumns.ts`, donde está explicado por\n * qué eso es un último recurso y no la solución.\n *\n * <b>Se conserva el reordenamiento de columnas por arrastre</b> que ya existía: es\n * funcionalidad del producto y el rediseño no la toca.\n */\nconst TableStockCritico: React.FC<WidgetProps> = ({ definition, period, isEditMode }) => {\n  const { t } = useDashboardTranslation();\n  const { data, schema, loading, error } = useWidgetFetch<Record<string, unknown>[]>(\n    definition.widget_id, period, definition.refresh_policy, definition.field_mapping?.rename\n  );\n\n  const tableConfig = definition.config_schema as (MappingConfig & {\n    type: 'table';\n    columns?: TableColumn[];\n    format?: string;\n    emptyTitle?: string;\n  }) | undefined;\n\n  const rows = useMemo(() => (Array.isArray(data) ? data : data ? [data] : []), [data]);\n\n  // `readColumns` descarta un `columns` que no sea un array de columnas con `key` y `type`:\n  // antes un valor mal declarado llegaba como `TableColumn[]` por el cast y rompía más abajo.\n  const declaredColumns = useMemo(() => readColumns(definition.config_schema), [definition.config_schema]);\n\n  const columns = useMemo(\n    () => resolveTableColumns(\n      declaredColumns,\n      rows,\n      tableConfig?.type === 'table' ? tableConfig.visibleColumns : undefined,\n      // El envelope del endpoint: trae las etiquetas de negocio ya escritas.\n      schema?.fields,\n    ),\n    [declaredColumns, tableConfig, rows, schema],\n  );\n\n  const columnKeys = useMemo(() => columns.map(c => c.key), [columns]);\n  const [localOrder, setLocalOrder] = useState<string[]>(columnKeys);\n\n  // Resincronizar cuando cambian las columnas de origen (p. ej. al cambiar periodo).\n  // Se compara por firma: comparar el array por referencia dispararía en cada render.\n  const columnsSignature = columnKeys.join('|');\n  useEffect(() => {\n    setLocalOrder(columnsSignature ? columnsSignature.split('|') : []);\n  }, [columnsSignature]);\n\n  /** Ancho del widget, para decidir qué columnas caben. */\n  const containerRef = React.useRef<HTMLDivElement>(null);\n  const [isCompact, setIsCompact] = useState(false);\n  useEffect(() => {\n    const element = containerRef.current;\n    if (!element || typeof ResizeObserver === 'undefined') return;\n    const observer = new ResizeObserver(([entry]) => {\n      setIsCompact(entry.contentRect.width < COMPACT_WIDTH);\n    });\n    observer.observe(element);\n    return () => observer.disconnect();\n  }, []);\n\n  const [sort, setSort] = useState<SortState>(null);\n\n  /**\n   * Ordenar es estado de UI, no de query: <b>no dispara `refetch`</b>. El tercer\n   * clic vuelve al orden del servidor, que es un estado distinto de \"ascendente\".\n   */\n  const handleSort = (key: string) => {\n    setSort(current => {\n      if (current?.key !== key) return { key, dir: 'asc' };\n      if (current.dir === 'asc') return { key, dir: 'desc' };\n      return null;\n    });\n  };\n\n  const visibleColumns = useMemo(() => {\n    const byKey = new Map(columns.map(c => [c.key, c]));\n    return localOrder\n      .map(key => byKey.get(key))\n      .filter((c): c is TableColumn => Boolean(c))\n      .filter(c => !(isCompact && c.hideOnCompact));\n  }, [localOrder, columns, isCompact]);\n\n  const sortedRows = useMemo(() => {\n    if (!sort) {\n      // Orden del servidor. Si el widget declaró uno por configuración, se respeta.\n      if (tableConfig?.type === 'table' && tableConfig.sortField) {\n        const field = tableConfig.sortField;\n        const dir = tableConfig.sortDirection === 'desc' ? -1 : 1;\n        return [...rows].sort((a, b) => compareValues(a[field], b[field]) * dir);\n      }\n      return rows;\n    }\n    const dir = sort.dir === 'desc' ? -1 : 1;\n    return [...rows].sort((a, b) => compareValues(a[sort.key], b[sort.key]) * dir);\n  }, [rows, sort, tableConfig]);\n\n  const currency = resolveCurrency().symbol;\n\n  /**\n   * Las etiquetas del booleano, traducidas aquí porque `formatCellValue` es una función pura y no\n   * puede llamar al hook. Sin esto, una columna booleana mostraba «Sí»/«No» en un host en inglés.\n   */\n  const cellLabels = useMemo<CellLabels>(\n    () => ({ yes: t('dashboard.table.yes'), no: t('dashboard.table.no') }),\n    [t],\n  );\n\n  const handleDragEnd = (event: DragEndEvent) => {\n    const { active, over } = event;\n    if (!over || active.id === over.id) return;\n    const oldIdx = localOrder.indexOf(active.id as string);\n    const newIdx = localOrder.indexOf(over.id as string);\n    if (oldIdx === -1 || newIdx === -1) return;\n    setLocalOrder(arrayMove(localOrder, oldIdx, newIdx));\n  };\n\n  const sensors = useSensors(\n    useSensor(PointerSensor, { activationConstraint: { delay: 150, tolerance: 5 } }),\n    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })\n  );\n\n  const isDraggable = !isEditMode && visibleColumns.length > 1;\n\n  return (\n    <WidgetDataGuard\n      loading={loading}\n      error={error}\n      data={data}\n      shape=\"table\"\n      emptyTitle={readString(definition.config_schema, 'emptyTitle')}\n    >\n      <div ref={containerRef} className=\"w-full h-full flex flex-col\">\n        <div className=\"flex-1 overflow-auto custom-scrollbar\">\n          <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>\n            <SortableContext items={visibleColumns.map(c => c.key)} strategy={horizontalListSortingStrategy}>\n              <table className=\"w-full text-left border-collapse\">\n                <thead className=\"sticky top-0 z-[5]\" style={{ background: 'var(--dash-surface-card)' }}>\n                  <tr>\n                    {visibleColumns.map(col => (\n                      <SortableHeader\n                        key={col.key}\n                        column={col}\n                        isDraggable={isDraggable}\n                        sort={sort}\n                        onSort={handleSort}\n                      />\n                    ))}\n                  </tr>\n                </thead>\n                <tbody>\n                  {sortedRows.map((row, i) => (\n                    <tr\n                      key={i}\n                      className=\"border-b transition-colors hover:bg-[var(--dash-surface-page)]\"\n                      style={{ borderColor: 'var(--dash-border)' }}\n                    >\n                      {visibleColumns.map(col => {\n                        const critical = meetsCompare(col, row);\n                        return (\n                          <td\n                            key={col.key}\n                            className={`px-3 py-2 text-[13px] whitespace-nowrap ${col.align === 'right' ? 'text-right' : 'text-left'}`}\n                            style={{\n                              color: critical ? 'var(--dash-danger)' : 'var(--dash-text-primary)',\n                              fontWeight: critical ? 500 : 400,\n                              fontVariantNumeric: col.align === 'right' ? 'tabular-nums' : undefined,\n                            }}\n                          >\n                            {/* Color MÁS forma: el punto dice lo mismo que el rojo\n                                para quien no distingue el rojo. */}\n                            {critical && (\n                              <span\n                                className=\"inline-block w-1.5 h-1.5 rounded-full mr-1.5 align-middle\"\n                                style={{ background: 'var(--dash-danger)' }}\n                                data-testid=\"cell-critical-dot\"\n                              />\n                            )}\n                            {formatCellValue(row[col.key], col.type, currency, cellLabels)}\n                          </td>\n                        );\n                      })}\n                    </tr>\n                  ))}\n                </tbody>\n              </table>\n            </SortableContext>\n          </DndContext>\n        </div>\n\n        {/* Pie: cuántas filas se ven. Sin él, tres filas en una tarjeta donde caben\n            diez parecen ser todo lo que existe. */}\n        <div\n          className=\"flex-shrink-0 flex items-center justify-between px-3 py-1.5 border-t text-[11px]\"\n          style={{ borderColor: 'var(--dash-border)', color: 'var(--dash-text-muted)' }}\n          data-testid=\"table-footer\"\n        >\n          <span>\n            {t('dashboard.table.rowCount').replace('{count}', String(sortedRows.length))}\n          </span>\n          {isCompact && columns.some(c => c.hideOnCompact) && (\n            <span>{t('dashboard.table.expandForMore')}</span>\n          )}\n        </div>\n      </div>\n    </WidgetDataGuard>\n  );\n};\n\nexport default TableStockCritico;\n"],"names":["DATE_HINTS","MONEY_HINTS","PERCENT_HINTS","COUNT_HINTS","ISO_DATE","humanizeKey","key","words","inferColumnType","sampleValues","firstDefined","v","esCadenaNumerica","matchesHint","defaultAlign","type","typeFromSchemaField","field","resolveTableColumns","declared","rows","visibleColumns","schemaFields","availableKeys","disponibles","col","porClave","c","k","keys","byName","row","meetsCompare","column","value","threshold","formatCellValue","currency","labels","formatExact","formatPercent","formatDate","COMPACT_WIDTH","compareValues","a","b","na","nb","DASHBOARD_LOCALE","SortableHeader","isDraggable","sort","onSort","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","isSorted","jsx","e","jsxs","ChevronDown","ChevronUp","TableStockCritico","definition","period","isEditMode","t","useDashboardTranslation","data","schema","loading","error","useWidgetFetch","tableConfig","useMemo","declaredColumns","readColumns","columns","columnKeys","localOrder","setLocalOrder","useState","columnsSignature","useEffect","containerRef","React","isCompact","setIsCompact","element","observer","entry","setSort","handleSort","current","byKey","sortedRows","dir","resolveCurrency","cellLabels","handleDragEnd","event","active","over","oldIdx","newIdx","arrayMove","sensors","useSensors","useSensor","PointerSensor","KeyboardSensor","sortableKeyboardCoordinates","WidgetDataGuard","readString","DndContext","closestCenter","SortableContext","horizontalListSortingStrategy","i","critical"],"mappings":"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"}