feat: version 4.14.0 -- Equipos: año del procesador con boton Obtener fecha (IA)

La IA consulta solo el nombre del procesador y devuelve el año (el mas antiguo si hay dos).
Migracion 039.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-29 19:07:31 -05:00
parent 0968e61ced
commit b2c25c4fe5
14 changed files with 89 additions and 6 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "project-linkedcorp-frontend",
"private": true,
"version": "4.13.1",
"version": "4.14.0",
"type": "module",
"scripts": {
"dev": "vite",
+8
View File
@@ -466,6 +466,10 @@ export const messages = {
eq_assigned_to: 'Asignado a',
eq_notes: 'Notas',
eq_cpu: 'Procesador',
eq_cpu_year: 'Año del procesador',
eq_cpu_year_get: 'Obtener fecha',
eq_cpu_year_loading: 'Consultando...',
eq_cpu_year_hint: 'La IA consulta solo el nombre del procesador y devuelve el año de lanzamiento (el más antiguo si hay dos).',
eq_ram: 'Memoria RAM',
eq_disk_total: 'Almacenamiento',
eq_disk_max_used: 'volumen más lleno',
@@ -1229,6 +1233,10 @@ export const messages = {
eq_assigned_to: 'Assigned to',
eq_notes: 'Notes',
eq_cpu: 'Processor',
eq_cpu_year: 'Processor year',
eq_cpu_year_get: 'Get date',
eq_cpu_year_loading: 'Looking up...',
eq_cpu_year_hint: 'The AI looks up only the processor name and returns its release year (the oldest if there are two).',
eq_ram: 'RAM',
eq_disk_total: 'Storage',
eq_disk_max_used: 'fullest volume',
+23 -2
View File
@@ -1,12 +1,12 @@
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { Navigate } from 'react-router-dom';
import { Pencil, Save, Plus, Trash2, Power, Copy, Download } from 'lucide-react';
import { Pencil, Save, Plus, Trash2, Power, Copy, Download, Sparkles } from 'lucide-react';
import { useUi } from '../../context/ui-context.jsx';
import { useAuth } from '../../context/auth-context.jsx';
import { useAsync, useAction } from '../../hooks/useAsync.js';
import {
listDevices, getDevice, updateDevice, getDevicesDashboard, listSoftware, listSoftwareDevices,
listDevices, getDevice, updateDevice, fetchDeviceCpuYear, getDevicesDashboard, listSoftware, listSoftwareDevices,
getDevicesAccess, listDeviceViewers, addDeviceViewer, removeDeviceViewer,
listInventoryTokens, createInventoryToken, setInventoryTokenActive, deleteInventoryToken, getInventoryTokenSecret,
} from '../../services/devices.js';
@@ -69,6 +69,7 @@ function DeviceDetail({ id, onClose, onChanged, canEdit, tab = 'general', onTabC
const setTab = onTabChange; // la pestaña vive en la URL (?deviceTab=)
const [searches, setSearches] = useState({});
const [showComponents, setShowComponents] = useState(false);
const [fetchingYear, setFetchingYear] = useState(false);
const [editing, setEditing] = useState(false);
// Borrador de los datos editables del equipo (estado, asignado, departamento, notas).
const draft = useDraftForm({
@@ -84,6 +85,16 @@ function DeviceDetail({ id, onClose, onChanged, canEdit, tab = 'general', onTabC
const userOptions = (users || []).map((u) => ({ value: u.id, label: u.name }));
const deptOptions = flat(departments).map((d) => ({ value: d.id, label: d.name }));
// Año de lanzamiento del procesador: la IA lo consulta solo con el nombre del procesador.
function getCpuYear() {
setFetchingYear(true);
runAction(async () => {
await fetchDeviceCpuYear(id);
await reload();
pushToast({ tone: 'success', message: t('common_saved') });
}).catch(() => {}).finally(() => setFetchingYear(false));
}
function startEdit() {
setEditing(true);
}
@@ -147,6 +158,16 @@ function DeviceDetail({ id, onClose, onChanged, canEdit, tab = 'general', onTabC
const cpuText = device.cpus.map((c) => `${c.name || ''}${c.cores ? ` · ${c.cores}c/${c.threads || '?'}t` : ''}`).join(' | ');
const hwRows = [
[t('eq_cpu'), val(cpuText), cpuText],
[t('eq_cpu_year'), (
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
{val(device.cpu_year)}
{canEdit && cpuText && (
<Button size="sm" variant="standard" icon={Sparkles} onClick={getCpuYear} disabled={fetchingYear} title={t('eq_cpu_year_hint')}>
{fetchingYear ? t('eq_cpu_year_loading') : t('eq_cpu_year_get')}
</Button>
)}
</span>
), String(device.cpu_year ?? '')],
[t('eq_ram'), gb(device.ram_mb), gb(device.ram_mb)],
[t('eq_disk_total'), <>{gb(device.disk_total_mb)} {device.max_disk_used_pct != null && <span className="text-muted">· {t('eq_disk_max_used')} {device.max_disk_used_pct}%</span>}</>, `${gb(device.disk_total_mb)} ${device.max_disk_used_pct ?? ''}`],
];
+1
View File
@@ -20,3 +20,4 @@ export const getDevicesAccess = () => api.get('/devices/access');
export const listDeviceViewers = () => api.get('/devices/viewers');
export const addDeviceViewer = (userId) => api.post('/devices/viewers', { userId });
export const removeDeviceViewer = (userId) => api.delete(`/devices/viewers/${userId}`);
export const fetchDeviceCpuYear = (id) => api.post(`/devices/${id}/cpu-year`);