trackops 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +695 -402
- package/bin/trackops.js +116 -116
- package/lib/config.js +326 -326
- package/lib/control.js +208 -208
- package/lib/env.js +244 -244
- package/lib/init.js +325 -325
- package/lib/locale.js +24 -0
- package/lib/opera-bootstrap.js +941 -874
- package/lib/opera.js +494 -477
- package/lib/preferences.js +74 -74
- package/lib/registry.js +214 -196
- package/lib/release.js +56 -56
- package/lib/runtime-state.js +144 -144
- package/lib/server.js +312 -207
- package/lib/skills.js +74 -57
- package/lib/workspace.js +260 -260
- package/locales/en.json +192 -166
- package/locales/es.json +192 -166
- package/package.json +61 -58
- package/scripts/postinstall-locale.js +21 -21
- package/scripts/skills-marketplace-smoke.js +124 -124
- package/scripts/smoke-tests.js +558 -554
- package/scripts/sync-skill-version.js +21 -21
- package/scripts/validate-skill.js +103 -103
- package/skills/trackops/SKILL.md +126 -122
- package/skills/trackops/agents/openai.yaml +7 -7
- package/skills/trackops/locales/en/SKILL.md +126 -122
- package/skills/trackops/locales/en/references/activation.md +94 -75
- package/skills/trackops/locales/en/references/troubleshooting.md +73 -55
- package/skills/trackops/locales/en/references/workflow.md +55 -32
- package/skills/trackops/references/activation.md +94 -75
- package/skills/trackops/references/troubleshooting.md +73 -55
- package/skills/trackops/references/workflow.md +55 -32
- package/skills/trackops/skill.json +29 -29
- package/templates/hooks/post-checkout +2 -2
- package/templates/hooks/post-commit +2 -2
- package/templates/hooks/post-merge +2 -2
- package/templates/opera/agent.md +28 -27
- package/templates/opera/architecture/dependency-graph.md +24 -24
- package/templates/opera/architecture/runtime-automation.md +24 -24
- package/templates/opera/architecture/runtime-operations.md +34 -34
- package/templates/opera/en/agent.md +22 -21
- package/templates/opera/en/architecture/dependency-graph.md +24 -24
- package/templates/opera/en/architecture/runtime-automation.md +24 -24
- package/templates/opera/en/architecture/runtime-operations.md +34 -34
- package/templates/opera/en/reviews/delivery-audit.md +18 -18
- package/templates/opera/en/reviews/integration-audit.md +18 -18
- package/templates/opera/en/router.md +24 -19
- package/templates/opera/references/autonomy-and-recovery.md +117 -117
- package/templates/opera/references/opera-cycle.md +193 -193
- package/templates/opera/registry.md +28 -28
- package/templates/opera/reviews/delivery-audit.md +18 -18
- package/templates/opera/reviews/integration-audit.md +18 -18
- package/templates/opera/router.md +54 -49
- package/templates/skills/changelog-updater/SKILL.md +69 -69
- package/templates/skills/commiter/SKILL.md +99 -99
- package/templates/skills/opera-contract-auditor/SKILL.md +38 -38
- package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -38
- package/templates/skills/opera-policy-guard/SKILL.md +26 -26
- package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -26
- package/templates/skills/opera-skill/SKILL.md +279 -0
- package/templates/skills/opera-skill/locales/en/SKILL.md +279 -0
- package/templates/skills/opera-skill/locales/en/references/phase-dod.md +138 -0
- package/templates/skills/opera-skill/references/phase-dod.md +138 -0
- package/templates/skills/project-starter-skill/SKILL.md +150 -131
- package/templates/skills/project-starter-skill/locales/en/SKILL.md +143 -105
- package/templates/skills/project-starter-skill/references/opera-cycle.md +195 -193
- package/ui/css/base.css +284 -266
- package/ui/css/charts.css +425 -327
- package/ui/css/components.css +1107 -570
- package/ui/css/onboarding.css +133 -0
- package/ui/css/panels.css +345 -406
- package/ui/css/terminal.css +125 -0
- package/ui/css/timeline.css +58 -0
- package/ui/css/tokens.css +284 -227
- package/ui/favicon.svg +5 -5
- package/ui/index.html +99 -96
- package/ui/js/api.js +49 -13
- package/ui/js/app.js +28 -32
- package/ui/js/charts.js +526 -0
- package/ui/js/console-logger.js +172 -172
- package/ui/js/filters.js +247 -0
- package/ui/js/icons.js +129 -104
- package/ui/js/keyboard.js +229 -0
- package/ui/js/onboarding.js +33 -42
- package/ui/js/router.js +142 -125
- package/ui/js/theme.js +100 -100
- package/ui/js/time-tracker.js +248 -248
- package/ui/js/views/board.js +84 -114
- package/ui/js/views/dashboard.js +870 -0
- package/ui/js/views/flash.js +47 -47
- package/ui/js/views/projects.js +745 -0
- package/ui/js/views/scrum.js +476 -0
- package/ui/js/views/settings.js +153 -203
- package/ui/js/views/sidebar.js +37 -31
- package/ui/js/views/tasks.js +218 -101
- package/ui/js/views/timeline.js +265 -0
- package/ui/js/views/topbar.js +94 -107
- package/ui/app.js +0 -950
- package/ui/js/views/insights.js +0 -340
- package/ui/js/views/overview.js +0 -369
- package/ui/styles.css +0 -688
package/ui/index.html
CHANGED
|
@@ -1,96 +1,99 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="es">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<title>TrackOps Beta — Centro de control</title>
|
|
7
|
-
<meta name="description" content="Panel local beta de TrackOps: gestión de proyectos, tareas, analíticas y seguimiento de tiempo para desarrolladores." />
|
|
8
|
-
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
|
9
|
-
|
|
10
|
-
<!-- Google Fonts (coherente con web corporativa) -->
|
|
11
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
12
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
13
|
-
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Outfit:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@700;800&display=swap" rel="stylesheet" />
|
|
14
|
-
|
|
15
|
-
<!-- Anti-FOUC: aplica el tema antes del primer paint -->
|
|
16
|
-
<script>
|
|
17
|
-
(function(){
|
|
18
|
-
var t = localStorage.getItem('trackops-theme');
|
|
19
|
-
if (!t) t = 'light';
|
|
20
|
-
if (t === 'light') document.documentElement.setAttribute('data-theme','light');
|
|
21
|
-
})();
|
|
22
|
-
</script>
|
|
23
|
-
|
|
24
|
-
<!-- CSS Modular -->
|
|
25
|
-
<link rel="stylesheet" href="/css/tokens.css" />
|
|
26
|
-
<link rel="stylesheet" href="/css/base.css" />
|
|
27
|
-
<link rel="stylesheet" href="/css/components.css" />
|
|
28
|
-
<link rel="stylesheet" href="/css/panels.css" />
|
|
29
|
-
<link rel="stylesheet" href="/css/charts.css" />
|
|
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
|
-
<div id="
|
|
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
|
-
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>TrackOps Beta — Centro de control</title>
|
|
7
|
+
<meta name="description" content="Panel local beta de TrackOps: gestión de proyectos, tareas, analíticas y seguimiento de tiempo para desarrolladores." />
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
|
9
|
+
|
|
10
|
+
<!-- Google Fonts (coherente con web corporativa) -->
|
|
11
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
12
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
13
|
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Outfit:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@700;800&display=swap" rel="stylesheet" />
|
|
14
|
+
|
|
15
|
+
<!-- Anti-FOUC: aplica el tema antes del primer paint -->
|
|
16
|
+
<script>
|
|
17
|
+
(function(){
|
|
18
|
+
var t = localStorage.getItem('trackops-theme');
|
|
19
|
+
if (!t) t = 'light';
|
|
20
|
+
if (t === 'light') document.documentElement.setAttribute('data-theme','light');
|
|
21
|
+
})();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<!-- CSS Modular -->
|
|
25
|
+
<link rel="stylesheet" href="/css/tokens.css" />
|
|
26
|
+
<link rel="stylesheet" href="/css/base.css" />
|
|
27
|
+
<link rel="stylesheet" href="/css/components.css" />
|
|
28
|
+
<link rel="stylesheet" href="/css/panels.css" />
|
|
29
|
+
<link rel="stylesheet" href="/css/charts.css" />
|
|
30
|
+
<link rel="stylesheet" href="/css/terminal.css" />
|
|
31
|
+
<link rel="stylesheet" href="/css/onboarding.css" />
|
|
32
|
+
<link rel="stylesheet" href="/css/timeline.css" />
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
|
|
36
|
+
<!-- Skip to content (WCAG 2.2 AA) -->
|
|
37
|
+
<a class="skip-link" href="#view-container">Saltar al contenido principal</a>
|
|
38
|
+
|
|
39
|
+
<!-- App shell -->
|
|
40
|
+
<div class="app-shell">
|
|
41
|
+
|
|
42
|
+
<!-- ══ SIDEBAR ══ -->
|
|
43
|
+
<aside id="sidebar" role="navigation" aria-label="Navegación principal">
|
|
44
|
+
<!-- Rendered by sidebar.js -->
|
|
45
|
+
</aside>
|
|
46
|
+
|
|
47
|
+
<!-- ══ TOPBAR ══ -->
|
|
48
|
+
<header id="topbar" role="banner">
|
|
49
|
+
<!-- Rendered by topbar.js -->
|
|
50
|
+
</header>
|
|
51
|
+
|
|
52
|
+
<!-- ══ MAIN CONTENT ══ -->
|
|
53
|
+
<main id="view-container" role="main" tabindex="-1">
|
|
54
|
+
<!-- Rendered by router.js / views -->
|
|
55
|
+
</main>
|
|
56
|
+
|
|
57
|
+
</div><!-- /.app-shell -->
|
|
58
|
+
|
|
59
|
+
<!-- Flash / Toast container (aria-live para a11y) -->
|
|
60
|
+
<div id="flash-container" aria-live="polite" aria-atomic="false"></div>
|
|
61
|
+
|
|
62
|
+
<!-- Panel de registros -->
|
|
63
|
+
<div id="console-panel" class="console-panel" role="log" aria-label="Consola de errores" aria-live="off">
|
|
64
|
+
<div class="console-panel-header">
|
|
65
|
+
<div class="console-panel-title" id="console-panel-title">
|
|
66
|
+
<span>·</span> Registros
|
|
67
|
+
<span id="console-error-count" class="badge badge-danger" style="display:none">0</span>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="console-panel-actions">
|
|
70
|
+
<button class="btn btn-ghost btn-sm" id="console-clear-btn" type="button" aria-label="Limpiar logs">Limpiar</button>
|
|
71
|
+
<button class="btn btn-ghost btn-sm" id="console-close-btn" type="button" aria-label="Cerrar consola">✕</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="console-logs" id="console-logs" role="list"></div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<!-- Onboarding Spotlight -->
|
|
78
|
+
<div id="onboarding-spotlight" class="onboarding-spotlight is-hidden" aria-hidden="true"></div>
|
|
79
|
+
|
|
80
|
+
<div id="onboarding-tooltip" class="onboarding-tooltip is-hidden" role="dialog" aria-modal="true" aria-labelledby="ob-title">
|
|
81
|
+
<div class="ob-step-label" id="ob-step-label">Paso 1 de X</div>
|
|
82
|
+
<h2 class="ob-title" id="ob-title"></h2>
|
|
83
|
+
<p class="ob-desc" id="ob-desc"></p>
|
|
84
|
+
|
|
85
|
+
<div class="ob-nav">
|
|
86
|
+
<div class="ob-dots" id="ob-dots" aria-hidden="true"></div>
|
|
87
|
+
<div class="ob-actions">
|
|
88
|
+
<button class="btn btn-ghost btn-sm" id="ob-skip" type="button">Saltar</button>
|
|
89
|
+
<button class="btn btn-ghost btn-sm" id="ob-prev" type="button">Anterior</button>
|
|
90
|
+
<button class="btn btn-primary btn-sm" id="ob-next" type="button">Siguiente</button>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<!-- JS Módulos (ES modules) -->
|
|
96
|
+
<script type="module" src="/js/app.js"></script>
|
|
97
|
+
|
|
98
|
+
</body>
|
|
99
|
+
</html>
|
package/ui/js/api.js
CHANGED
|
@@ -79,24 +79,50 @@ export async function updateProjectLocale(locale) {
|
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Obtiene el estado de un proyecto especifico (sin cambiar el proyecto activo)
|
|
84
|
+
* @param {string} projectId
|
|
85
|
+
*/
|
|
86
|
+
export async function getProjectState(projectId) {
|
|
87
|
+
return call(`/api/state?project=${encodeURIComponent(projectId)}`, { projectAware: false });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Elimina un proyecto del registro (no borra archivos)
|
|
92
|
+
* @param {string} projectId
|
|
93
|
+
*/
|
|
94
|
+
export async function removeProject(projectId) {
|
|
95
|
+
return call(`/api/projects/${encodeURIComponent(projectId)}`, {
|
|
96
|
+
method: 'DELETE',
|
|
97
|
+
projectAware: false,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function purgeUnavailableProjects() {
|
|
102
|
+
return call('/api/projects/purge-unavailable', {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
projectAware: false,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
82
108
|
// ─────────────────────────────── ESTADO ─────────────────────────────────────
|
|
83
109
|
|
|
84
110
|
/**
|
|
85
111
|
* Obtiene el estado completo del proyecto activo
|
|
86
112
|
*/
|
|
87
|
-
export async function getState() {
|
|
88
|
-
return call('/api/state');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export async function getEnvStatus() {
|
|
92
|
-
return call('/api/env');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export async function syncEnv() {
|
|
96
|
-
return call('/api/env/sync', {
|
|
97
|
-
method: 'POST',
|
|
98
|
-
});
|
|
99
|
-
}
|
|
113
|
+
export async function getState() {
|
|
114
|
+
return call('/api/state');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function getEnvStatus() {
|
|
118
|
+
return call('/api/env');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function syncEnv() {
|
|
122
|
+
return call('/api/env/sync', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
100
126
|
|
|
101
127
|
// ─────────────────────────────── TAREAS ─────────────────────────────────────
|
|
102
128
|
|
|
@@ -202,6 +228,16 @@ export async function getTimeEntries() {
|
|
|
202
228
|
return call('/api/time');
|
|
203
229
|
}
|
|
204
230
|
|
|
231
|
+
// ─────────────────────────────── ANALYTICS ────────────────────────────────
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Obtiene datos analiticos computados del proyecto
|
|
235
|
+
* @param {string} [range='30'] — Rango en dias (7, 30, 90, 'all')
|
|
236
|
+
*/
|
|
237
|
+
export async function getAnalytics(range = '30') {
|
|
238
|
+
return call(`/api/analytics?range=${encodeURIComponent(range)}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
205
241
|
// ─────────────────────────────── SKILLS HUB ────────────────────────────────
|
|
206
242
|
|
|
207
243
|
export async function fetchSkillsLocal() {
|
package/ui/js/app.js
CHANGED
|
@@ -10,17 +10,17 @@ import * as consoleLogger from './console-logger.js';
|
|
|
10
10
|
import * as onboarding from './onboarding.js';
|
|
11
11
|
import * as timeTracker from './time-tracker.js';
|
|
12
12
|
import * as theme from './theme.js';
|
|
13
|
+
import * as keyboard from './keyboard.js';
|
|
13
14
|
|
|
14
15
|
// Vistas
|
|
15
16
|
import { render as renderSidebar } from './views/sidebar.js';
|
|
16
17
|
import { render as renderTopbar } from './views/topbar.js';
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import { render as renderTasks } from './views/tasks.js';
|
|
18
|
+
import * as dashboardView from './views/dashboard.js';
|
|
19
|
+
import * as tasksView from './views/tasks.js';
|
|
20
20
|
import * as executionView from './views/execution.js';
|
|
21
|
-
import
|
|
21
|
+
import * as projectsView from './views/projects.js';
|
|
22
|
+
import { render as renderTimeline } from './views/timeline.js';
|
|
22
23
|
import * as settingsView from './views/settings.js';
|
|
23
|
-
import * as skillsView from './views/skills.js';
|
|
24
24
|
|
|
25
25
|
// ─────────────────────────────── INIT ───────────────────────────────────────
|
|
26
26
|
|
|
@@ -32,28 +32,32 @@ async function init() {
|
|
|
32
32
|
consoleLogger.init();
|
|
33
33
|
|
|
34
34
|
// 2. Registrar rutas en el router
|
|
35
|
-
router.register('
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
router.register('dashboard', async () => {
|
|
36
|
+
const html = await dashboardView.render();
|
|
37
|
+
setTimeout(() => dashboardView.bindEvents?.(), 50);
|
|
38
|
+
return html;
|
|
39
|
+
});
|
|
40
|
+
router.register('tasks', async () => {
|
|
41
|
+
const html = await tasksView.render();
|
|
42
|
+
setTimeout(() => tasksView.bindEvents?.(), 50);
|
|
43
|
+
return html;
|
|
44
|
+
});
|
|
45
|
+
router.register('terminal', async () => {
|
|
39
46
|
const html = await executionView.render();
|
|
40
47
|
setTimeout(() => executionView.bindEvents(), 50);
|
|
41
48
|
return html;
|
|
42
49
|
});
|
|
43
|
-
router.register('
|
|
50
|
+
router.register('timeline', renderTimeline);
|
|
51
|
+
router.register('projects', async () => {
|
|
52
|
+
const html = await projectsView.render();
|
|
53
|
+
setTimeout(() => projectsView.bindEvents(), 50);
|
|
54
|
+
return html;
|
|
55
|
+
});
|
|
44
56
|
router.register('settings', async () => {
|
|
45
57
|
const html = await settingsView.render();
|
|
46
58
|
setTimeout(() => settingsView.bindEvents(), 50);
|
|
47
59
|
return html;
|
|
48
60
|
});
|
|
49
|
-
router.register('skills', async () => {
|
|
50
|
-
const html = await skillsView.render();
|
|
51
|
-
setTimeout(() => {
|
|
52
|
-
skillsView.bindEvents();
|
|
53
|
-
skillsView.loadData();
|
|
54
|
-
}, 50);
|
|
55
|
-
return html;
|
|
56
|
-
});
|
|
57
61
|
|
|
58
62
|
// 3. Inicializar el router
|
|
59
63
|
router.init(document.getElementById('view-container'));
|
|
@@ -66,7 +70,7 @@ async function init() {
|
|
|
66
70
|
renderTopbar();
|
|
67
71
|
|
|
68
72
|
// 6. Navegar a la vista inicial
|
|
69
|
-
await router.start('
|
|
73
|
+
await router.start('dashboard');
|
|
70
74
|
|
|
71
75
|
// 7. Cargar time entries en background
|
|
72
76
|
timeTracker.loadEntries().catch(err => {
|
|
@@ -76,7 +80,10 @@ async function init() {
|
|
|
76
80
|
// 8. Inicializar onboarding
|
|
77
81
|
onboarding.init();
|
|
78
82
|
|
|
79
|
-
// 9.
|
|
83
|
+
// 9. Inicializar atajos de teclado
|
|
84
|
+
keyboard.init();
|
|
85
|
+
|
|
86
|
+
// 10. Suscribir refreshes globales
|
|
80
87
|
_bindGlobalEvents();
|
|
81
88
|
|
|
82
89
|
// 10. Auto-refresh cada 60s
|
|
@@ -161,22 +168,11 @@ function _bindGlobalEvents() {
|
|
|
161
168
|
// Búsqueda global → refrescar la vista actual
|
|
162
169
|
window.addEventListener('ops:search', () => {
|
|
163
170
|
const active = router.current();
|
|
164
|
-
if (active === '
|
|
171
|
+
if (active === 'tasks') {
|
|
165
172
|
router.refresh();
|
|
166
173
|
}
|
|
167
174
|
});
|
|
168
175
|
|
|
169
|
-
// Navegación por teclado: Escape cierra modales / deselecciona
|
|
170
|
-
document.addEventListener('keydown', e => {
|
|
171
|
-
if (e.key === 'Escape') {
|
|
172
|
-
// Deseleccionar tarea si no hay modal abierto
|
|
173
|
-
const modalEl = document.querySelector('.modal-overlay:not(.is-hidden)');
|
|
174
|
-
if (!modalEl) {
|
|
175
|
-
// No deseleccionar: permite a las vistas manejar escape internamente
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
176
|
// Actualizar sidebar badges cuando cambia el payload
|
|
181
177
|
state.subscribe('payload', () => {
|
|
182
178
|
import('./views/sidebar.js').then(m => m.updateBadges?.());
|