daily-focus 1.1.1-dev.3 → 1.2.0-dev.10
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/README.md +34 -20
- package/SETUP.md +93 -20
- package/dist/{audit-B5GKGH2P.js → audit-7ZCLKF46.js} +6 -5
- package/dist/{chunk-YWHADSKR.js → chunk-64XB7UDN.js} +1 -1
- package/dist/{chunk-NWYOCDUU.js → chunk-J7ZYVUG6.js} +4 -6
- package/dist/chunk-ODJGQCM3.js +1003 -0
- package/dist/{chunk-C6FXWHGT.js → chunk-RZNQJ6UG.js} +123 -282
- package/dist/{chunk-AUBJ2IDQ.js → chunk-Z4SFMMRQ.js} +2 -2
- package/dist/cli.js +9 -8
- package/dist/{demo-AMK3Y4JZ.js → demo-BYLLMKSQ.js} +135 -32
- package/dist/{init-YGOPPELJ.js → init-EMZDG2I7.js} +1 -9
- package/dist/{seed-57RJGU4Y.js → seed-JU4LQ33D.js} +3 -3
- package/dist/{server-5HCA62YY.js → server-WQYUOKB3.js} +416 -384
- package/dist/{service-63U4WBUH.js → service-PUJ3YDH5.js} +1 -1
- package/package.json +2 -2
- package/prompts/README.md +2 -3
- package/prompts/assistant.md +14 -3
- package/prompts/morning-brief-personal.md +1 -25
- package/prompts/morning-brief-work.md +8 -33
- package/public/app.js +440 -441
- package/public/style.css +192 -181
- package/dist/chunk-GFCWPYEI.js +0 -456
package/public/app.js
CHANGED
|
@@ -69,9 +69,9 @@ function H() {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
function L(n3, l5, u4, t4, i4, r4, o4, e4, f4, c4, a4) {
|
|
72
|
-
var s4, h5, p5, v4,
|
|
73
|
-
for (f4 = T(u4, l5, g4, f4, m4), s4 = 0; s4 < m4; s4++) null != (p5 = u4.__k[s4]) && (h5 = -1 != p5.__i && g4[p5.__i] || d, p5.__i = s4, _5 = q(n3, p5, h5, i4, r4, o4, e4, f4, c4, a4), v4 = p5.__e, p5.ref && h5.ref != p5.ref && (h5.ref && J(h5.ref, null, p5), a4.push(p5.ref, p5.__c || v4, p5)), null ==
|
|
74
|
-
return u4.__e =
|
|
72
|
+
var s4, h5, p5, v4, y5, _5, g4 = t4 && t4.__k || w, m4 = l5.length;
|
|
73
|
+
for (f4 = T(u4, l5, g4, f4, m4), s4 = 0; s4 < m4; s4++) null != (p5 = u4.__k[s4]) && (h5 = -1 != p5.__i && g4[p5.__i] || d, p5.__i = s4, _5 = q(n3, p5, h5, i4, r4, o4, e4, f4, c4, a4), v4 = p5.__e, p5.ref && h5.ref != p5.ref && (h5.ref && J(h5.ref, null, p5), a4.push(p5.ref, p5.__c || v4, p5)), null == y5 && null != v4 && (y5 = v4), 4 & p5.__u ? (f4 = j(p5, f4, n3), h5.__e && (h5.__e = null)) : "function" == typeof p5.type && void 0 !== _5 ? f4 = _5 : v4 && (f4 = v4.nextSibling), p5.__u &= -7);
|
|
74
|
+
return u4.__e = y5, f4;
|
|
75
75
|
}
|
|
76
76
|
function T(n3, l5, u4, t4, i4) {
|
|
77
77
|
var r4, o4, e4, f4, c4, a4 = u4.length, s4 = a4, h5 = 0;
|
|
@@ -131,29 +131,29 @@ function V(n3) {
|
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
function q(n3, u4, t4, i4, r4, o4, e4, f4, c4, a4) {
|
|
134
|
-
var s4, h5, p5, v4,
|
|
134
|
+
var s4, h5, p5, v4, y5, d5, _5, k3, x4, M, I2, P2, A3, H2, T4, j4, F2 = u4.type;
|
|
135
135
|
if (void 0 !== u4.constructor) return null;
|
|
136
136
|
128 & t4.__u && (c4 = !!(32 & t4.__u), o4 = [f4 = u4.__e = t4.__e]), (s4 = l.__b) && s4(u4);
|
|
137
137
|
n: if ("function" == typeof F2) {
|
|
138
138
|
h5 = e4.length;
|
|
139
139
|
try {
|
|
140
|
-
if (x4 = u4.props, M = F2.prototype && F2.prototype.render, I2 = (s4 = F2.contextType) && i4[s4.__c], P2 = s4 ? I2 ? I2.props.value : s4.__ : i4, t4.__c ? k3 = (p5 = u4.__c = t4.__c).__ = p5.__E : (M ? u4.__c = p5 = new F2(x4, P2) : (u4.__c = p5 = new C(x4, P2), p5.constructor = F2, p5.render = Q), I2 && I2.sub(p5), p5.state || (p5.state = {}), p5.__n = i4, v4 = p5.__d = true, p5.__h = [], p5._sb = []), M && null == p5.__s && (p5.__s = p5.state), M && null != F2.getDerivedStateFromProps && (p5.__s == p5.state && (p5.__s = m({}, p5.__s)), m(p5.__s, F2.getDerivedStateFromProps(x4, p5.__s))),
|
|
140
|
+
if (x4 = u4.props, M = F2.prototype && F2.prototype.render, I2 = (s4 = F2.contextType) && i4[s4.__c], P2 = s4 ? I2 ? I2.props.value : s4.__ : i4, t4.__c ? k3 = (p5 = u4.__c = t4.__c).__ = p5.__E : (M ? u4.__c = p5 = new F2(x4, P2) : (u4.__c = p5 = new C(x4, P2), p5.constructor = F2, p5.render = Q), I2 && I2.sub(p5), p5.state || (p5.state = {}), p5.__n = i4, v4 = p5.__d = true, p5.__h = [], p5._sb = []), M && null == p5.__s && (p5.__s = p5.state), M && null != F2.getDerivedStateFromProps && (p5.__s == p5.state && (p5.__s = m({}, p5.__s)), m(p5.__s, F2.getDerivedStateFromProps(x4, p5.__s))), y5 = p5.props, d5 = p5.state, p5.__v = u4, v4) M && null == F2.getDerivedStateFromProps && null != p5.componentWillMount && p5.componentWillMount(), M && null != p5.componentDidMount && p5.__h.push(p5.componentDidMount);
|
|
141
141
|
else {
|
|
142
|
-
if (M && null == F2.getDerivedStateFromProps && x4 !==
|
|
142
|
+
if (M && null == F2.getDerivedStateFromProps && x4 !== y5 && null != p5.componentWillReceiveProps && p5.componentWillReceiveProps(x4, P2), u4.__v == t4.__v || !p5.__e && null != p5.shouldComponentUpdate && false === p5.shouldComponentUpdate(x4, p5.__s, P2)) {
|
|
143
143
|
u4.__v != t4.__v && (p5.props = x4, p5.state = p5.__s, p5.__d = false), u4.__e = t4.__e, u4.__k = t4.__k, u4.__k.some(function(n4) {
|
|
144
144
|
n4 && (n4.__ = u4);
|
|
145
145
|
}), w.push.apply(p5.__h, p5._sb), p5._sb = [], p5.__h.length && e4.push(p5), f4 = $(t4);
|
|
146
146
|
break n;
|
|
147
147
|
}
|
|
148
148
|
null != p5.componentWillUpdate && p5.componentWillUpdate(x4, p5.__s, P2), M && null != p5.componentDidUpdate && p5.__h.push(function() {
|
|
149
|
-
p5.componentDidUpdate(
|
|
149
|
+
p5.componentDidUpdate(y5, d5, _5);
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
if (p5.context = P2, p5.props = x4, p5.__P = n3, p5.__e = false, A3 = l.__r, H2 = 0, M) p5.state = p5.__s, p5.__d = false, A3 && A3(u4), s4 = p5.render(p5.props, p5.state, p5.context), w.push.apply(p5.__h, p5._sb), p5._sb = [];
|
|
153
153
|
else do {
|
|
154
154
|
p5.__d = false, A3 && A3(u4), s4 = p5.render(p5.props, p5.state, p5.context), p5.state = p5.__s;
|
|
155
155
|
} while (p5.__d && ++H2 < 25);
|
|
156
|
-
p5.state = p5.__s, null != p5.getChildContext && (i4 = m(m({}, i4), p5.getChildContext())), M && !v4 && null != p5.getSnapshotBeforeUpdate && (_5 = p5.getSnapshotBeforeUpdate(
|
|
156
|
+
p5.state = p5.__s, null != p5.getChildContext && (i4 = m(m({}, i4), p5.getChildContext())), M && !v4 && null != p5.getSnapshotBeforeUpdate && (_5 = p5.getSnapshotBeforeUpdate(y5, d5)), T4 = null != s4 && s4.type === S && null == s4.key ? E(s4.props.children) : s4, f4 = L(n3, g(T4) ? T4 : [T4], u4, t4, i4, r4, o4, e4, f4, c4, a4), p5.base = u4.__e, u4.__u &= -161, p5.__h.length && e4.push(p5), k3 && (p5.__E = p5.__ = null);
|
|
157
157
|
} catch (n4) {
|
|
158
158
|
if (e4.length = h5, u4.__v = null, c4 || null != o4) {
|
|
159
159
|
if (n4.then) {
|
|
@@ -185,10 +185,10 @@ function E(n3) {
|
|
|
185
185
|
return "object" != typeof n3 || null == n3 || n3.__b > 0 ? n3 : g(n3) ? n3.map(E) : void 0 !== n3.constructor ? null : m({}, n3);
|
|
186
186
|
}
|
|
187
187
|
function G(u4, t4, i4, r4, o4, e4, f4, c4, a4) {
|
|
188
|
-
var s4, h5, p5, v4,
|
|
188
|
+
var s4, h5, p5, v4, y5, w5, _5, m4 = i4.props || d, k3 = t4.props, x4 = t4.type;
|
|
189
189
|
if ("svg" == x4 ? o4 = "http://www.w3.org/2000/svg" : "math" == x4 ? o4 = "http://www.w3.org/1998/Math/MathML" : o4 || (o4 = "http://www.w3.org/1999/xhtml"), null != e4) {
|
|
190
|
-
for (s4 = 0; s4 < e4.length; s4++) if ((
|
|
191
|
-
u4 =
|
|
190
|
+
for (s4 = 0; s4 < e4.length; s4++) if ((y5 = e4[s4]) && "setAttribute" in y5 == !!x4 && (x4 ? y5.localName == x4 : 3 == y5.nodeType)) {
|
|
191
|
+
u4 = y5, e4[s4] = null;
|
|
192
192
|
break;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
@@ -198,9 +198,9 @@ function G(u4, t4, i4, r4, o4, e4, f4, c4, a4) {
|
|
|
198
198
|
}
|
|
199
199
|
if (null == x4) m4 === k3 || c4 && u4.data == k3 || (u4.data = k3);
|
|
200
200
|
else {
|
|
201
|
-
if (e4 = "textarea" == x4 && null != k3.defaultValue ? null : e4 && n.call(u4.childNodes), !c4 && null != e4) for (m4 = {}, s4 = 0; s4 < u4.attributes.length; s4++) m4[(
|
|
202
|
-
for (s4 in m4)
|
|
203
|
-
for (s4 in k3)
|
|
201
|
+
if (e4 = "textarea" == x4 && null != k3.defaultValue ? null : e4 && n.call(u4.childNodes), !c4 && null != e4) for (m4 = {}, s4 = 0; s4 < u4.attributes.length; s4++) m4[(y5 = u4.attributes[s4]).name] = y5.value;
|
|
202
|
+
for (s4 in m4) y5 = m4[s4], "dangerouslySetInnerHTML" == s4 ? p5 = y5 : "children" == s4 || s4 in k3 || "value" == s4 && "defaultValue" in k3 || "checked" == s4 && "defaultChecked" in k3 || N(u4, s4, null, y5, o4);
|
|
203
|
+
for (s4 in k3) y5 = k3[s4], "children" == s4 ? v4 = y5 : "dangerouslySetInnerHTML" == s4 ? h5 = y5 : "value" == s4 ? w5 = y5 : "checked" == s4 ? _5 = y5 : c4 && "function" != typeof y5 || m4[s4] === y5 || N(u4, s4, y5, m4[s4], o4);
|
|
204
204
|
if (h5) c4 || p5 && (h5.__html == p5.__html || h5.__html == u4.innerHTML) || (u4.innerHTML = h5.__html), t4.__k = [];
|
|
205
205
|
else if (p5 && (u4.innerHTML = ""), L("template" == t4.type ? u4.content : u4, g(v4) ? v4 : [v4], t4, i4, r4, "foreignObject" == x4 ? "http://www.w3.org/1999/xhtml" : o4, e4, f4, e4 ? e4[0] : i4.__k && $(i4, 0), c4, a4), null != e4) for (s4 = e4.length; s4--; ) b(e4[s4]);
|
|
206
206
|
c4 && "textarea" != x4 || (s4 = "value", "progress" == x4 && null == w5 ? u4.removeAttribute("value") : null != w5 && (w5 !== u4[s4] || "progress" == x4 && !w5 || "option" == x4 && w5 != m4[s4]) && N(u4, s4, w5, m4[s4], o4), s4 = "checked", null != _5 && _5 != u4[s4] && N(u4, s4, _5, m4[s4], o4));
|
|
@@ -274,6 +274,42 @@ function s2(n3, t4) {
|
|
|
274
274
|
var u4 = r2.__H || (r2.__H = { __: [], __h: [] });
|
|
275
275
|
return n3 >= u4.__.length && u4.__.push({}), u4.__[n3];
|
|
276
276
|
}
|
|
277
|
+
function d2(n3) {
|
|
278
|
+
return o2 = 1, y2(D2, n3);
|
|
279
|
+
}
|
|
280
|
+
function y2(n3, u4, i4) {
|
|
281
|
+
var o4 = s2(t2++, 2);
|
|
282
|
+
if (o4.t = n3, !o4.__c && (o4.__ = [i4 ? i4(u4) : D2(void 0, u4), function(n4) {
|
|
283
|
+
var t4 = o4.__N ? o4.__N[0] : o4.__[0], r4 = o4.t(t4, n4);
|
|
284
|
+
t4 !== r4 && (o4.__N = [r4, o4.__[1]], o4.__c.setState({}));
|
|
285
|
+
}], o4.__c = r2, !r2.__f)) {
|
|
286
|
+
var f4 = function(n4, t4, r4) {
|
|
287
|
+
if (!o4.__c.__H) return true;
|
|
288
|
+
var u5 = false, i5 = o4.__c.props !== n4;
|
|
289
|
+
if (o4.__c.__H.__.some(function(n5) {
|
|
290
|
+
if (n5.__N) {
|
|
291
|
+
u5 = true;
|
|
292
|
+
var t5 = n5.__[0];
|
|
293
|
+
n5.__ = n5.__N, n5.__N = void 0, t5 !== n5.__[0] && (i5 = true);
|
|
294
|
+
}
|
|
295
|
+
}), c4) {
|
|
296
|
+
var f5 = c4.call(this, n4, t4, r4);
|
|
297
|
+
return u5 ? f5 || i5 : f5;
|
|
298
|
+
}
|
|
299
|
+
return !u5 || i5;
|
|
300
|
+
};
|
|
301
|
+
r2.__f = true;
|
|
302
|
+
var c4 = r2.shouldComponentUpdate, e4 = r2.componentWillUpdate;
|
|
303
|
+
r2.componentWillUpdate = function(n4, t4, r4) {
|
|
304
|
+
if (this.__e) {
|
|
305
|
+
var u5 = c4;
|
|
306
|
+
c4 = void 0, f4(n4, t4, r4), c4 = u5;
|
|
307
|
+
}
|
|
308
|
+
e4 && e4.call(this, n4, t4, r4);
|
|
309
|
+
}, r2.shouldComponentUpdate = f4;
|
|
310
|
+
}
|
|
311
|
+
return o4.__N || o4.__;
|
|
312
|
+
}
|
|
277
313
|
function h2(n3, u4) {
|
|
278
314
|
var i4 = s2(t2++, 3);
|
|
279
315
|
!c2.__s && C2(i4.__H, u4) && (i4.__ = n3, i4.u = u4, r2.__H.__h.push(i4));
|
|
@@ -360,6 +396,9 @@ function C2(n3, t4) {
|
|
|
360
396
|
return t5 !== n3[r4];
|
|
361
397
|
});
|
|
362
398
|
}
|
|
399
|
+
function D2(n3, t4) {
|
|
400
|
+
return "function" == typeof t4 ? t4(n3) : t4;
|
|
401
|
+
}
|
|
363
402
|
|
|
364
403
|
// node_modules/@preact/signals-core/dist/signals-core.module.js
|
|
365
404
|
var i3 = /* @__PURE__ */ Symbol.for("preact-signals");
|
|
@@ -430,7 +469,7 @@ var s3 = 0;
|
|
|
430
469
|
var u3 = 0;
|
|
431
470
|
var e3 = 0;
|
|
432
471
|
var c3 = void 0;
|
|
433
|
-
var
|
|
472
|
+
var d3 = 0;
|
|
434
473
|
function a3(i4) {
|
|
435
474
|
if (void 0 !== o3) {
|
|
436
475
|
var t4 = i4.n;
|
|
@@ -543,7 +582,7 @@ Object.defineProperty(l3.prototype, "value", { get: function() {
|
|
|
543
582
|
})(this);
|
|
544
583
|
this.v = i4;
|
|
545
584
|
this.i++;
|
|
546
|
-
|
|
585
|
+
d3++;
|
|
547
586
|
v3++;
|
|
548
587
|
try {
|
|
549
588
|
for (var n3 = this.t; void 0 !== n3; n3 = n3.x) n3.t.N();
|
|
@@ -552,7 +591,7 @@ Object.defineProperty(l3.prototype, "value", { get: function() {
|
|
|
552
591
|
}
|
|
553
592
|
}
|
|
554
593
|
} });
|
|
555
|
-
function
|
|
594
|
+
function y3(i4, t4) {
|
|
556
595
|
return new l3(i4, t4);
|
|
557
596
|
}
|
|
558
597
|
function w3(i4) {
|
|
@@ -590,7 +629,7 @@ function p3(i4, t4) {
|
|
|
590
629
|
l3.call(this, void 0, t4);
|
|
591
630
|
this.x = i4;
|
|
592
631
|
this.s = void 0;
|
|
593
|
-
this.g =
|
|
632
|
+
this.g = d3 - 1;
|
|
594
633
|
this.f = 4;
|
|
595
634
|
}
|
|
596
635
|
p3.prototype = new l3();
|
|
@@ -599,8 +638,8 @@ p3.prototype.h = function() {
|
|
|
599
638
|
if (1 & this.f) return false;
|
|
600
639
|
if (32 == (36 & this.f)) return true;
|
|
601
640
|
this.f &= -5;
|
|
602
|
-
if (this.g ===
|
|
603
|
-
this.g =
|
|
641
|
+
if (this.g === d3) return true;
|
|
642
|
+
this.g = d3;
|
|
604
643
|
this.f |= 1;
|
|
605
644
|
if (this.i > 0 && !w3(this)) {
|
|
606
645
|
this.f &= -2;
|
|
@@ -754,7 +793,7 @@ function j3(i4, t4) {
|
|
|
754
793
|
// node_modules/@preact/signals/dist/signals.module.js
|
|
755
794
|
var l4;
|
|
756
795
|
var h4;
|
|
757
|
-
var
|
|
796
|
+
var d4;
|
|
758
797
|
var p4 = "undefined" != typeof window && !!window.__PREACT_SIGNALS_DEVTOOLS__;
|
|
759
798
|
var _4 = [];
|
|
760
799
|
j3(function() {
|
|
@@ -765,14 +804,14 @@ function g3(i4, r4) {
|
|
|
765
804
|
});
|
|
766
805
|
}
|
|
767
806
|
function b3(i4) {
|
|
768
|
-
if (
|
|
769
|
-
var n3 =
|
|
770
|
-
|
|
807
|
+
if (d4) {
|
|
808
|
+
var n3 = d4;
|
|
809
|
+
d4 = void 0;
|
|
771
810
|
n3();
|
|
772
811
|
}
|
|
773
|
-
|
|
812
|
+
d4 = i4 && i4.S();
|
|
774
813
|
}
|
|
775
|
-
function
|
|
814
|
+
function y4(i4) {
|
|
776
815
|
var n3 = this, t4 = i4.data, f4 = useSignal(t4);
|
|
777
816
|
f4.name = "ReactiveDom";
|
|
778
817
|
f4.value = t4;
|
|
@@ -802,8 +841,8 @@ function y3(i4) {
|
|
|
802
841
|
}, []), a4 = e4[0], v4 = e4[1];
|
|
803
842
|
return a4.value ? v4.peek() : v4.value;
|
|
804
843
|
}
|
|
805
|
-
|
|
806
|
-
Object.defineProperties(l3.prototype, { constructor: { configurable: true, value: void 0 }, type: { configurable: true, value:
|
|
844
|
+
y4.displayName = "ReactiveTextNode";
|
|
845
|
+
Object.defineProperties(l3.prototype, { constructor: { configurable: true, value: void 0 }, type: { configurable: true, value: y4 }, props: { configurable: true, get: function() {
|
|
807
846
|
var i4 = this;
|
|
808
847
|
return { data: { get value() {
|
|
809
848
|
return i4.value;
|
|
@@ -887,7 +926,7 @@ g3("diffed", function(i4, n3) {
|
|
|
887
926
|
i4(n3);
|
|
888
927
|
});
|
|
889
928
|
function w4(i4, n3, r4, t4) {
|
|
890
|
-
var o4 = n3 in i4 && void 0 === i4.ownerSVGElement, f4 =
|
|
929
|
+
var o4 = n3 in i4 && void 0 === i4.ownerSVGElement, f4 = y3(r4);
|
|
891
930
|
return { o: function(i5, n4) {
|
|
892
931
|
f4.value = i5;
|
|
893
932
|
t4 = n4;
|
|
@@ -955,7 +994,7 @@ C.prototype.shouldComponentUpdate = function(i4, n3) {
|
|
|
955
994
|
};
|
|
956
995
|
function useSignal(i4, n3) {
|
|
957
996
|
return T2(function() {
|
|
958
|
-
return
|
|
997
|
+
return y3(i4, n3);
|
|
959
998
|
}, []);
|
|
960
999
|
}
|
|
961
1000
|
var q2 = function(i4) {
|
|
@@ -1013,9 +1052,6 @@ function subscribe(onState, onError) {
|
|
|
1013
1052
|
function postTimeZone(timeZone) {
|
|
1014
1053
|
return post("/api/timezone", { timeZone });
|
|
1015
1054
|
}
|
|
1016
|
-
function postSession(body) {
|
|
1017
|
-
return post("/api/session", body);
|
|
1018
|
-
}
|
|
1019
1055
|
function postBoardRefresh() {
|
|
1020
1056
|
return post("/api/board/refresh");
|
|
1021
1057
|
}
|
|
@@ -1080,40 +1116,35 @@ var VIEWS = ["today", "board", "tickets", "settings"];
|
|
|
1080
1116
|
var RUN_PREFIX = "run:";
|
|
1081
1117
|
var PANEL_PREFIX = "panel:";
|
|
1082
1118
|
var VIEW_KEY = "daily-focus:view";
|
|
1083
|
-
var UNATTENDED_SEEN_KEY = "daily-focus:unattended-seen";
|
|
1084
1119
|
var AGENT_RUN_SEEN_KEY = "daily-focus:agent-run-seen";
|
|
1085
|
-
var FOCUS_MODE_KEY = "daily-focus:focus-mode";
|
|
1086
1120
|
var DETAIL_KEY = "daily-focus:detail-for";
|
|
1087
|
-
var state =
|
|
1121
|
+
var state = y3(null);
|
|
1088
1122
|
function createUi(initial = {}) {
|
|
1089
1123
|
return {
|
|
1090
|
-
selectedId:
|
|
1091
|
-
clickedId:
|
|
1092
|
-
pending:
|
|
1093
|
-
menuFor:
|
|
1094
|
-
statusFor:
|
|
1095
|
-
detailFor:
|
|
1096
|
-
noteDraft:
|
|
1097
|
-
assistantDraft:
|
|
1098
|
-
focusField:
|
|
1099
|
-
openDrawers:
|
|
1100
|
-
ticketMode:
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
settingsSaving: y2(initial.settingsSaving ?? false),
|
|
1115
|
-
texts: y2(initial.texts ?? {}),
|
|
1116
|
-
calendars: y2(initial.calendars ?? null)
|
|
1124
|
+
selectedId: y3(initial.selectedId ?? null),
|
|
1125
|
+
clickedId: y3(initial.clickedId ?? null),
|
|
1126
|
+
pending: y3(initial.pending ?? /* @__PURE__ */ new Set()),
|
|
1127
|
+
menuFor: y3(initial.menuFor ?? null),
|
|
1128
|
+
statusFor: y3(initial.statusFor ?? null),
|
|
1129
|
+
detailFor: y3(initial.detailFor ?? null),
|
|
1130
|
+
noteDraft: y3(initial.noteDraft ?? ""),
|
|
1131
|
+
assistantDraft: y3(initial.assistantDraft ?? ""),
|
|
1132
|
+
focusField: y3(initial.focusField ?? null),
|
|
1133
|
+
openDrawers: y3(initial.openDrawers ?? /* @__PURE__ */ new Set()),
|
|
1134
|
+
ticketMode: y3(initial.ticketMode ?? "sync"),
|
|
1135
|
+
agentReportSeen: y3(initial.agentReportSeen ?? null),
|
|
1136
|
+
messageOpen: y3(initial.messageOpen ?? /* @__PURE__ */ new Map()),
|
|
1137
|
+
view: y3(initial.view ?? "today"),
|
|
1138
|
+
theme: y3(initial.theme ?? "system"),
|
|
1139
|
+
toast: y3(initial.toast ?? null),
|
|
1140
|
+
connectionError: y3(initial.connectionError ?? null),
|
|
1141
|
+
settingsReturn: y3(initial.settingsReturn ?? "today"),
|
|
1142
|
+
settings: y3(initial.settings ?? null),
|
|
1143
|
+
settingsDraft: y3(initial.settingsDraft ?? /* @__PURE__ */ new Map()),
|
|
1144
|
+
settingsError: y3(initial.settingsError ?? null),
|
|
1145
|
+
settingsSaving: y3(initial.settingsSaving ?? false),
|
|
1146
|
+
texts: y3(initial.texts ?? {}),
|
|
1147
|
+
calendars: y3(initial.calendars ?? null)
|
|
1117
1148
|
};
|
|
1118
1149
|
}
|
|
1119
1150
|
function isView(value) {
|
|
@@ -1125,9 +1156,7 @@ function remembered() {
|
|
|
1125
1156
|
return {
|
|
1126
1157
|
// Settings is a page to visit, so a reload returns to the view underneath.
|
|
1127
1158
|
view: isView(view) && view !== "settings" ? view : "today",
|
|
1128
|
-
unattendedSeen: localStorage.getItem(UNATTENDED_SEEN_KEY),
|
|
1129
1159
|
agentReportSeen: localStorage.getItem(AGENT_RUN_SEEN_KEY),
|
|
1130
|
-
focusMode: localStorage.getItem(FOCUS_MODE_KEY) === "1",
|
|
1131
1160
|
detailFor: sessionStorage.getItem(DETAIL_KEY)
|
|
1132
1161
|
};
|
|
1133
1162
|
} catch {
|
|
@@ -1295,208 +1324,6 @@ function ThemeToggle({ ui: ui2, handlers: handlers2 }) {
|
|
|
1295
1324
|
);
|
|
1296
1325
|
}
|
|
1297
1326
|
|
|
1298
|
-
// client/format.ts
|
|
1299
|
-
var DAY_FORMAT = {
|
|
1300
|
-
weekday: "long",
|
|
1301
|
-
day: "numeric",
|
|
1302
|
-
month: "long"
|
|
1303
|
-
};
|
|
1304
|
-
function formatters(timeZone) {
|
|
1305
|
-
return {
|
|
1306
|
-
time: new Intl.DateTimeFormat(void 0, { timeZone, hour: "2-digit", minute: "2-digit" }),
|
|
1307
|
-
day: new Intl.DateTimeFormat(void 0, { timeZone, ...DAY_FORMAT }),
|
|
1308
|
-
shortDay: new Intl.DateTimeFormat(void 0, { timeZone, day: "numeric", month: "short" }),
|
|
1309
|
-
shortDayYear: new Intl.DateTimeFormat(void 0, { timeZone, day: "numeric", month: "short", year: "numeric" }),
|
|
1310
|
-
weekday: new Intl.DateTimeFormat(void 0, { timeZone, weekday: "long" })
|
|
1311
|
-
};
|
|
1312
|
-
}
|
|
1313
|
-
var clockFormats = formatters();
|
|
1314
|
-
var dateFormats = formatters("UTC");
|
|
1315
|
-
var DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
1316
|
-
function formatted(value, kind) {
|
|
1317
|
-
const bare = typeof value === "string" && DATE_ONLY.test(value);
|
|
1318
|
-
const d4 = bare ? /* @__PURE__ */ new Date(`${value}T00:00:00Z`) : parseDate(value);
|
|
1319
|
-
return d4 && !Number.isNaN(d4.getTime()) ? (bare ? dateFormats : clockFormats)[kind].format(d4) : "";
|
|
1320
|
-
}
|
|
1321
|
-
function parseDate(value) {
|
|
1322
|
-
if (typeof value !== "string" || value === "") return null;
|
|
1323
|
-
const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
1324
|
-
if (dateOnly) return new Date(+dateOnly[1], +dateOnly[2] - 1, +dateOnly[3]);
|
|
1325
|
-
const d4 = new Date(value);
|
|
1326
|
-
return Number.isNaN(d4.getTime()) ? null : d4;
|
|
1327
|
-
}
|
|
1328
|
-
function formatTime(value) {
|
|
1329
|
-
return formatted(value, "time");
|
|
1330
|
-
}
|
|
1331
|
-
function formatDay(value) {
|
|
1332
|
-
return formatted(value, "day");
|
|
1333
|
-
}
|
|
1334
|
-
function formatShortDay(value) {
|
|
1335
|
-
return formatted(value, "shortDay");
|
|
1336
|
-
}
|
|
1337
|
-
function formatWeekday(value) {
|
|
1338
|
-
return formatted(value, "weekday");
|
|
1339
|
-
}
|
|
1340
|
-
var dayKeyFmt = null;
|
|
1341
|
-
var calendarZone;
|
|
1342
|
-
function setCalendarZone(timeZone) {
|
|
1343
|
-
if (timeZone === calendarZone) return;
|
|
1344
|
-
calendarZone = timeZone;
|
|
1345
|
-
try {
|
|
1346
|
-
clockFormats = formatters(timeZone);
|
|
1347
|
-
dayKeyFmt = timeZone ? new Intl.DateTimeFormat("en-US", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }) : null;
|
|
1348
|
-
} catch {
|
|
1349
|
-
dayKeyFmt = null;
|
|
1350
|
-
clockFormats = formatters();
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
function dayKey(d4) {
|
|
1354
|
-
if (dayKeyFmt) {
|
|
1355
|
-
const parts = dayKeyFmt.formatToParts(d4);
|
|
1356
|
-
const part = (type) => parts.find((p5) => p5.type === type)?.value ?? "";
|
|
1357
|
-
return `${part("year")}-${part("month")}-${part("day")}`;
|
|
1358
|
-
}
|
|
1359
|
-
const m4 = String(d4.getMonth() + 1).padStart(2, "0");
|
|
1360
|
-
const day = String(d4.getDate()).padStart(2, "0");
|
|
1361
|
-
return `${d4.getFullYear()}-${m4}-${day}`;
|
|
1362
|
-
}
|
|
1363
|
-
function splitKey(key) {
|
|
1364
|
-
const [y4, m4, d4] = key.split("-").map(Number);
|
|
1365
|
-
return [y4, m4 - 1, d4];
|
|
1366
|
-
}
|
|
1367
|
-
function keyAt(ms) {
|
|
1368
|
-
return new Date(ms).toISOString().slice(0, 10);
|
|
1369
|
-
}
|
|
1370
|
-
function addDays(key, days) {
|
|
1371
|
-
const [y4, m4, d4] = splitKey(key);
|
|
1372
|
-
return keyAt(Date.UTC(y4, m4, d4 + days));
|
|
1373
|
-
}
|
|
1374
|
-
function addMonths(key, months) {
|
|
1375
|
-
const [y4, m4, d4] = splitKey(key);
|
|
1376
|
-
const lastDay = new Date(Date.UTC(y4, m4 + months + 1, 0)).getUTCDate();
|
|
1377
|
-
return keyAt(Date.UTC(y4, m4 + months, Math.min(d4, lastDay)));
|
|
1378
|
-
}
|
|
1379
|
-
function daysFromToday(value, now = /* @__PURE__ */ new Date()) {
|
|
1380
|
-
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
1381
|
-
const [y4, m4, d4] = splitKey(value);
|
|
1382
|
-
const [ty, tm, td] = splitKey(dayKey(now));
|
|
1383
|
-
return Math.round((Date.UTC(y4, m4, d4) - Date.UTC(ty, tm, td)) / 864e5);
|
|
1384
|
-
}
|
|
1385
|
-
const target = parseDate(value);
|
|
1386
|
-
if (!target) return null;
|
|
1387
|
-
const a4 = Date.UTC(...splitKey(dayKey(now)));
|
|
1388
|
-
const b4 = Date.UTC(...splitKey(dayKey(target)));
|
|
1389
|
-
return Math.round((b4 - a4) / 864e5);
|
|
1390
|
-
}
|
|
1391
|
-
function relativeDay(value, now = /* @__PURE__ */ new Date()) {
|
|
1392
|
-
const diff = daysFromToday(value, now);
|
|
1393
|
-
if (diff === null) return "";
|
|
1394
|
-
if (diff === 0) return "today";
|
|
1395
|
-
if (diff === 1) return "tomorrow";
|
|
1396
|
-
if (diff === -1) return "yesterday";
|
|
1397
|
-
if (diff > 1 && diff <= 7) return `in ${diff} days`;
|
|
1398
|
-
if (diff < -1 && diff >= -7) return `${Math.abs(diff)} days ago`;
|
|
1399
|
-
return formatShortDay(value);
|
|
1400
|
-
}
|
|
1401
|
-
function formatDuration(minutes) {
|
|
1402
|
-
const h5 = Math.floor(minutes / 60);
|
|
1403
|
-
const m4 = minutes % 60;
|
|
1404
|
-
if (h5 === 0) return `${m4} min`;
|
|
1405
|
-
if (m4 === 0) return `${h5} h`;
|
|
1406
|
-
return `${h5} h ${m4} min`;
|
|
1407
|
-
}
|
|
1408
|
-
function relativeTime(value, now = /* @__PURE__ */ new Date()) {
|
|
1409
|
-
const d4 = parseDate(value);
|
|
1410
|
-
if (!d4) return "";
|
|
1411
|
-
const seconds = Math.round((now.getTime() - d4.getTime()) / 1e3);
|
|
1412
|
-
if (seconds < 60) return "just now";
|
|
1413
|
-
const minutes = Math.round(seconds / 60);
|
|
1414
|
-
if (minutes < 60) return `${minutes} min ago`;
|
|
1415
|
-
const hours = Math.round(minutes / 60);
|
|
1416
|
-
if (hours < 48) return `${hours} h ago`;
|
|
1417
|
-
const days = Math.round(hours / 24);
|
|
1418
|
-
if (days <= 30) return `${days} days ago`;
|
|
1419
|
-
return dayKey(d4).slice(0, 4) === dayKey(now).slice(0, 4) ? formatShortDay(value) : formatted(value, "shortDayYear");
|
|
1420
|
-
}
|
|
1421
|
-
function firstLine(text) {
|
|
1422
|
-
const line = String(text).split("\n").find((l5) => l5.trim() !== "") ?? "";
|
|
1423
|
-
return line.replace(/^[#>*\-\s]+/, "").replace(/[*_`]/g, "").trim();
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
// client/timer.ts
|
|
1427
|
-
function clock(seconds) {
|
|
1428
|
-
const total = Math.abs(seconds);
|
|
1429
|
-
const mm = Math.floor(total / 60);
|
|
1430
|
-
const ss = Math.floor(total % 60);
|
|
1431
|
-
return `${seconds < 0 ? "+" : ""}${mm}:${String(ss).padStart(2, "0")}`;
|
|
1432
|
-
}
|
|
1433
|
-
function remainingSeconds(active, nowMs) {
|
|
1434
|
-
return Math.round((new Date(active.endsAt).getTime() - nowMs) / 1e3);
|
|
1435
|
-
}
|
|
1436
|
-
function unattendedNotice(closed, handlers2) {
|
|
1437
|
-
const stoppedAt = formatTime(closed.endedAt);
|
|
1438
|
-
const headline = closed.reason === "away" ? `Timer stopped at ${stoppedAt} \u2014 nothing had touched the machine since.` : `Timer stopped at ${stoppedAt} \u2014 it had been left running.`;
|
|
1439
|
-
return el(
|
|
1440
|
-
"div",
|
|
1441
|
-
{ class: "timer__away", role: "status" },
|
|
1442
|
-
el(
|
|
1443
|
-
"span",
|
|
1444
|
-
{ class: "timer__away-body" },
|
|
1445
|
-
el("span", { class: "timer__away-text" }, headline),
|
|
1446
|
-
el(
|
|
1447
|
-
"span",
|
|
1448
|
-
{ class: "timer__away-detail" },
|
|
1449
|
-
`${formatDuration(closed.actualMinutes)} logged on \u201C${closed.title}\u201D. `,
|
|
1450
|
-
closed.reason === "away" ? "The time you were away is not in the record." : "Treat that as an upper bound, not a measurement."
|
|
1451
|
-
)
|
|
1452
|
-
),
|
|
1453
|
-
el("button", { type: "button", class: "button", onClick: () => handlers2.startSession(closed.id) }, "Pick it back up"),
|
|
1454
|
-
el(
|
|
1455
|
-
"button",
|
|
1456
|
-
{
|
|
1457
|
-
type: "button",
|
|
1458
|
-
class: "icon-button",
|
|
1459
|
-
"aria-label": "Dismiss",
|
|
1460
|
-
onClick: () => handlers2.dismissUnattended(closed.endedAt)
|
|
1461
|
-
},
|
|
1462
|
-
"\u2715"
|
|
1463
|
-
)
|
|
1464
|
-
);
|
|
1465
|
-
}
|
|
1466
|
-
function Timer({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
1467
|
-
const { active, completedToday, minutesToday, unattendedClose } = state2.session;
|
|
1468
|
-
const closed = unattendedClose && ui2.unattendedSeen.value !== unattendedClose.endedAt ? unattendedClose : null;
|
|
1469
|
-
if (!active && completedToday === 0 && !closed) {
|
|
1470
|
-
return el("div", { class: "timer", id: "timer", hidden: true });
|
|
1471
|
-
}
|
|
1472
|
-
const tally = completedToday > 0 ? `${completedToday} session${completedToday === 1 ? "" : "s"} today \xB7 ${formatDuration(minutesToday)}` : null;
|
|
1473
|
-
if (!active) {
|
|
1474
|
-
return el(
|
|
1475
|
-
"div",
|
|
1476
|
-
{ class: "timer", id: "timer", hidden: false, "data-state": closed ? "stopped" : "idle" },
|
|
1477
|
-
closed ? unattendedNotice(closed, handlers2) : null,
|
|
1478
|
-
tally ? el("span", { class: "timer__tally" }, tally) : null
|
|
1479
|
-
);
|
|
1480
|
-
}
|
|
1481
|
-
const remaining = remainingSeconds(active, ui2.clock.value);
|
|
1482
|
-
const overrun = remaining < 0;
|
|
1483
|
-
return el(
|
|
1484
|
-
"div",
|
|
1485
|
-
{ class: "timer", id: "timer", hidden: false, "data-state": overrun ? "overrun" : "running" },
|
|
1486
|
-
el("span", { class: "timer__clock" }, clock(remaining)),
|
|
1487
|
-
el(
|
|
1488
|
-
"span",
|
|
1489
|
-
{ class: "timer__title" },
|
|
1490
|
-
active.title,
|
|
1491
|
-
overrun ? el("span", { class: "timer__note" }, ` \xB7 ${active.minutes} min in, still counting`) : null,
|
|
1492
|
-
// The one thing a kitchen timer can't tell you.
|
|
1493
|
-
active.collidesWithNextEvent && !overrun ? el("span", { class: "timer__note timer__note--warn" }, ` \xB7 runs into ${formatTime(active.nextEventAt)}`) : null
|
|
1494
|
-
),
|
|
1495
|
-
tally ? el("span", { class: "timer__tally" }, tally) : null,
|
|
1496
|
-
el("button", { type: "button", class: "button", onClick: () => handlers2.stopSession() }, "Stop")
|
|
1497
|
-
);
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
1327
|
// client/actions.ts
|
|
1501
1328
|
function afterRender(fn) {
|
|
1502
1329
|
if (typeof requestAnimationFrame === "function") requestAnimationFrame(fn);
|
|
@@ -1550,7 +1377,6 @@ function adoptState(next) {
|
|
|
1550
1377
|
state.value = next;
|
|
1551
1378
|
ui.connectionError.value = null;
|
|
1552
1379
|
});
|
|
1553
|
-
startLocalTick();
|
|
1554
1380
|
checkStore(next.storeId);
|
|
1555
1381
|
checkAssetVersion(next.assetVersion);
|
|
1556
1382
|
}
|
|
@@ -1593,7 +1419,8 @@ var PAST_TENSE = {
|
|
|
1593
1419
|
dismiss: "Dismissed",
|
|
1594
1420
|
snooze: "Snoozed",
|
|
1595
1421
|
reopen: "Restored",
|
|
1596
|
-
note: "Note saved"
|
|
1422
|
+
note: "Note saved",
|
|
1423
|
+
nudge: "Nudged, back tomorrow"
|
|
1597
1424
|
};
|
|
1598
1425
|
var lastAction = null;
|
|
1599
1426
|
var parkedFrom = /* @__PURE__ */ new Map();
|
|
@@ -1605,6 +1432,9 @@ function unpark(id) {
|
|
|
1605
1432
|
function undoLast() {
|
|
1606
1433
|
if (lastAction && lastAction.action !== "reopen") void unpark(lastAction.id);
|
|
1607
1434
|
}
|
|
1435
|
+
function isRemark(action) {
|
|
1436
|
+
return action === "note" || action === "nudge";
|
|
1437
|
+
}
|
|
1608
1438
|
function optimistic(current, id, action, extra) {
|
|
1609
1439
|
const status = action === "reopen" ? "open" : action === "dismiss" ? "dismissed" : action === "done" ? "done" : "snoozed";
|
|
1610
1440
|
const statusAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1631,12 +1461,12 @@ async function applyAction(id, action, extra = {}) {
|
|
|
1631
1461
|
if (row && action === "snooze" && item && (item.status === "done" || item.status === "dismissed")) {
|
|
1632
1462
|
parkedFrom.set(id, item.status === "done" ? "done" : "dismiss");
|
|
1633
1463
|
}
|
|
1634
|
-
if (action
|
|
1464
|
+
if (!isRemark(action)) state.value = optimistic(current, id, action, extra);
|
|
1635
1465
|
});
|
|
1636
1466
|
try {
|
|
1637
1467
|
state.value = await postAction({ id, action, ...extra });
|
|
1638
1468
|
removePending(id);
|
|
1639
|
-
if (action
|
|
1469
|
+
if (isRemark(action)) {
|
|
1640
1470
|
showToast(PAST_TENSE[action]);
|
|
1641
1471
|
return;
|
|
1642
1472
|
}
|
|
@@ -1710,6 +1540,27 @@ async function stopAssistant(id) {
|
|
|
1710
1540
|
showToast(`Could not stop: ${err.message}`);
|
|
1711
1541
|
}
|
|
1712
1542
|
}
|
|
1543
|
+
async function copy(text) {
|
|
1544
|
+
try {
|
|
1545
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
1546
|
+
await navigator.clipboard.writeText(text);
|
|
1547
|
+
} else {
|
|
1548
|
+
const field = document.createElement("textarea");
|
|
1549
|
+
field.value = text;
|
|
1550
|
+
field.setAttribute("readonly", "");
|
|
1551
|
+
field.style.position = "fixed";
|
|
1552
|
+
field.style.opacity = "0";
|
|
1553
|
+
document.body.append(field);
|
|
1554
|
+
field.select();
|
|
1555
|
+
const copied = document.execCommand("copy");
|
|
1556
|
+
field.remove();
|
|
1557
|
+
if (!copied) throw new Error("the browser would not copy");
|
|
1558
|
+
}
|
|
1559
|
+
showToast("Copied");
|
|
1560
|
+
} catch (err) {
|
|
1561
|
+
showToast(`Could not copy: ${err.message}`);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1713
1564
|
async function runAgent() {
|
|
1714
1565
|
if (!state.value?.agentRun?.enabled || state.value.agentRun.last?.status === "running") return;
|
|
1715
1566
|
const ok = window.confirm(
|
|
@@ -1738,53 +1589,6 @@ async function askAgent(run, text) {
|
|
|
1738
1589
|
showToast(`Could not ask the morning agent: ${err.message}`);
|
|
1739
1590
|
}
|
|
1740
1591
|
}
|
|
1741
|
-
async function changeSession(body) {
|
|
1742
|
-
if (body.action === "start" && "Notification" in window && Notification.permission === "default") {
|
|
1743
|
-
void Notification.requestPermission();
|
|
1744
|
-
}
|
|
1745
|
-
try {
|
|
1746
|
-
state.value = await postSession(body);
|
|
1747
|
-
startLocalTick();
|
|
1748
|
-
} catch (err) {
|
|
1749
|
-
showToast(`Could not change the timer: ${err.message}`);
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
var tickTimer = null;
|
|
1753
|
-
var announcedOverrunFor = null;
|
|
1754
|
-
function startLocalTick() {
|
|
1755
|
-
if (tickTimer) clearInterval(tickTimer);
|
|
1756
|
-
tickTimer = setInterval(tick, 1e3);
|
|
1757
|
-
tick();
|
|
1758
|
-
}
|
|
1759
|
-
function tick() {
|
|
1760
|
-
const active = state.value?.session.active;
|
|
1761
|
-
if (!active) {
|
|
1762
|
-
document.title = "Daily Focus";
|
|
1763
|
-
if (tickTimer) clearInterval(tickTimer);
|
|
1764
|
-
tickTimer = null;
|
|
1765
|
-
return;
|
|
1766
|
-
}
|
|
1767
|
-
const nowMs = Date.now();
|
|
1768
|
-
ui.clock.value = nowMs;
|
|
1769
|
-
const remaining = remainingSeconds(active, nowMs);
|
|
1770
|
-
const mm = Math.floor(Math.abs(remaining) / 60);
|
|
1771
|
-
const ss = String(Math.floor(Math.abs(remaining) % 60)).padStart(2, "0");
|
|
1772
|
-
document.title = `${remaining < 0 ? "+" : ""}${mm}:${ss} \xB7 ${active.title}`;
|
|
1773
|
-
if (remaining <= 0 && announcedOverrunFor !== active.startedAt) {
|
|
1774
|
-
announcedOverrunFor = active.startedAt;
|
|
1775
|
-
announceSessionEnd(active);
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
function announceSessionEnd(active) {
|
|
1779
|
-
const label = active.minutes === 1 ? "1 minute" : `${active.minutes} minutes`;
|
|
1780
|
-
showToast(`${label} in \u2014 still on "${active.title}"?`, null);
|
|
1781
|
-
if ("Notification" in window && Notification.permission === "granted") {
|
|
1782
|
-
new Notification("Still on this?", {
|
|
1783
|
-
body: `${label} in on ${active.title}. Keep going, or stop and log it.`,
|
|
1784
|
-
tag: "daily-focus-session"
|
|
1785
|
-
});
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
1592
|
function showView(view) {
|
|
1789
1593
|
if (ui.view.value === view) return;
|
|
1790
1594
|
if (state.value && !availableViews(state.value).includes(view)) return;
|
|
@@ -1833,10 +1637,6 @@ function setTicketMode(mode) {
|
|
|
1833
1637
|
closeMenus();
|
|
1834
1638
|
});
|
|
1835
1639
|
}
|
|
1836
|
-
function setFocusMode(on) {
|
|
1837
|
-
ui.focusMode.value = on;
|
|
1838
|
-
remember(FOCUS_MODE_KEY, on ? "1" : null);
|
|
1839
|
-
}
|
|
1840
1640
|
function restartToast(page) {
|
|
1841
1641
|
if (page.restart === "manual") showToast("Saved. Restart the dashboard to apply it.");
|
|
1842
1642
|
else if (page.restart === "waiting" && state.value?.agentRun?.last?.status === "running") {
|
|
@@ -2059,21 +1859,16 @@ var handlers = {
|
|
|
2059
1859
|
() => document.querySelector('#tickets .item[data-selected="true"]')?.scrollIntoView({ block: "center", behavior: "smooth" })
|
|
2060
1860
|
);
|
|
2061
1861
|
},
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
ui.unattendedSeen.value = endedAt;
|
|
2066
|
-
remember(UNATTENDED_SEEN_KEY, endedAt);
|
|
2067
|
-
},
|
|
2068
|
-
// A nudge on Slack is invisible to GitHub, so it's recorded as a note: the agent
|
|
2069
|
-
// reads it as free text, and the board's nudge timer starts over from it.
|
|
2070
|
-
nudge: (id) => void applyAction(id, "note", { text: "Nudged reviewers" }),
|
|
1862
|
+
// A nudge on Slack is invisible to GitHub, so it's recorded: the board's nudge
|
|
1863
|
+
// timer starts over from it, and the agent reads that the user asked.
|
|
1864
|
+
nudge: (id) => void applyAction(id, "nudge"),
|
|
2071
1865
|
unpark: (id) => void unpark(id),
|
|
2072
1866
|
refreshBoard: () => void refreshBoard(),
|
|
2073
1867
|
refreshTickets: () => void refreshTickets(),
|
|
2074
1868
|
refreshCalendar: () => void refreshCalendar(),
|
|
2075
1869
|
ask: (id, body) => void ask(id, body),
|
|
2076
1870
|
stopAssistant: (id) => void stopAssistant(id),
|
|
1871
|
+
copy: (text) => void copy(text),
|
|
2077
1872
|
runAgent: () => void runAgent(),
|
|
2078
1873
|
stopAgent: () => void stopAgent(),
|
|
2079
1874
|
askAgent: (run, text) => void askAgent(run, text),
|
|
@@ -2092,7 +1887,6 @@ var handlers = {
|
|
|
2092
1887
|
applyTheme(mode);
|
|
2093
1888
|
ui.theme.value = mode;
|
|
2094
1889
|
},
|
|
2095
|
-
setFocusMode,
|
|
2096
1890
|
openHelp: () => document.getElementById("help")?.showModal(),
|
|
2097
1891
|
hideToast,
|
|
2098
1892
|
openSettings,
|
|
@@ -2113,6 +1907,145 @@ var handlers = {
|
|
|
2113
1907
|
listCalendars: () => void listCalendars()
|
|
2114
1908
|
};
|
|
2115
1909
|
|
|
1910
|
+
// client/format.ts
|
|
1911
|
+
var DAY_FORMAT = {
|
|
1912
|
+
weekday: "long",
|
|
1913
|
+
day: "numeric",
|
|
1914
|
+
month: "long"
|
|
1915
|
+
};
|
|
1916
|
+
function formatters(timeZone) {
|
|
1917
|
+
return {
|
|
1918
|
+
time: new Intl.DateTimeFormat(void 0, { timeZone, hour: "2-digit", minute: "2-digit" }),
|
|
1919
|
+
day: new Intl.DateTimeFormat(void 0, { timeZone, ...DAY_FORMAT }),
|
|
1920
|
+
shortDay: new Intl.DateTimeFormat(void 0, { timeZone, day: "numeric", month: "short" }),
|
|
1921
|
+
shortDayYear: new Intl.DateTimeFormat(void 0, { timeZone, day: "numeric", month: "short", year: "numeric" }),
|
|
1922
|
+
weekday: new Intl.DateTimeFormat(void 0, { timeZone, weekday: "long" })
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
var clockFormats = formatters();
|
|
1926
|
+
var dateFormats = formatters("UTC");
|
|
1927
|
+
var DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
1928
|
+
function formatted(value, kind) {
|
|
1929
|
+
const bare = typeof value === "string" && DATE_ONLY.test(value);
|
|
1930
|
+
const d5 = bare ? /* @__PURE__ */ new Date(`${value}T00:00:00Z`) : parseDate(value);
|
|
1931
|
+
return d5 && !Number.isNaN(d5.getTime()) ? (bare ? dateFormats : clockFormats)[kind].format(d5) : "";
|
|
1932
|
+
}
|
|
1933
|
+
function parseDate(value) {
|
|
1934
|
+
if (typeof value !== "string" || value === "") return null;
|
|
1935
|
+
const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
1936
|
+
if (dateOnly) return new Date(+dateOnly[1], +dateOnly[2] - 1, +dateOnly[3]);
|
|
1937
|
+
const d5 = new Date(value);
|
|
1938
|
+
return Number.isNaN(d5.getTime()) ? null : d5;
|
|
1939
|
+
}
|
|
1940
|
+
function formatTime(value) {
|
|
1941
|
+
return formatted(value, "time");
|
|
1942
|
+
}
|
|
1943
|
+
function formatDay(value) {
|
|
1944
|
+
return formatted(value, "day");
|
|
1945
|
+
}
|
|
1946
|
+
function formatShortDay(value) {
|
|
1947
|
+
return formatted(value, "shortDay");
|
|
1948
|
+
}
|
|
1949
|
+
function formatWeekday(value) {
|
|
1950
|
+
return formatted(value, "weekday");
|
|
1951
|
+
}
|
|
1952
|
+
var dayKeyFmt = null;
|
|
1953
|
+
var calendarZone;
|
|
1954
|
+
function setCalendarZone(timeZone) {
|
|
1955
|
+
if (timeZone === calendarZone) return;
|
|
1956
|
+
calendarZone = timeZone;
|
|
1957
|
+
try {
|
|
1958
|
+
clockFormats = formatters(timeZone);
|
|
1959
|
+
dayKeyFmt = timeZone ? new Intl.DateTimeFormat("en-US", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }) : null;
|
|
1960
|
+
} catch {
|
|
1961
|
+
dayKeyFmt = null;
|
|
1962
|
+
clockFormats = formatters();
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
function dayKey(d5) {
|
|
1966
|
+
if (dayKeyFmt) {
|
|
1967
|
+
const parts = dayKeyFmt.formatToParts(d5);
|
|
1968
|
+
const part = (type) => parts.find((p5) => p5.type === type)?.value ?? "";
|
|
1969
|
+
return `${part("year")}-${part("month")}-${part("day")}`;
|
|
1970
|
+
}
|
|
1971
|
+
const m4 = String(d5.getMonth() + 1).padStart(2, "0");
|
|
1972
|
+
const day = String(d5.getDate()).padStart(2, "0");
|
|
1973
|
+
return `${d5.getFullYear()}-${m4}-${day}`;
|
|
1974
|
+
}
|
|
1975
|
+
function splitKey(key) {
|
|
1976
|
+
const [y5, m4, d5] = key.split("-").map(Number);
|
|
1977
|
+
return [y5, m4 - 1, d5];
|
|
1978
|
+
}
|
|
1979
|
+
function keyAt(ms) {
|
|
1980
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
1981
|
+
}
|
|
1982
|
+
function addDays(key, days) {
|
|
1983
|
+
const [y5, m4, d5] = splitKey(key);
|
|
1984
|
+
return keyAt(Date.UTC(y5, m4, d5 + days));
|
|
1985
|
+
}
|
|
1986
|
+
function addMonths(key, months) {
|
|
1987
|
+
const [y5, m4, d5] = splitKey(key);
|
|
1988
|
+
const lastDay = new Date(Date.UTC(y5, m4 + months + 1, 0)).getUTCDate();
|
|
1989
|
+
return keyAt(Date.UTC(y5, m4 + months, Math.min(d5, lastDay)));
|
|
1990
|
+
}
|
|
1991
|
+
function daysFromToday(value, now = /* @__PURE__ */ new Date()) {
|
|
1992
|
+
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
1993
|
+
const [y5, m4, d5] = splitKey(value);
|
|
1994
|
+
const [ty, tm, td] = splitKey(dayKey(now));
|
|
1995
|
+
return Math.round((Date.UTC(y5, m4, d5) - Date.UTC(ty, tm, td)) / 864e5);
|
|
1996
|
+
}
|
|
1997
|
+
const target = parseDate(value);
|
|
1998
|
+
if (!target) return null;
|
|
1999
|
+
const a4 = Date.UTC(...splitKey(dayKey(now)));
|
|
2000
|
+
const b4 = Date.UTC(...splitKey(dayKey(target)));
|
|
2001
|
+
return Math.round((b4 - a4) / 864e5);
|
|
2002
|
+
}
|
|
2003
|
+
function relativeDay(value, now = /* @__PURE__ */ new Date()) {
|
|
2004
|
+
const diff = daysFromToday(value, now);
|
|
2005
|
+
if (diff === null) return "";
|
|
2006
|
+
if (diff === 0) return "today";
|
|
2007
|
+
if (diff === 1) return "tomorrow";
|
|
2008
|
+
if (diff === -1) return "yesterday";
|
|
2009
|
+
if (diff > 1 && diff <= 7) return `in ${diff} days`;
|
|
2010
|
+
if (diff < -1 && diff >= -7) return `${Math.abs(diff)} days ago`;
|
|
2011
|
+
return formatShortDay(value);
|
|
2012
|
+
}
|
|
2013
|
+
function formatDuration(minutes) {
|
|
2014
|
+
const h5 = Math.floor(minutes / 60);
|
|
2015
|
+
const m4 = minutes % 60;
|
|
2016
|
+
if (h5 === 0) return `${m4} min`;
|
|
2017
|
+
if (m4 === 0) return `${h5} h`;
|
|
2018
|
+
return `${h5} h ${m4} min`;
|
|
2019
|
+
}
|
|
2020
|
+
function relativeTime(value, now = /* @__PURE__ */ new Date()) {
|
|
2021
|
+
const d5 = parseDate(value);
|
|
2022
|
+
if (!d5) return "";
|
|
2023
|
+
const seconds = Math.round((now.getTime() - d5.getTime()) / 1e3);
|
|
2024
|
+
if (seconds < 60) return "just now";
|
|
2025
|
+
const minutes = Math.round(seconds / 60);
|
|
2026
|
+
if (minutes < 60) return `${minutes} min ago`;
|
|
2027
|
+
const hours = Math.round(minutes / 60);
|
|
2028
|
+
if (hours < 48) return `${hours} h ago`;
|
|
2029
|
+
const days = Math.round(hours / 24);
|
|
2030
|
+
if (days <= 30) return `${days} days ago`;
|
|
2031
|
+
return dayKey(d5).slice(0, 4) === dayKey(now).slice(0, 4) ? formatShortDay(value) : formatted(value, "shortDayYear");
|
|
2032
|
+
}
|
|
2033
|
+
function durationBetween(start, end) {
|
|
2034
|
+
const from = parseDate(start);
|
|
2035
|
+
const to = parseDate(end);
|
|
2036
|
+
if (!from || !to || to < from) return "";
|
|
2037
|
+
const seconds = Math.round((to.getTime() - from.getTime()) / 1e3);
|
|
2038
|
+
return seconds < 60 ? `${seconds} s` : formatDuration(Math.round(seconds / 60));
|
|
2039
|
+
}
|
|
2040
|
+
function formatClock(seconds) {
|
|
2041
|
+
const whole = Math.max(0, Math.floor(seconds));
|
|
2042
|
+
return `${Math.floor(whole / 60)}:${String(whole % 60).padStart(2, "0")}`;
|
|
2043
|
+
}
|
|
2044
|
+
function firstLine(text) {
|
|
2045
|
+
const line = String(text).split("\n").find((l5) => l5.trim() !== "") ?? "";
|
|
2046
|
+
return line.replace(/^[#>*\-\s]+/, "").replace(/[*_`]/g, "").trim();
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2116
2049
|
// client/failure.ts
|
|
2117
2050
|
function failureNotice(failure, { fold, className, icon, lastGood, now, onRetry }, ui2, handlers2) {
|
|
2118
2051
|
return el(
|
|
@@ -2306,7 +2239,7 @@ function renderMarkdown(value) {
|
|
|
2306
2239
|
function anchor(href, label) {
|
|
2307
2240
|
return el("a", { href: /^https?:\/\//i.test(href) ? href : "#", target: "_blank", rel: "noopener noreferrer" }, label);
|
|
2308
2241
|
}
|
|
2309
|
-
function renderMarkdownBlocks(value) {
|
|
2242
|
+
function renderMarkdownBlocks(value, options = {}) {
|
|
2310
2243
|
const out = [];
|
|
2311
2244
|
const lines = String(value).replace(/\r\n/g, "\n").split("\n");
|
|
2312
2245
|
let i4 = 0;
|
|
@@ -2317,7 +2250,16 @@ function renderMarkdownBlocks(value) {
|
|
|
2317
2250
|
i4++;
|
|
2318
2251
|
while (i4 < lines.length && !/^\s*```/.test(lines[i4])) code.push(lines[i4++]);
|
|
2319
2252
|
i4++;
|
|
2320
|
-
|
|
2253
|
+
const text = code.join("\n");
|
|
2254
|
+
const { onCopy } = options;
|
|
2255
|
+
out.push(
|
|
2256
|
+
onCopy ? el(
|
|
2257
|
+
"div",
|
|
2258
|
+
{ class: "code-block" },
|
|
2259
|
+
el("pre", null, text),
|
|
2260
|
+
el("button", { type: "button", class: "code-block__copy", title: "Copy to the clipboard", onClick: () => onCopy(text) }, "Copy")
|
|
2261
|
+
) : el("pre", null, text)
|
|
2262
|
+
);
|
|
2321
2263
|
continue;
|
|
2322
2264
|
}
|
|
2323
2265
|
if (line.trim() === "") {
|
|
@@ -2327,7 +2269,7 @@ function renderMarkdownBlocks(value) {
|
|
|
2327
2269
|
if (/^\s*>/.test(line)) {
|
|
2328
2270
|
const quoted = [];
|
|
2329
2271
|
while (i4 < lines.length && /^\s*>/.test(lines[i4])) quoted.push(lines[i4++].replace(/^\s*>\s?/, ""));
|
|
2330
|
-
out.push(el("blockquote", null, renderMarkdownBlocks(quoted.join("\n"))));
|
|
2272
|
+
out.push(el("blockquote", null, renderMarkdownBlocks(quoted.join("\n"), options)));
|
|
2331
2273
|
continue;
|
|
2332
2274
|
}
|
|
2333
2275
|
if (/^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
|
|
@@ -2571,9 +2513,6 @@ function renderItem(item, state2, ui2, handlers2) {
|
|
|
2571
2513
|
function ItemRow({ item, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
2572
2514
|
const now = new Date(state2.now);
|
|
2573
2515
|
const selected = ui2.selectedId.value === item.id;
|
|
2574
|
-
const active = state2.session?.active ?? null;
|
|
2575
|
-
const running = active !== null && active.id === item.id;
|
|
2576
|
-
const overrun = running && remainingSeconds(active, ui2.clock.value) < 0;
|
|
2577
2516
|
const repo = githubRepo(item);
|
|
2578
2517
|
const title = item.url ? el(
|
|
2579
2518
|
"a",
|
|
@@ -2591,8 +2530,6 @@ function ItemRow({ item, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
2591
2530
|
"data-selected": String(selected),
|
|
2592
2531
|
"data-priority": String(item.priority !== void 0 && item.status === "open"),
|
|
2593
2532
|
"data-pending": String(ui2.pending.value.has(item.id)),
|
|
2594
|
-
"data-running": String(running),
|
|
2595
|
-
"data-overrun": String(overrun),
|
|
2596
2533
|
"data-detail": String(ui2.detailFor.value === item.id),
|
|
2597
2534
|
// A click on the card opens the panel on it: one way in, and the whole card is it.
|
|
2598
2535
|
onClick: (event) => {
|
|
@@ -2612,31 +2549,21 @@ function ItemRow({ item, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
2612
2549
|
"div",
|
|
2613
2550
|
{ class: "item__body" },
|
|
2614
2551
|
el("p", { class: "item__title" }, title),
|
|
2615
|
-
renderMeta(item, state2,
|
|
2616
|
-
item.detail ? el("p", { class: "item__detail" }, renderMarkdown(item.detail)) : null
|
|
2552
|
+
renderMeta(item, state2, now),
|
|
2553
|
+
item.detail ? el("p", { class: "item__detail" }, renderMarkdown(item.detail)) : null,
|
|
2554
|
+
renderAhead(item.id, state2)
|
|
2617
2555
|
),
|
|
2618
|
-
renderActions(item,
|
|
2556
|
+
renderActions(item, ui2, handlers2),
|
|
2619
2557
|
ui2.menuFor.value === item.id ? renderSnoozeMenu(item, now, handlers2) : null
|
|
2620
2558
|
);
|
|
2621
2559
|
}
|
|
2622
|
-
function renderMeta(item, state2,
|
|
2560
|
+
function renderMeta(item, state2, now) {
|
|
2623
2561
|
const pills = [];
|
|
2624
2562
|
const said = /* @__PURE__ */ new Set();
|
|
2625
2563
|
const pill = (cls, text) => {
|
|
2626
2564
|
pills.push(el("span", { class: cls }, text));
|
|
2627
2565
|
said.add(text.trim().toLowerCase());
|
|
2628
2566
|
};
|
|
2629
|
-
const active = state2.session?.active ?? null;
|
|
2630
|
-
if (active && active.id === item.id) {
|
|
2631
|
-
pills.push(
|
|
2632
|
-
el(
|
|
2633
|
-
"span",
|
|
2634
|
-
{ class: "pill pill--running" },
|
|
2635
|
-
el("span", { class: "item__running-clock" }, clock(remainingSeconds(active, ui2.clock.value))),
|
|
2636
|
-
" focusing"
|
|
2637
|
-
)
|
|
2638
|
-
);
|
|
2639
|
-
}
|
|
2640
2567
|
if (item.priority !== void 0 && item.status === "open") {
|
|
2641
2568
|
pill("pill pill--priority", `#${item.priority}`);
|
|
2642
2569
|
}
|
|
@@ -2688,24 +2615,43 @@ function rowPillTexts(row, state2) {
|
|
|
2688
2615
|
function rowPills(row, state2) {
|
|
2689
2616
|
return rowPillTexts(row, state2).map(([cls, text]) => el("span", { class: cls }, text));
|
|
2690
2617
|
}
|
|
2691
|
-
|
|
2618
|
+
var READING = {
|
|
2619
|
+
"assess-review": "Reading the review\u2026",
|
|
2620
|
+
"explain-ci": "Reading the failing checks\u2026"
|
|
2621
|
+
};
|
|
2622
|
+
function renderAhead(id, state2) {
|
|
2623
|
+
const auto = state2.assistant?.auto;
|
|
2624
|
+
const keys = auto?.rows?.[id];
|
|
2625
|
+
if (!auto || !keys?.length) return null;
|
|
2626
|
+
const turn = (state2.assistant.items?.[id]?.turns ?? []).findLast((candidate) => candidate.auto !== null && keys.includes(candidate.auto));
|
|
2627
|
+
const mark = el("span", { class: "item__ahead-mark", "aria-hidden": "true" }, "\u2726");
|
|
2628
|
+
if (!turn) {
|
|
2629
|
+
return auto.enabled && auto.usedToday >= auto.limit ? el("p", { class: "item__ahead item__ahead--quiet" }, mark, `Not answered ahead: today's ${auto.limit} are used.`) : null;
|
|
2630
|
+
}
|
|
2631
|
+
if (turn.status === "running") {
|
|
2632
|
+
return el("p", { class: "item__ahead item__ahead--quiet", "data-status": "running" }, mark, READING[turn.action ?? ""] ?? "Reading\u2026");
|
|
2633
|
+
}
|
|
2634
|
+
if (turn.status === "failed") {
|
|
2635
|
+
return el("p", { class: "item__ahead item__ahead--quiet" }, mark, "Could not answer ahead; the panel says why.");
|
|
2636
|
+
}
|
|
2637
|
+
const verdict = turn.status === "done" ? verdictLine(turn.reply) : "";
|
|
2638
|
+
if (!verdict) return null;
|
|
2639
|
+
return el(
|
|
2640
|
+
"p",
|
|
2641
|
+
{ class: "item__ahead", title: `Answered ahead ${relativeTime(turn.endedAt ?? turn.startedAt, new Date(state2.now))}. Open the panel for the whole answer.` },
|
|
2642
|
+
mark,
|
|
2643
|
+
renderMarkdown(verdict)
|
|
2644
|
+
);
|
|
2645
|
+
}
|
|
2646
|
+
function verdictLine(reply) {
|
|
2647
|
+
const line = reply.split("\n").find((candidate) => candidate.trim() !== "") ?? "";
|
|
2648
|
+
return line.replace(/^\s*(?:#{1,6}\s+|>\s*|[-*•]\s+|\d+[.)]\s+)/, "").trim();
|
|
2649
|
+
}
|
|
2650
|
+
function renderActions(item, ui2, handlers2) {
|
|
2692
2651
|
const buttons = [];
|
|
2693
2652
|
const act = (id, action) => () => handlers2.onAction(id, action);
|
|
2694
|
-
const running = state2.session?.active?.id === item.id;
|
|
2695
2653
|
if (item.status === "open") {
|
|
2696
2654
|
if (item.kind === "task") {
|
|
2697
|
-
buttons.push(
|
|
2698
|
-
el(
|
|
2699
|
-
"button",
|
|
2700
|
-
{
|
|
2701
|
-
type: "button",
|
|
2702
|
-
class: running ? "button button--primary" : "button",
|
|
2703
|
-
title: running ? "Stop the focus session" : "Start a focus session on this",
|
|
2704
|
-
onClick: () => running ? handlers2.stopSession() : handlers2.startSession(item.id)
|
|
2705
|
-
},
|
|
2706
|
-
running ? "Stop" : "Focus"
|
|
2707
|
-
)
|
|
2708
|
-
);
|
|
2709
2655
|
buttons.push(el("button", { type: "button", class: "button", onClick: act(item.id, "done") }, "Done"));
|
|
2710
2656
|
buttons.push(
|
|
2711
2657
|
el(
|
|
@@ -2905,8 +2851,10 @@ function renderBoard(state2, ui2, handlers2) {
|
|
|
2905
2851
|
const open = board.rows.filter((row) => row.status === "open");
|
|
2906
2852
|
for (const court of COURT_ORDER) {
|
|
2907
2853
|
const rows = open.filter((row) => row.court === court);
|
|
2908
|
-
|
|
2909
|
-
|
|
2854
|
+
const nudged = court === "reviewers" ? rows.filter((row) => row.nudgedAt) : [];
|
|
2855
|
+
const waiting = rows.filter((row) => !row.nudgedAt);
|
|
2856
|
+
if (waiting.length > 0) parts.push(section(COURT_TITLE[court], waiting, state2, ui2, handlers2, null, renderPullRow));
|
|
2857
|
+
if (nudged.length > 0) parts.push(section("Nudged", nudged, state2, ui2, handlers2, null, renderPullRow));
|
|
2910
2858
|
}
|
|
2911
2859
|
if (open.length === 0 && !board.reason) {
|
|
2912
2860
|
parts.push(
|
|
@@ -2963,6 +2911,7 @@ function PullRow({ item: row, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
2963
2911
|
"data-id": row.id,
|
|
2964
2912
|
"data-status": row.status,
|
|
2965
2913
|
"data-court": row.court,
|
|
2914
|
+
"data-nudged": String(Boolean(row.nudgedAt)),
|
|
2966
2915
|
"data-selected": String(selected),
|
|
2967
2916
|
"data-pending": String(ui2.pending.value.has(row.id)),
|
|
2968
2917
|
"data-detail": String(ui2.detailFor.value === row.id),
|
|
@@ -2991,7 +2940,8 @@ function PullRow({ item: row, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
2991
2940
|
),
|
|
2992
2941
|
renderPullMeta(row, state2, now),
|
|
2993
2942
|
renderPullReasons(row, now),
|
|
2994
|
-
renderCancelledChecks(row)
|
|
2943
|
+
renderCancelledChecks(row),
|
|
2944
|
+
renderAhead(row.id, state2)
|
|
2995
2945
|
),
|
|
2996
2946
|
renderPullActions(row, ui2, handlers2),
|
|
2997
2947
|
ui2.menuFor.value === row.id ? renderSnoozeMenu(row, now, handlers2, { indefinite: false }) : null
|
|
@@ -3010,6 +2960,9 @@ function renderPullMeta(row, state2, now) {
|
|
|
3010
2960
|
if (row.mergeable === "CONFLICTING") pill("pill pill--overdue", "conflicts");
|
|
3011
2961
|
if (row.autoMerge) pill("pill pill--good", "auto-merge on");
|
|
3012
2962
|
if (row.nudge) pill("pill pill--age", "time to ask");
|
|
2963
|
+
if (row.nudgedAt && row.nudgedUntil) {
|
|
2964
|
+
pill("pill", `nudged ${relativeTime(row.nudgedAt, now)}, back ${relativeDay(row.nudgedUntil, now)} ${formatTime(row.nudgedUntil)}`);
|
|
2965
|
+
}
|
|
3013
2966
|
if (row.court === "blocked") {
|
|
3014
2967
|
pill("pill", `blocked ${waitedFor(row.since, now)}`);
|
|
3015
2968
|
} else if (row.court === "gate" || row.court === "checks") {
|
|
@@ -3114,7 +3067,7 @@ function renderPullActions(row, ui2, handlers2) {
|
|
|
3114
3067
|
)
|
|
3115
3068
|
);
|
|
3116
3069
|
if (row.status === "open") {
|
|
3117
|
-
if (row.court === "reviewers") {
|
|
3070
|
+
if (row.court === "reviewers" && !row.nudgedAt) {
|
|
3118
3071
|
buttons.push(
|
|
3119
3072
|
el(
|
|
3120
3073
|
"button",
|
|
@@ -3151,7 +3104,7 @@ var TICKET_COURT_TITLE = {
|
|
|
3151
3104
|
};
|
|
3152
3105
|
var TICKET_COURT_ORDER = ["settled", "started", "idle"];
|
|
3153
3106
|
var TICKET_COURT_HINT = {
|
|
3154
|
-
settled: "Every pull request
|
|
3107
|
+
settled: "Every pull request linked to these is closed. Move them on, or say what is still to come \u2014 a pull request nobody has written yet is invisible from here.",
|
|
3155
3108
|
started: "A pull request is open, so the work has begun. The status still says it has not.",
|
|
3156
3109
|
idle: "Nothing in Jira links any code to these. Fine for work that is not code; worth a look otherwise."
|
|
3157
3110
|
};
|
|
@@ -3362,7 +3315,8 @@ function TicketRowView({ item: row, state: state2, ui: ui2, handlers: handlers2
|
|
|
3362
3315
|
{ class: "item__body" },
|
|
3363
3316
|
renderTicketStatus(row, state2, ui2, handlers2),
|
|
3364
3317
|
el("p", { class: "item__title" }, title),
|
|
3365
|
-
renderTicketMeta(row, state2, handlers2)
|
|
3318
|
+
renderTicketMeta(row, state2, handlers2),
|
|
3319
|
+
renderGitHubEvidence(row, now)
|
|
3366
3320
|
),
|
|
3367
3321
|
renderTicketActions(row, ui2, handlers2),
|
|
3368
3322
|
ui2.menuFor.value === row.id ? renderSnoozeMenu(row, now, handlers2, PARK_MENU) : null
|
|
@@ -3436,6 +3390,25 @@ function renderTicketMeta(row, state2, handlers2) {
|
|
|
3436
3390
|
pills.push(...rowPills(row, state2));
|
|
3437
3391
|
return pills.length > 0 ? el("div", { class: "item__meta item__meta--extra" }, pills) : null;
|
|
3438
3392
|
}
|
|
3393
|
+
var EVIDENCE_SHOWN = 3;
|
|
3394
|
+
function renderGitHubEvidence(row, now) {
|
|
3395
|
+
const pulls = row.pulls ?? [];
|
|
3396
|
+
if (!row.fromGitHub || pulls.length === 0) return null;
|
|
3397
|
+
const parts = ["GitHub, ahead of Jira: "];
|
|
3398
|
+
pulls.slice(0, EVIDENCE_SHOWN).forEach((pull, i4) => {
|
|
3399
|
+
if (i4 > 0) parts.push(" \xB7 ");
|
|
3400
|
+
parts.push(
|
|
3401
|
+
el("a", { href: pull.url, target: "_blank", rel: "noopener noreferrer", title: pull.title }, `${pull.repo}#${pull.number}`),
|
|
3402
|
+
` ${describePull(pull, now)}`
|
|
3403
|
+
);
|
|
3404
|
+
});
|
|
3405
|
+
if (pulls.length > EVIDENCE_SHOWN) parts.push(` \xB7 and ${pulls.length - EVIDENCE_SHOWN} more`);
|
|
3406
|
+
return el("p", { class: "item__reason item__reason--waiting" }, parts);
|
|
3407
|
+
}
|
|
3408
|
+
function describePull(pull, now) {
|
|
3409
|
+
if (pull.state === "open" || pull.state === "draft") return pull.state;
|
|
3410
|
+
return pull.closedAt ? `${pull.state} ${relativeTime(pull.closedAt, now)}` : pull.state;
|
|
3411
|
+
}
|
|
3439
3412
|
function outOfSyncFlag(row, state2, handlers2) {
|
|
3440
3413
|
const hit = state2.tickets?.rows?.find((candidate) => candidate.id === row.id && candidate.status === "open");
|
|
3441
3414
|
if (!hit) return null;
|
|
@@ -3746,8 +3719,6 @@ var SHORTCUTS = [
|
|
|
3746
3719
|
[["Esc"], "Close the menu, then the panel"],
|
|
3747
3720
|
[["o"], "Open the source link"],
|
|
3748
3721
|
[["u"], "Undo the last action"],
|
|
3749
|
-
[["f"], "Focus mode \u2014 hide all but the top item"],
|
|
3750
|
-
[["p"], "Start a focus session on the selected item"],
|
|
3751
3722
|
[["r"], "Refresh whichever board you are on"],
|
|
3752
3723
|
[["w"], "Jira tickets: switch between out of sync and working on"],
|
|
3753
3724
|
[[","], "Settings: your objective, where the agent looks, and the rest"],
|
|
@@ -3777,7 +3748,7 @@ function HelpDialog(_props) {
|
|
|
3777
3748
|
el(
|
|
3778
3749
|
"p",
|
|
3779
3750
|
{ class: "help__note" },
|
|
3780
|
-
`Done, snoozed and dismissed all tell the morning agent to leave an item out of tomorrow's brief. A note is sent along with it as free text. On both boards only snooze and note apply: a pull request stays until it's merged or closed, and a ticket whose status looks wrong is put right in Jira rather than here. Click a card to open its panel, where its notes and the assistant live; the panel stays on the item it was opened for. The assistant is a CLI run on your machine
|
|
3751
|
+
`Done, snoozed and dismissed all tell the morning agent to leave an item out of tomorrow's brief. A note is sent along with it as free text. On both boards only snooze and note apply: a pull request stays until it's merged or closed, and a ticket whose status looks wrong is put right in Jira rather than here. Click a card to open its panel, where its notes and the assistant live; the panel stays on the item it was opened for. The assistant is a CLI run on your machine, told to read and draft, never to send or post. Click "updated \u2026 ago" in the header to open the morning agent's latest run: its report, earlier runs, and a place to ask it why it did what it did.`
|
|
3781
3752
|
),
|
|
3782
3753
|
el("form", { method: "dialog" }, el("button", { type: "submit", class: "button" }, "Close"))
|
|
3783
3754
|
);
|
|
@@ -3941,11 +3912,7 @@ function runStatus(run, now, handlers2) {
|
|
|
3941
3912
|
);
|
|
3942
3913
|
}
|
|
3943
3914
|
function runDuration(run) {
|
|
3944
|
-
|
|
3945
|
-
const to = parseDate(run.endedAt);
|
|
3946
|
-
if (!from || !to || to < from) return "";
|
|
3947
|
-
const seconds = Math.round((to.getTime() - from.getTime()) / 1e3);
|
|
3948
|
-
return seconds < 60 ? `${seconds} s` : formatDuration(Math.round(seconds / 60));
|
|
3915
|
+
return durationBetween(run.startedAt, run.endedAt);
|
|
3949
3916
|
}
|
|
3950
3917
|
function runConversation(run, busy, answering, enabled, ui2, handlers2, inputRef) {
|
|
3951
3918
|
const turns = run.turns.length ? el(
|
|
@@ -4101,8 +4068,9 @@ function RowPanel({ row, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4101
4068
|
) : el("p", { class: "flyout__empty" }, "Nothing noted yet. A note goes to the morning agent as free text."),
|
|
4102
4069
|
k(NoteForm, { row, title: facts.title, ui: ui2, handlers: handlers2, inputRef: noteInput })
|
|
4103
4070
|
),
|
|
4104
|
-
|
|
4105
|
-
)
|
|
4071
|
+
entry.turns.length ? renderAssistantSection(state2, entry, enabled, handlers2) : null
|
|
4072
|
+
),
|
|
4073
|
+
enabled ? renderAssistantFooter(facts, state2, entry, ui2, handlers2, askInput, row) : null
|
|
4106
4074
|
];
|
|
4107
4075
|
}
|
|
4108
4076
|
function describeRow(row) {
|
|
@@ -4203,21 +4171,27 @@ function NoteForm({
|
|
|
4203
4171
|
el("button", { type: "submit", class: "button button--primary flyout__submit" }, "Save")
|
|
4204
4172
|
);
|
|
4205
4173
|
}
|
|
4206
|
-
function renderAssistantSection(
|
|
4207
|
-
const source = "source" in row ? row.source : "github";
|
|
4208
|
-
const actions = (state2.assistant?.quickActions ?? []).filter(
|
|
4209
|
-
(action) => action.sources === null || action.sources.includes(source)
|
|
4210
|
-
);
|
|
4174
|
+
function renderAssistantSection(state2, entry, enabled, handlers2) {
|
|
4211
4175
|
const label = new Map((state2.assistant?.quickActions ?? []).map((action) => [action.id, action]));
|
|
4212
4176
|
return el(
|
|
4213
4177
|
"section",
|
|
4214
4178
|
{ class: "flyout__section assistant", "data-running": String(entry.running) },
|
|
4215
4179
|
el("h3", { class: "flyout__label" }, "Assistant"),
|
|
4216
|
-
|
|
4180
|
+
el(
|
|
4217
4181
|
"div",
|
|
4218
4182
|
{ class: "assistant__turns" },
|
|
4219
|
-
entry.turns.map((turn) => renderAssistantTurn(turn, label))
|
|
4220
|
-
)
|
|
4183
|
+
entry.turns.map((turn) => renderAssistantTurn(turn, label, handlers2))
|
|
4184
|
+
),
|
|
4185
|
+
enabled ? null : el("p", { class: "flyout__empty" }, "The assistant is switched off (DAILY_FOCUS_ASSISTANT), so nothing more can be asked here.")
|
|
4186
|
+
);
|
|
4187
|
+
}
|
|
4188
|
+
function renderAssistantFooter(facts, state2, entry, ui2, handlers2, inputRef, row) {
|
|
4189
|
+
const actions = (state2.assistant?.quickActions ?? []).filter(
|
|
4190
|
+
(action) => action.sources === null || action.sources.includes(facts.source)
|
|
4191
|
+
);
|
|
4192
|
+
return el(
|
|
4193
|
+
"div",
|
|
4194
|
+
{ class: "flyout__footer" },
|
|
4221
4195
|
entry.running ? null : el(
|
|
4222
4196
|
"div",
|
|
4223
4197
|
{ class: "assistant__quick" },
|
|
@@ -4237,20 +4211,6 @@ function renderAssistantSection(row, facts, state2, entry, ui2, handlers2, input
|
|
|
4237
4211
|
k(AssistantComposer, { row, title: facts.title, entry, ui: ui2, handlers: handlers2, inputRef })
|
|
4238
4212
|
);
|
|
4239
4213
|
}
|
|
4240
|
-
function renderAssistantHistory(state2, entry) {
|
|
4241
|
-
const label = new Map((state2.assistant?.quickActions ?? []).map((action) => [action.id, action]));
|
|
4242
|
-
return el(
|
|
4243
|
-
"section",
|
|
4244
|
-
{ class: "flyout__section assistant", "data-running": "false" },
|
|
4245
|
-
el("h3", { class: "flyout__label" }, "Assistant"),
|
|
4246
|
-
el(
|
|
4247
|
-
"div",
|
|
4248
|
-
{ class: "assistant__turns" },
|
|
4249
|
-
entry.turns.map((turn) => renderAssistantTurn(turn, label))
|
|
4250
|
-
),
|
|
4251
|
-
el("p", { class: "flyout__empty" }, "The assistant is switched off (DAILY_FOCUS_ASSISTANT), so nothing more can be asked here.")
|
|
4252
|
-
);
|
|
4253
|
-
}
|
|
4254
4214
|
function AssistantComposer({
|
|
4255
4215
|
row,
|
|
4256
4216
|
title,
|
|
@@ -4279,7 +4239,7 @@ function AssistantComposer({
|
|
|
4279
4239
|
rows: 2,
|
|
4280
4240
|
ref: inputRef,
|
|
4281
4241
|
value: ui2.assistantDraft.value,
|
|
4282
|
-
placeholder: entry.turns.length ? "Follow up\u2026" : "
|
|
4242
|
+
placeholder: entry.turns.length ? "Follow up\u2026" : "Ask the assistant about this\u2026",
|
|
4283
4243
|
"aria-label": `Ask the assistant about ${title}`,
|
|
4284
4244
|
disabled: entry.running,
|
|
4285
4245
|
onInput: (event) => {
|
|
@@ -4295,19 +4255,84 @@ function AssistantComposer({
|
|
|
4295
4255
|
entry.running ? el("button", { type: "button", class: "button flyout__submit", onClick: () => handlers2.stopAssistant(row.id) }, "Stop") : el("button", { type: "submit", class: "button button--primary flyout__submit" }, "Send")
|
|
4296
4256
|
);
|
|
4297
4257
|
}
|
|
4298
|
-
function renderAssistantTurn(turn, label) {
|
|
4258
|
+
function renderAssistantTurn(turn, label, handlers2) {
|
|
4299
4259
|
const action = turn.action ? label.get(turn.action) : null;
|
|
4300
4260
|
const extra = action && turn.request.startsWith(action.request) ? turn.request.slice(action.request.length).trim() : null;
|
|
4301
4261
|
const asked = action ? [el("strong", null, action.label), extra ? ` \u2014 ${extra}` : ""] : [turn.request];
|
|
4302
|
-
|
|
4262
|
+
if (turn.auto) asked.push(el("span", { class: "assistant__auto", title: "The dashboard asked this on its own, when the pull request started waiting on you." }, " \xB7 asked ahead"));
|
|
4263
|
+
const { body, created } = turn.status === "done" ? splitCreated(turn.reply) : { body: turn.reply, created: [] };
|
|
4264
|
+
const status = turn.status === "failed" ? el("p", { class: "assistant__status assistant__status--bad" }, `Failed: ${turn.error}`) : turn.status === "aborted" ? el("p", { class: "assistant__status" }, `Stopped: ${turn.error}`) : null;
|
|
4303
4265
|
return el(
|
|
4304
4266
|
"div",
|
|
4305
|
-
{ class: "assistant__turn", "data-status": turn.status },
|
|
4267
|
+
{ key: turn.id, class: "assistant__turn", "data-status": turn.status },
|
|
4306
4268
|
el("p", { class: "assistant__request" }, asked),
|
|
4307
|
-
|
|
4308
|
-
|
|
4269
|
+
renderWork(turn),
|
|
4270
|
+
body ? el("div", { class: "assistant__reply" }, renderMarkdownBlocks(body, { onCopy: (text) => handlers2.copy(text) })) : null,
|
|
4271
|
+
status,
|
|
4272
|
+
turn.status === "done" && (body || created.length) ? el(
|
|
4273
|
+
"div",
|
|
4274
|
+
{ class: "assistant__after" },
|
|
4275
|
+
created.map(
|
|
4276
|
+
(link) => el("a", { class: "button", href: link.url, target: "_blank", rel: "noopener noreferrer", title: link.url }, `${link.label} \u2197`)
|
|
4277
|
+
),
|
|
4278
|
+
body ? el("button", { type: "button", class: "button", onClick: () => handlers2.copy(body) }, "Copy reply") : null
|
|
4279
|
+
) : null
|
|
4280
|
+
);
|
|
4281
|
+
}
|
|
4282
|
+
function renderWork(turn) {
|
|
4283
|
+
const steps = turn.steps ?? [];
|
|
4284
|
+
if (turn.status === "running") {
|
|
4285
|
+
return el(
|
|
4286
|
+
"div",
|
|
4287
|
+
{ class: "assistant__work" },
|
|
4288
|
+
el("p", { class: "assistant__status assistant__status--working" }, "Working \xB7 ", k(Elapsed, { since: turn.startedAt })),
|
|
4289
|
+
steps.length ? renderSteps(steps) : null
|
|
4290
|
+
);
|
|
4291
|
+
}
|
|
4292
|
+
const took = durationBetween(turn.startedAt, turn.endedAt);
|
|
4293
|
+
if (!steps.length) return took ? el("p", { class: "assistant__took" }, `Answered in ${took}`) : null;
|
|
4294
|
+
const failed = steps.filter((step2) => step2.state === "failed").length;
|
|
4295
|
+
const summary = [
|
|
4296
|
+
took ? `${turn.status === "done" ? "Worked" : "Ran"} for ${took}` : null,
|
|
4297
|
+
`${steps.length} ${steps.length === 1 ? "step" : "steps"}`,
|
|
4298
|
+
failed ? `${failed} failed` : null
|
|
4299
|
+
].filter(Boolean).join(" \xB7 ");
|
|
4300
|
+
return el("details", { class: "assistant__work", open: turn.status === "failed" }, el("summary", null, summary), renderSteps(steps));
|
|
4301
|
+
}
|
|
4302
|
+
function renderSteps(steps) {
|
|
4303
|
+
return el(
|
|
4304
|
+
"ol",
|
|
4305
|
+
{ class: "assistant__steps" },
|
|
4306
|
+
steps.map(
|
|
4307
|
+
(step2, index) => step2.kind === "message" ? el("li", { key: index, class: "assistant__step assistant__step--message" }, renderMarkdown(step2.text.trim())) : el(
|
|
4308
|
+
"li",
|
|
4309
|
+
{ key: index, class: "assistant__step", "data-state": step2.state },
|
|
4310
|
+
el("span", { class: "assistant__step-text" }, step2.text),
|
|
4311
|
+
step2.detail ? el("code", { class: "assistant__step-detail", title: step2.detail }, step2.detail) : null
|
|
4312
|
+
)
|
|
4313
|
+
)
|
|
4309
4314
|
);
|
|
4310
4315
|
}
|
|
4316
|
+
function Elapsed({ since }) {
|
|
4317
|
+
const [now, setNow] = d2(() => Date.now());
|
|
4318
|
+
h2(() => {
|
|
4319
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
4320
|
+
return () => clearInterval(timer);
|
|
4321
|
+
}, []);
|
|
4322
|
+
const start = parseDate(since)?.getTime() ?? now;
|
|
4323
|
+
return el("span", { class: "assistant__clock" }, formatClock((now - start) / 1e3));
|
|
4324
|
+
}
|
|
4325
|
+
var CREATED = /^\s*(?:[-*]\s+)?Created:\s*\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)\s*\.?\s*$/i;
|
|
4326
|
+
function splitCreated(reply) {
|
|
4327
|
+
const created = [];
|
|
4328
|
+
const kept = [];
|
|
4329
|
+
for (const line of reply.split("\n")) {
|
|
4330
|
+
const match = CREATED.exec(line);
|
|
4331
|
+
if (match) created.push({ label: match[1].trim(), url: match[2] });
|
|
4332
|
+
else kept.push(line);
|
|
4333
|
+
}
|
|
4334
|
+
return { body: created.length ? kept.join("\n").trim() : reply, created };
|
|
4335
|
+
}
|
|
4311
4336
|
|
|
4312
4337
|
// client/settings.ts
|
|
4313
4338
|
var VIEW_NAME = {
|
|
@@ -4843,14 +4868,8 @@ function boardRow(name, health, text, action) {
|
|
|
4843
4868
|
|
|
4844
4869
|
// client/today.ts
|
|
4845
4870
|
function TodayView({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
{ class: "focus-bar", id: "focus-bar", hidden: !ui2.focusMode.value },
|
|
4849
|
-
"Focus mode \u2014 everything but the top item is hidden. ",
|
|
4850
|
-
el("button", { type: "button", class: "button", id: "focus-exit", onClick: () => handlers2.setFocusMode(false) }, "Show everything")
|
|
4851
|
-
);
|
|
4852
|
-
if (state2.setup?.needed) return [focusBar, k(SetupCard, { state: state2, ui: ui2, handlers: handlers2 })];
|
|
4853
|
-
return [focusBar, renderObjective(state2, handlers2), renderStats(state2), renderHeadline(state2), renderSections(state2, ui2, handlers2)];
|
|
4871
|
+
if (state2.setup?.needed) return [k(SetupCard, { state: state2, ui: ui2, handlers: handlers2 })];
|
|
4872
|
+
return [renderObjective(state2, handlers2), renderStats(state2), renderHeadline(state2), renderSections(state2, ui2, handlers2)];
|
|
4854
4873
|
}
|
|
4855
4874
|
function renderObjective(state2, handlers2 = null) {
|
|
4856
4875
|
const focus = state2.focus;
|
|
@@ -4973,7 +4992,6 @@ function App({ ui: ui2, handlers: handlers2 }) {
|
|
|
4973
4992
|
el("a", { class: "skip-link", href: "#main" }, "Skip to content"),
|
|
4974
4993
|
k(Header, { state: current, ui: ui2, handlers: handlers2 }),
|
|
4975
4994
|
k(Tabs, { state: current, ui: ui2, handlers: handlers2 }),
|
|
4976
|
-
current ? k(Timer, { state: current, ui: ui2, handlers: handlers2 }) : el("div", { class: "timer", id: "timer", hidden: true }),
|
|
4977
4995
|
el("div", { id: "banners", class: "banners" }, current ? renderBanners(current, ui2, handlers2) : null),
|
|
4978
4996
|
el(
|
|
4979
4997
|
"main",
|
|
@@ -5091,11 +5109,6 @@ function installKeyboard(handlers2) {
|
|
|
5091
5109
|
event.preventDefault();
|
|
5092
5110
|
moveSelection(-1);
|
|
5093
5111
|
return;
|
|
5094
|
-
case "f":
|
|
5095
|
-
if (ui.view.value !== "today") return;
|
|
5096
|
-
event.preventDefault();
|
|
5097
|
-
handlers2.setFocusMode(!ui.focusMode.value);
|
|
5098
|
-
return;
|
|
5099
5112
|
case "1":
|
|
5100
5113
|
event.preventDefault();
|
|
5101
5114
|
handlers2.setView("today");
|
|
@@ -5140,7 +5153,6 @@ function installKeyboard(handlers2) {
|
|
|
5140
5153
|
if (!item) return;
|
|
5141
5154
|
const boardRow2 = ui.view.value !== "today";
|
|
5142
5155
|
const status = "status" in item ? item.status : null;
|
|
5143
|
-
const kind = "kind" in item ? item.kind : null;
|
|
5144
5156
|
switch (event.key) {
|
|
5145
5157
|
case "e":
|
|
5146
5158
|
event.preventDefault();
|
|
@@ -5163,12 +5175,6 @@ function installKeyboard(handlers2) {
|
|
|
5163
5175
|
event.preventDefault();
|
|
5164
5176
|
handlers2.openDetail(item.id, "assistant");
|
|
5165
5177
|
break;
|
|
5166
|
-
case "p":
|
|
5167
|
-
event.preventDefault();
|
|
5168
|
-
if (boardRow2) break;
|
|
5169
|
-
if (state.value?.session.active?.id === item.id) handlers2.stopSession();
|
|
5170
|
-
else if (status === "open" && kind === "task") handlers2.startSession(item.id);
|
|
5171
|
-
break;
|
|
5172
5178
|
case "o":
|
|
5173
5179
|
if (item.url) {
|
|
5174
5180
|
event.preventDefault();
|
|
@@ -5188,15 +5194,9 @@ R(k(App, { ui, handlers }), root);
|
|
|
5188
5194
|
j3(() => {
|
|
5189
5195
|
document.body.dataset.view = ui.view.value;
|
|
5190
5196
|
});
|
|
5191
|
-
j3(() => {
|
|
5192
|
-
document.body.dataset.focusMode = String(ui.focusMode.value);
|
|
5193
|
-
});
|
|
5194
5197
|
j3(() => {
|
|
5195
5198
|
document.body.dataset.offline = String(ui.connectionError.value !== null);
|
|
5196
5199
|
});
|
|
5197
|
-
j3(() => {
|
|
5198
|
-
document.body.dataset.sessionActive = String(state.value?.session.active != null);
|
|
5199
|
-
});
|
|
5200
5200
|
j3(() => {
|
|
5201
5201
|
const current = state.value;
|
|
5202
5202
|
const open = current !== null && (detailRun(current, ui) !== null || detailRow(current, ui) !== null);
|
|
@@ -5223,7 +5223,6 @@ j3(() => {
|
|
|
5223
5223
|
});
|
|
5224
5224
|
installKeyboard(handlers);
|
|
5225
5225
|
await refresh();
|
|
5226
|
-
startLocalTick();
|
|
5227
5226
|
var zone = watchZone({
|
|
5228
5227
|
browserZone,
|
|
5229
5228
|
dashboardZone: () => state.value?.timeZone,
|