epiq 1.3.5 → 1.4.0
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/dist/gui/main.js +2572 -538
- package/dist/index.js +55 -53
- package/dist/mcp.js +46 -46
- package/package.json +5 -2
package/dist/gui/main.js
CHANGED
|
@@ -4749,8 +4749,8 @@ var require_react_dom_client_development = __commonJS({
|
|
|
4749
4749
|
var lane = concurrentQueues[i];
|
|
4750
4750
|
concurrentQueues[i++] = null;
|
|
4751
4751
|
if (null !== queue && null !== update) {
|
|
4752
|
-
var
|
|
4753
|
-
null ===
|
|
4752
|
+
var pending2 = queue.pending;
|
|
4753
|
+
null === pending2 ? update.next = update : (update.next = pending2.next, pending2.next = update);
|
|
4754
4754
|
queue.pending = update;
|
|
4755
4755
|
}
|
|
4756
4756
|
0 !== lane && markUpdateLaneFromFiberToRoot(fiber, update, lane);
|
|
@@ -8127,8 +8127,8 @@ var require_react_dom_client_development = __commonJS({
|
|
|
8127
8127
|
}
|
|
8128
8128
|
function enqueueRenderPhaseUpdate(queue, update) {
|
|
8129
8129
|
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
|
|
8130
|
-
var
|
|
8131
|
-
null ===
|
|
8130
|
+
var pending2 = queue.pending;
|
|
8131
|
+
null === pending2 ? update.next = update : (update.next = pending2.next, pending2.next = update);
|
|
8132
8132
|
queue.pending = update;
|
|
8133
8133
|
}
|
|
8134
8134
|
function entangleTransitionUpdate(root5, queue, lane) {
|
|
@@ -8245,14 +8245,14 @@ var require_react_dom_client_development = __commonJS({
|
|
|
8245
8245
|
1,
|
|
8246
8246
|
badgeFormat + " " + error[0],
|
|
8247
8247
|
badgeStyle,
|
|
8248
|
-
|
|
8248
|
+
pad2 + JSCompiler_inline_result + pad2,
|
|
8249
8249
|
resetStyle
|
|
8250
8250
|
) : error.splice(
|
|
8251
8251
|
0,
|
|
8252
8252
|
0,
|
|
8253
8253
|
badgeFormat,
|
|
8254
8254
|
badgeStyle,
|
|
8255
|
-
|
|
8255
|
+
pad2 + JSCompiler_inline_result + pad2,
|
|
8256
8256
|
resetStyle
|
|
8257
8257
|
);
|
|
8258
8258
|
error.unshift(console);
|
|
@@ -21216,7 +21216,7 @@ var require_react_dom_client_development = __commonJS({
|
|
|
21216
21216
|
_currentValue: NotPendingTransition,
|
|
21217
21217
|
_currentValue2: NotPendingTransition,
|
|
21218
21218
|
_threadCount: 0
|
|
21219
|
-
}, badgeFormat = "%c%s%c", badgeStyle = "background: #e6e6e6;background: light-dark(rgba(0,0,0,0.1), rgba(255,255,255,0.25));color: #000000;color: light-dark(#000000, #ffffff);border-radius: 2px", resetStyle = "",
|
|
21219
|
+
}, badgeFormat = "%c%s%c", badgeStyle = "background: #e6e6e6;background: light-dark(rgba(0,0,0,0.1), rgba(255,255,255,0.25));color: #000000;color: light-dark(#000000, #ffffff);border-radius: 2px", resetStyle = "", pad2 = " ", bind = Function.prototype.bind;
|
|
21220
21220
|
var didWarnAboutNestedUpdates = false;
|
|
21221
21221
|
var overrideHookState = null, overrideHookStateDeletePath = null, overrideHookStateRenamePath = null, overrideProps = null, overridePropsDeletePath = null, overridePropsRenamePath = null, scheduleUpdate = null, scheduleRetry = null, setErrorHandler = null, setSuspenseHandler = null;
|
|
21222
21222
|
overrideHookState = function(fiber, id, path2, value) {
|
|
@@ -24825,7 +24825,7 @@ function useViewTransitionState(to, { relative } = {}) {
|
|
|
24825
24825
|
}
|
|
24826
24826
|
|
|
24827
24827
|
// source/gui/client/App.tsx
|
|
24828
|
-
var
|
|
24828
|
+
var import_react15 = __toESM(require_react(), 1);
|
|
24829
24829
|
|
|
24830
24830
|
// source/gui/client/components/Aside.tsx
|
|
24831
24831
|
var import_react = __toESM(require_react(), 1);
|
|
@@ -24841,20 +24841,12 @@ var GUI_THEME = {
|
|
|
24841
24841
|
primary: "#c2c5d0",
|
|
24842
24842
|
secondary: "#7f8aa3",
|
|
24843
24843
|
tertiary: "rgb(31 33 43)",
|
|
24844
|
-
dim: "#
|
|
24845
|
-
dim2: "rgb(
|
|
24844
|
+
dim: "#585d78",
|
|
24845
|
+
dim2: "rgb(100 107 133)",
|
|
24846
24846
|
accent: "#76d4ff",
|
|
24847
24847
|
green: "#8ce99a",
|
|
24848
24848
|
red: "#ff8787"
|
|
24849
24849
|
};
|
|
24850
|
-
var getContrastTextColor = (backgroundColor) => {
|
|
24851
|
-
const hex = backgroundColor.replace("#", "");
|
|
24852
|
-
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
24853
|
-
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
24854
|
-
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
24855
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
24856
|
-
return luminance > 0.6 ? "#111111" : "#ffffff";
|
|
24857
|
-
};
|
|
24858
24850
|
|
|
24859
24851
|
// source/gui/client/components/Aside.tsx
|
|
24860
24852
|
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
@@ -25046,7 +25038,8 @@ var Dropdown = ({
|
|
|
25046
25038
|
value,
|
|
25047
25039
|
items,
|
|
25048
25040
|
placeholder = "Select...",
|
|
25049
|
-
onSelect
|
|
25041
|
+
onSelect,
|
|
25042
|
+
testId
|
|
25050
25043
|
}) => {
|
|
25051
25044
|
const [open, setOpen] = (0, import_react3.useState)(false);
|
|
25052
25045
|
const ref = (0, import_react3.useRef)(null);
|
|
@@ -25076,6 +25069,7 @@ var Dropdown = ({
|
|
|
25076
25069
|
Button,
|
|
25077
25070
|
{
|
|
25078
25071
|
variant: "ghost",
|
|
25072
|
+
"data-testid": testId,
|
|
25079
25073
|
onClick: () => setOpen((value2) => !value2),
|
|
25080
25074
|
style: {
|
|
25081
25075
|
display: "flex",
|
|
@@ -25122,6 +25116,7 @@ var Dropdown = ({
|
|
|
25122
25116
|
"button",
|
|
25123
25117
|
{
|
|
25124
25118
|
type: "button",
|
|
25119
|
+
"data-testid": testId ? `${testId}-option` : void 0,
|
|
25125
25120
|
onClick: () => {
|
|
25126
25121
|
setOpen(false);
|
|
25127
25122
|
onSelect(item.id);
|
|
@@ -25159,6 +25154,7 @@ var Dropdown = ({
|
|
|
25159
25154
|
// source/gui/client/components/Panel.tsx
|
|
25160
25155
|
var import_react4 = __toESM(require_react(), 1);
|
|
25161
25156
|
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
|
|
25157
|
+
var POINTER_SAMPLE_MS = 16;
|
|
25162
25158
|
var Panel = ({
|
|
25163
25159
|
as,
|
|
25164
25160
|
children,
|
|
@@ -25166,6 +25162,8 @@ var Panel = ({
|
|
|
25166
25162
|
borderColor = GUI_THEME.line,
|
|
25167
25163
|
glowColor = GUI_THEME.secondary,
|
|
25168
25164
|
glowOpacity = 0.25,
|
|
25165
|
+
glowRadius = 200,
|
|
25166
|
+
proximityReach,
|
|
25169
25167
|
borderRadius = 12,
|
|
25170
25168
|
style,
|
|
25171
25169
|
...props
|
|
@@ -25173,6 +25171,38 @@ var Panel = ({
|
|
|
25173
25171
|
const Component4 = as ?? "div";
|
|
25174
25172
|
const [mouse, setMouse] = (0, import_react4.useState)({ x: 0, y: 0 });
|
|
25175
25173
|
const [hovered, setHovered] = (0, import_react4.useState)(false);
|
|
25174
|
+
const [proximity, setProximity] = (0, import_react4.useState)(0);
|
|
25175
|
+
const glowRef = (0, import_react4.useRef)(null);
|
|
25176
|
+
const lastMeasuredRef = (0, import_react4.useRef)(0);
|
|
25177
|
+
(0, import_react4.useEffect)(() => {
|
|
25178
|
+
if (proximityReach === void 0) return;
|
|
25179
|
+
const onMove = (event) => {
|
|
25180
|
+
const now = Date.now();
|
|
25181
|
+
if (now - lastMeasuredRef.current < POINTER_SAMPLE_MS) return;
|
|
25182
|
+
lastMeasuredRef.current = now;
|
|
25183
|
+
const panel = glowRef.current?.parentElement;
|
|
25184
|
+
if (!panel) return;
|
|
25185
|
+
const rect = panel.getBoundingClientRect();
|
|
25186
|
+
const dx = Math.max(
|
|
25187
|
+
rect.left - event.clientX,
|
|
25188
|
+
0,
|
|
25189
|
+
event.clientX - rect.right
|
|
25190
|
+
);
|
|
25191
|
+
const dy = Math.max(
|
|
25192
|
+
rect.top - event.clientY,
|
|
25193
|
+
0,
|
|
25194
|
+
event.clientY - rect.bottom
|
|
25195
|
+
);
|
|
25196
|
+
const distance = Math.hypot(dx, dy);
|
|
25197
|
+
setProximity(
|
|
25198
|
+
distance >= proximityReach ? 0 : 1 - distance / proximityReach
|
|
25199
|
+
);
|
|
25200
|
+
setMouse({ x: event.clientX - rect.left, y: event.clientY - rect.top });
|
|
25201
|
+
};
|
|
25202
|
+
window.addEventListener("mousemove", onMove);
|
|
25203
|
+
return () => window.removeEventListener("mousemove", onMove);
|
|
25204
|
+
}, [proximityReach]);
|
|
25205
|
+
const glowStrength = active ? 1 : proximityReach !== void 0 ? proximity : hovered ? 1 : 0;
|
|
25176
25206
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
25177
25207
|
Component4,
|
|
25178
25208
|
{
|
|
@@ -25204,15 +25234,16 @@ var Panel = ({
|
|
|
25204
25234
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
25205
25235
|
"div",
|
|
25206
25236
|
{
|
|
25237
|
+
ref: glowRef,
|
|
25207
25238
|
style: {
|
|
25208
25239
|
position: "absolute",
|
|
25209
25240
|
inset: 0,
|
|
25210
25241
|
borderRadius,
|
|
25211
25242
|
padding: 1,
|
|
25212
25243
|
pointerEvents: "none",
|
|
25213
|
-
opacity:
|
|
25244
|
+
opacity: glowStrength * glowOpacity,
|
|
25214
25245
|
background: `radial-gradient(
|
|
25215
|
-
|
|
25246
|
+
${glowRadius}px circle at ${mouse.x}px ${mouse.y}px,
|
|
25216
25247
|
${glowColor},
|
|
25217
25248
|
transparent 100%
|
|
25218
25249
|
)`,
|
|
@@ -25260,12 +25291,13 @@ var User = ({
|
|
|
25260
25291
|
display: "flex",
|
|
25261
25292
|
alignItems: "center",
|
|
25262
25293
|
justifyContent: "center",
|
|
25263
|
-
background:
|
|
25264
|
-
color:
|
|
25294
|
+
background: "transparent",
|
|
25295
|
+
color: user.color,
|
|
25296
|
+
border: `1px solid ${user.color}`,
|
|
25265
25297
|
fontSize: 11,
|
|
25266
25298
|
fontWeight: 700,
|
|
25267
|
-
marginLeft: index2 === 0 ? 0 :
|
|
25268
|
-
|
|
25299
|
+
marginLeft: index2 === 0 ? 0 : 4,
|
|
25300
|
+
flexShrink: 0
|
|
25269
25301
|
},
|
|
25270
25302
|
children: user.name.at(0)?.toUpperCase()
|
|
25271
25303
|
},
|
|
@@ -25273,7 +25305,7 @@ var User = ({
|
|
|
25273
25305
|
);
|
|
25274
25306
|
|
|
25275
25307
|
// source/version.ts
|
|
25276
|
-
var EPIQ_VERSION = "1.
|
|
25308
|
+
var EPIQ_VERSION = "1.4.0";
|
|
25277
25309
|
|
|
25278
25310
|
// source/gui/client/components/Header.tsx
|
|
25279
25311
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
@@ -25410,11 +25442,202 @@ var Header = ({ state, connected, syncStatus }) => {
|
|
|
25410
25442
|
};
|
|
25411
25443
|
|
|
25412
25444
|
// source/gui/client/components/IssueDetails.tsx
|
|
25413
|
-
var
|
|
25445
|
+
var import_react10 = __toESM(require_react(), 1);
|
|
25414
25446
|
|
|
25415
|
-
// source/gui/client/components/
|
|
25447
|
+
// source/gui/client/components/ManageContributorsModal.tsx
|
|
25416
25448
|
var import_react5 = __toESM(require_react(), 1);
|
|
25449
|
+
|
|
25450
|
+
// source/gui/client/components/IconLock.tsx
|
|
25417
25451
|
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
25452
|
+
var IconLock = ({ size = 13 }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
25453
|
+
"svg",
|
|
25454
|
+
{
|
|
25455
|
+
width: size,
|
|
25456
|
+
height: size,
|
|
25457
|
+
viewBox: "0 0 24 24",
|
|
25458
|
+
fill: "none",
|
|
25459
|
+
stroke: "currentColor",
|
|
25460
|
+
strokeWidth: "2",
|
|
25461
|
+
strokeLinecap: "round",
|
|
25462
|
+
strokeLinejoin: "round",
|
|
25463
|
+
"aria-hidden": "true",
|
|
25464
|
+
children: [
|
|
25465
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
|
|
25466
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" }),
|
|
25467
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "16.5", r: "2.1", fill: "currentColor", stroke: "none" })
|
|
25468
|
+
]
|
|
25469
|
+
}
|
|
25470
|
+
);
|
|
25471
|
+
|
|
25472
|
+
// source/gui/client/components/IconTrash.tsx
|
|
25473
|
+
var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
|
|
25474
|
+
var IconTrash = ({ size = 14 }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
25475
|
+
"svg",
|
|
25476
|
+
{
|
|
25477
|
+
width: size,
|
|
25478
|
+
height: size,
|
|
25479
|
+
viewBox: "0 0 24 24",
|
|
25480
|
+
fill: "none",
|
|
25481
|
+
stroke: "currentColor",
|
|
25482
|
+
strokeWidth: "2",
|
|
25483
|
+
strokeLinecap: "round",
|
|
25484
|
+
strokeLinejoin: "round",
|
|
25485
|
+
"aria-hidden": "true",
|
|
25486
|
+
children: [
|
|
25487
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "3 6 5 6 21 6" }),
|
|
25488
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }),
|
|
25489
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "10", y1: "11", x2: "10", y2: "17" }),
|
|
25490
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "14", y1: "11", x2: "14", y2: "17" })
|
|
25491
|
+
]
|
|
25492
|
+
}
|
|
25493
|
+
);
|
|
25494
|
+
|
|
25495
|
+
// source/gui/client/components/ManageContributorsModal.tsx
|
|
25496
|
+
var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
|
|
25497
|
+
var ManageContributorsModal = ({
|
|
25498
|
+
contributors,
|
|
25499
|
+
onRemove,
|
|
25500
|
+
onClose
|
|
25501
|
+
}) => {
|
|
25502
|
+
const [armedId, setArmedId] = (0, import_react5.useState)(null);
|
|
25503
|
+
const sorted = [...contributors].sort((a, b) => a.name.localeCompare(b.name));
|
|
25504
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
25505
|
+
"div",
|
|
25506
|
+
{
|
|
25507
|
+
style: {
|
|
25508
|
+
position: "fixed",
|
|
25509
|
+
inset: 0,
|
|
25510
|
+
background: "rgba(0, 0, 0, 0.25)",
|
|
25511
|
+
backdropFilter: "blur(.5px)",
|
|
25512
|
+
display: "flex",
|
|
25513
|
+
alignItems: "center",
|
|
25514
|
+
justifyContent: "center",
|
|
25515
|
+
zIndex: 1e3
|
|
25516
|
+
},
|
|
25517
|
+
onMouseDown: onClose,
|
|
25518
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
25519
|
+
"div",
|
|
25520
|
+
{
|
|
25521
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
25522
|
+
style: {
|
|
25523
|
+
marginTop: "-100px",
|
|
25524
|
+
width: 460,
|
|
25525
|
+
background: GUI_THEME.panel,
|
|
25526
|
+
border: `1px solid ${GUI_THEME.line}`,
|
|
25527
|
+
borderRadius: 12,
|
|
25528
|
+
padding: 20,
|
|
25529
|
+
display: "flex",
|
|
25530
|
+
flexDirection: "column",
|
|
25531
|
+
gap: 14
|
|
25532
|
+
},
|
|
25533
|
+
children: [
|
|
25534
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
25535
|
+
"div",
|
|
25536
|
+
{
|
|
25537
|
+
style: {
|
|
25538
|
+
color: GUI_THEME.secondary,
|
|
25539
|
+
fontSize: 10,
|
|
25540
|
+
letterSpacing: 1,
|
|
25541
|
+
textTransform: "uppercase"
|
|
25542
|
+
},
|
|
25543
|
+
children: "Manage external contributors"
|
|
25544
|
+
}
|
|
25545
|
+
),
|
|
25546
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { fontSize: 12, color: GUI_THEME.secondary }, children: "Remove contributors from the suggestion lists. Locked ones have contributed, so their name is in the immutable log either way." }),
|
|
25547
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
25548
|
+
"div",
|
|
25549
|
+
{
|
|
25550
|
+
style: {
|
|
25551
|
+
display: "flex",
|
|
25552
|
+
flexDirection: "column",
|
|
25553
|
+
gap: 2,
|
|
25554
|
+
maxHeight: 260,
|
|
25555
|
+
overflowY: "auto"
|
|
25556
|
+
},
|
|
25557
|
+
children: sorted.map((contributor) => {
|
|
25558
|
+
const locked = contributor.hasAuthoredAnywhere;
|
|
25559
|
+
const armed = armedId === contributor.id;
|
|
25560
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
25561
|
+
"div",
|
|
25562
|
+
{
|
|
25563
|
+
style: {
|
|
25564
|
+
display: "flex",
|
|
25565
|
+
alignItems: "center",
|
|
25566
|
+
justifyContent: "space-between",
|
|
25567
|
+
gap: 8,
|
|
25568
|
+
padding: "6px 8px",
|
|
25569
|
+
borderRadius: 6
|
|
25570
|
+
},
|
|
25571
|
+
children: [
|
|
25572
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
25573
|
+
"span",
|
|
25574
|
+
{
|
|
25575
|
+
style: {
|
|
25576
|
+
fontSize: 12,
|
|
25577
|
+
color: contributor.color,
|
|
25578
|
+
opacity: locked ? 0.5 : 1
|
|
25579
|
+
},
|
|
25580
|
+
children: [
|
|
25581
|
+
"@",
|
|
25582
|
+
contributor.name
|
|
25583
|
+
]
|
|
25584
|
+
}
|
|
25585
|
+
),
|
|
25586
|
+
locked ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
25587
|
+
"span",
|
|
25588
|
+
{
|
|
25589
|
+
title: "Has contributed \u2014 their name is in the immutable log either way",
|
|
25590
|
+
style: {
|
|
25591
|
+
display: "flex",
|
|
25592
|
+
color: GUI_THEME.dim,
|
|
25593
|
+
opacity: 0.7,
|
|
25594
|
+
// Matches the ghost button's padding so locked and
|
|
25595
|
+
// removable rows keep the same height.
|
|
25596
|
+
padding: "3px 6px"
|
|
25597
|
+
},
|
|
25598
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconLock, {})
|
|
25599
|
+
}
|
|
25600
|
+
) : contributor.isRemoved ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { color: GUI_THEME.dim, fontSize: 10 }, children: "removed" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
25601
|
+
Button,
|
|
25602
|
+
{
|
|
25603
|
+
variant: "ghost",
|
|
25604
|
+
title: armed ? `Click again to remove @${contributor.name}` : `Remove @${contributor.name}`,
|
|
25605
|
+
onClick: () => {
|
|
25606
|
+
if (!armed) return setArmedId(contributor.id);
|
|
25607
|
+
onRemove(contributor.id);
|
|
25608
|
+
setArmedId(null);
|
|
25609
|
+
},
|
|
25610
|
+
style: {
|
|
25611
|
+
display: "flex",
|
|
25612
|
+
alignItems: "center",
|
|
25613
|
+
gap: 6,
|
|
25614
|
+
color: armed ? GUI_THEME.red : GUI_THEME.dim,
|
|
25615
|
+
borderColor: armed ? GUI_THEME.red : void 0
|
|
25616
|
+
},
|
|
25617
|
+
children: [
|
|
25618
|
+
armed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontSize: 10 }, children: "confirm" }),
|
|
25619
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconTrash, {})
|
|
25620
|
+
]
|
|
25621
|
+
}
|
|
25622
|
+
)
|
|
25623
|
+
]
|
|
25624
|
+
},
|
|
25625
|
+
contributor.id
|
|
25626
|
+
);
|
|
25627
|
+
})
|
|
25628
|
+
}
|
|
25629
|
+
),
|
|
25630
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { display: "flex", justifyContent: "flex-end" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { variant: "ghost", onClick: onClose, children: "close" }) })
|
|
25631
|
+
]
|
|
25632
|
+
}
|
|
25633
|
+
)
|
|
25634
|
+
}
|
|
25635
|
+
);
|
|
25636
|
+
};
|
|
25637
|
+
|
|
25638
|
+
// source/gui/client/components/CopyRef.tsx
|
|
25639
|
+
var import_react6 = __toESM(require_react(), 1);
|
|
25640
|
+
var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
|
|
25418
25641
|
var copyToClipboard = async (value) => {
|
|
25419
25642
|
try {
|
|
25420
25643
|
await navigator.clipboard.writeText(value);
|
|
@@ -25424,12 +25647,12 @@ var copyToClipboard = async (value) => {
|
|
|
25424
25647
|
}
|
|
25425
25648
|
};
|
|
25426
25649
|
var CopyRef = ({ refValue }) => {
|
|
25427
|
-
const [copied, setCopied] = (0,
|
|
25428
|
-
const resetTimer = (0,
|
|
25650
|
+
const [copied, setCopied] = (0, import_react6.useState)(false);
|
|
25651
|
+
const resetTimer = (0, import_react6.useRef)(
|
|
25429
25652
|
void 0
|
|
25430
25653
|
);
|
|
25431
|
-
(0,
|
|
25432
|
-
return /* @__PURE__ */ (0,
|
|
25654
|
+
(0, import_react6.useEffect)(() => () => clearTimeout(resetTimer.current), []);
|
|
25655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
25433
25656
|
"button",
|
|
25434
25657
|
{
|
|
25435
25658
|
type: "button",
|
|
@@ -25464,8 +25687,8 @@ var CopyRef = ({ refValue }) => {
|
|
|
25464
25687
|
};
|
|
25465
25688
|
|
|
25466
25689
|
// source/gui/client/components/FormHeader.tsx
|
|
25467
|
-
var
|
|
25468
|
-
var FormHeader = ({ children }) => /* @__PURE__ */ (0,
|
|
25690
|
+
var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
|
|
25691
|
+
var FormHeader = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
25469
25692
|
"div",
|
|
25470
25693
|
{
|
|
25471
25694
|
style: {
|
|
@@ -25480,8 +25703,8 @@ var FormHeader = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
|
25480
25703
|
);
|
|
25481
25704
|
|
|
25482
25705
|
// source/gui/client/components/FormPrimitives.tsx
|
|
25483
|
-
var
|
|
25484
|
-
var Input = (props) => /* @__PURE__ */ (0,
|
|
25706
|
+
var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
|
|
25707
|
+
var Input = (props) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
25485
25708
|
"input",
|
|
25486
25709
|
{
|
|
25487
25710
|
...props,
|
|
@@ -25499,7 +25722,7 @@ var Input = (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
|
25499
25722
|
}
|
|
25500
25723
|
}
|
|
25501
25724
|
);
|
|
25502
|
-
var Textarea = (props) => /* @__PURE__ */ (0,
|
|
25725
|
+
var Textarea = (props) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
25503
25726
|
"textarea",
|
|
25504
25727
|
{
|
|
25505
25728
|
maxLength: props.maxLength ?? 1500,
|
|
@@ -25521,28 +25744,28 @@ var Textarea = (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
|
25521
25744
|
}
|
|
25522
25745
|
}
|
|
25523
25746
|
);
|
|
25524
|
-
var ActionRow = ({ children }) => /* @__PURE__ */ (0,
|
|
25747
|
+
var ActionRow = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
25525
25748
|
"div",
|
|
25526
25749
|
{
|
|
25527
25750
|
style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 8 },
|
|
25528
25751
|
children
|
|
25529
25752
|
}
|
|
25530
25753
|
);
|
|
25531
|
-
var AddRow = ({ children }) => /* @__PURE__ */ (0,
|
|
25532
|
-
var ChipRow = ({ children }) => /* @__PURE__ */ (0,
|
|
25533
|
-
var Empty = ({ children }) => /* @__PURE__ */ (0,
|
|
25754
|
+
var AddRow = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", gap: 8, marginTop: 10 }, children });
|
|
25755
|
+
var ChipRow = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap", marginTop: 10 }, children });
|
|
25756
|
+
var Empty = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { display: "inline-block", marginTop: 8, color: GUI_THEME.dim }, children });
|
|
25534
25757
|
|
|
25535
25758
|
// source/gui/client/components/IssueAttachments.tsx
|
|
25536
|
-
var
|
|
25759
|
+
var import_react7 = __toESM(require_react(), 1);
|
|
25537
25760
|
|
|
25538
25761
|
// source/gui/client/components/Section.tsx
|
|
25539
|
-
var
|
|
25762
|
+
var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
|
|
25540
25763
|
var Section = ({
|
|
25541
25764
|
title,
|
|
25542
25765
|
action,
|
|
25543
25766
|
children,
|
|
25544
25767
|
first = false
|
|
25545
|
-
}) => /* @__PURE__ */ (0,
|
|
25768
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
25546
25769
|
"section",
|
|
25547
25770
|
{
|
|
25548
25771
|
style: {
|
|
@@ -25550,7 +25773,7 @@ var Section = ({
|
|
|
25550
25773
|
borderTop: first ? "none" : `1px solid ${GUI_THEME.line}`
|
|
25551
25774
|
},
|
|
25552
25775
|
children: [
|
|
25553
|
-
/* @__PURE__ */ (0,
|
|
25776
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
25554
25777
|
"div",
|
|
25555
25778
|
{
|
|
25556
25779
|
style: {
|
|
@@ -25560,7 +25783,7 @@ var Section = ({
|
|
|
25560
25783
|
gap: 12
|
|
25561
25784
|
},
|
|
25562
25785
|
children: [
|
|
25563
|
-
/* @__PURE__ */ (0,
|
|
25786
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
25564
25787
|
"span",
|
|
25565
25788
|
{
|
|
25566
25789
|
style: {
|
|
@@ -25582,7 +25805,7 @@ var Section = ({
|
|
|
25582
25805
|
);
|
|
25583
25806
|
|
|
25584
25807
|
// source/gui/client/components/IssueAttachments.tsx
|
|
25585
|
-
var
|
|
25808
|
+
var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
|
|
25586
25809
|
var IssueAttachments = ({
|
|
25587
25810
|
issueId,
|
|
25588
25811
|
readonly,
|
|
@@ -25591,15 +25814,15 @@ var IssueAttachments = ({
|
|
|
25591
25814
|
onUploadFiles,
|
|
25592
25815
|
onDeleteAttachment
|
|
25593
25816
|
}) => {
|
|
25594
|
-
const [dragging, setDragging] = (0,
|
|
25595
|
-
const [lightbox, setLightbox] = (0,
|
|
25596
|
-
const [broken, setBroken] = (0,
|
|
25597
|
-
(0,
|
|
25817
|
+
const [dragging, setDragging] = (0, import_react7.useState)(false);
|
|
25818
|
+
const [lightbox, setLightbox] = (0, import_react7.useState)(null);
|
|
25819
|
+
const [broken, setBroken] = (0, import_react7.useState)({});
|
|
25820
|
+
(0, import_react7.useEffect)(() => {
|
|
25598
25821
|
setLightbox(null);
|
|
25599
25822
|
setDragging(false);
|
|
25600
25823
|
setBroken({});
|
|
25601
25824
|
}, [issueId]);
|
|
25602
|
-
(0,
|
|
25825
|
+
(0, import_react7.useEffect)(() => {
|
|
25603
25826
|
if (!lightbox) return;
|
|
25604
25827
|
const onKeyDown = (event) => {
|
|
25605
25828
|
if (event.key === "Escape") setLightbox(null);
|
|
@@ -25617,12 +25840,12 @@ var IssueAttachments = ({
|
|
|
25617
25840
|
);
|
|
25618
25841
|
if (files.length > 0) onUploadFiles?.(issueId, files);
|
|
25619
25842
|
};
|
|
25620
|
-
return /* @__PURE__ */ (0,
|
|
25843
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
25621
25844
|
Section,
|
|
25622
25845
|
{
|
|
25623
25846
|
title: `Attachments${attachments.length ? ` (${attachments.length})` : ""}`,
|
|
25624
25847
|
children: [
|
|
25625
|
-
/* @__PURE__ */ (0,
|
|
25848
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
25626
25849
|
"div",
|
|
25627
25850
|
{
|
|
25628
25851
|
onDragOver: (event) => {
|
|
@@ -25640,7 +25863,7 @@ var IssueAttachments = ({
|
|
|
25640
25863
|
transition: "padding 0.12s ease, border-color 0.12s ease"
|
|
25641
25864
|
},
|
|
25642
25865
|
children: [
|
|
25643
|
-
attachments.length === 0 ? /* @__PURE__ */ (0,
|
|
25866
|
+
attachments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Empty, { children: canUpload ? "No attachments \u2014 drop an image here" : "No attachments" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25644
25867
|
"div",
|
|
25645
25868
|
{
|
|
25646
25869
|
style: {
|
|
@@ -25648,12 +25871,12 @@ var IssueAttachments = ({
|
|
|
25648
25871
|
flexWrap: "wrap",
|
|
25649
25872
|
gap: 8
|
|
25650
25873
|
},
|
|
25651
|
-
children: attachments.map((attachment) => /* @__PURE__ */ (0,
|
|
25874
|
+
children: attachments.map((attachment) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
25652
25875
|
"div",
|
|
25653
25876
|
{
|
|
25654
25877
|
style: { position: "relative", width: 72, height: 72 },
|
|
25655
25878
|
children: [
|
|
25656
|
-
/* @__PURE__ */ (0,
|
|
25879
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25657
25880
|
"button",
|
|
25658
25881
|
{
|
|
25659
25882
|
type: "button",
|
|
@@ -25673,7 +25896,7 @@ var IssueAttachments = ({
|
|
|
25673
25896
|
width: "100%",
|
|
25674
25897
|
height: "100%"
|
|
25675
25898
|
},
|
|
25676
|
-
children: broken[attachment.id] ? /* @__PURE__ */ (0,
|
|
25899
|
+
children: broken[attachment.id] ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25677
25900
|
"span",
|
|
25678
25901
|
{
|
|
25679
25902
|
title: "Attachment unavailable (missing, corrupt, or over the size cap)",
|
|
@@ -25690,7 +25913,7 @@ var IssueAttachments = ({
|
|
|
25690
25913
|
},
|
|
25691
25914
|
children: "unavailable"
|
|
25692
25915
|
}
|
|
25693
|
-
) : /* @__PURE__ */ (0,
|
|
25916
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25694
25917
|
"img",
|
|
25695
25918
|
{
|
|
25696
25919
|
src: `/media/${attachment.fileName}`,
|
|
@@ -25707,7 +25930,7 @@ var IssueAttachments = ({
|
|
|
25707
25930
|
)
|
|
25708
25931
|
}
|
|
25709
25932
|
),
|
|
25710
|
-
attachment.canDelete && !readonly && onDeleteAttachment && /* @__PURE__ */ (0,
|
|
25933
|
+
attachment.canDelete && !readonly && onDeleteAttachment && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25711
25934
|
"button",
|
|
25712
25935
|
{
|
|
25713
25936
|
type: "button",
|
|
@@ -25737,7 +25960,7 @@ var IssueAttachments = ({
|
|
|
25737
25960
|
))
|
|
25738
25961
|
}
|
|
25739
25962
|
),
|
|
25740
|
-
canUpload && attachments.length > 0 && /* @__PURE__ */ (0,
|
|
25963
|
+
canUpload && attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25741
25964
|
"div",
|
|
25742
25965
|
{
|
|
25743
25966
|
style: {
|
|
@@ -25748,7 +25971,7 @@ var IssueAttachments = ({
|
|
|
25748
25971
|
children: "drop an image to attach"
|
|
25749
25972
|
}
|
|
25750
25973
|
),
|
|
25751
|
-
uploadStatus.state === "uploading" && /* @__PURE__ */ (0,
|
|
25974
|
+
uploadStatus.state === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
25752
25975
|
"div",
|
|
25753
25976
|
{
|
|
25754
25977
|
style: {
|
|
@@ -25763,7 +25986,7 @@ var IssueAttachments = ({
|
|
|
25763
25986
|
]
|
|
25764
25987
|
}
|
|
25765
25988
|
),
|
|
25766
|
-
uploadStatus.state === "error" && /* @__PURE__ */ (0,
|
|
25989
|
+
uploadStatus.state === "error" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25767
25990
|
"div",
|
|
25768
25991
|
{
|
|
25769
25992
|
style: {
|
|
@@ -25777,7 +26000,7 @@ var IssueAttachments = ({
|
|
|
25777
26000
|
]
|
|
25778
26001
|
}
|
|
25779
26002
|
),
|
|
25780
|
-
lightbox && /* @__PURE__ */ (0,
|
|
26003
|
+
lightbox && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
25781
26004
|
"div",
|
|
25782
26005
|
{
|
|
25783
26006
|
onClick: () => setLightbox(null),
|
|
@@ -25794,7 +26017,7 @@ var IssueAttachments = ({
|
|
|
25794
26017
|
cursor: "zoom-out"
|
|
25795
26018
|
},
|
|
25796
26019
|
children: [
|
|
25797
|
-
/* @__PURE__ */ (0,
|
|
26020
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
25798
26021
|
"img",
|
|
25799
26022
|
{
|
|
25800
26023
|
src: `/media/${lightbox.fileName}`,
|
|
@@ -25807,7 +26030,7 @@ var IssueAttachments = ({
|
|
|
25807
26030
|
}
|
|
25808
26031
|
}
|
|
25809
26032
|
),
|
|
25810
|
-
/* @__PURE__ */ (0,
|
|
26033
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { color: GUI_THEME.secondary, fontSize: 11 }, children: [
|
|
25811
26034
|
lightbox.name,
|
|
25812
26035
|
" \xB7 ",
|
|
25813
26036
|
Math.max(1, Math.round(lightbox.bytes / 1024)),
|
|
@@ -25823,7 +26046,7 @@ var IssueAttachments = ({
|
|
|
25823
26046
|
};
|
|
25824
26047
|
|
|
25825
26048
|
// source/gui/client/components/IssueComments.tsx
|
|
25826
|
-
var
|
|
26049
|
+
var import_react9 = __toESM(require_react(), 1);
|
|
25827
26050
|
|
|
25828
26051
|
// source/gui/client/lib/gui-format.helper.ts
|
|
25829
26052
|
var timeAgo = (timestampMs) => {
|
|
@@ -27479,11 +27702,11 @@ function addChildren(props, children) {
|
|
|
27479
27702
|
}
|
|
27480
27703
|
}
|
|
27481
27704
|
}
|
|
27482
|
-
function productionCreate(_,
|
|
27705
|
+
function productionCreate(_, jsx34, jsxs22) {
|
|
27483
27706
|
return create2;
|
|
27484
27707
|
function create2(_2, type, props, key) {
|
|
27485
27708
|
const isStaticChildren = Array.isArray(props.children);
|
|
27486
|
-
const fn = isStaticChildren ?
|
|
27709
|
+
const fn = isStaticChildren ? jsxs22 : jsx34;
|
|
27487
27710
|
return key ? fn(type, props, key) : fn(type, props);
|
|
27488
27711
|
}
|
|
27489
27712
|
}
|
|
@@ -27728,8 +27951,8 @@ var urlAttributes = {
|
|
|
27728
27951
|
};
|
|
27729
27952
|
|
|
27730
27953
|
// node_modules/react-markdown/lib/index.js
|
|
27731
|
-
var
|
|
27732
|
-
var
|
|
27954
|
+
var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
|
|
27955
|
+
var import_react8 = __toESM(require_react(), 1);
|
|
27733
27956
|
|
|
27734
27957
|
// node_modules/mdast-util-to-string/lib/index.js
|
|
27735
27958
|
var emptyOptions2 = {};
|
|
@@ -35403,11 +35626,11 @@ function post(tree, options) {
|
|
|
35403
35626
|
}
|
|
35404
35627
|
visit(tree, transform);
|
|
35405
35628
|
return toJsxRuntime(tree, {
|
|
35406
|
-
Fragment:
|
|
35629
|
+
Fragment: import_jsx_runtime16.Fragment,
|
|
35407
35630
|
components: components2,
|
|
35408
35631
|
ignoreInvalidStyle: true,
|
|
35409
|
-
jsx:
|
|
35410
|
-
jsxs:
|
|
35632
|
+
jsx: import_jsx_runtime16.jsx,
|
|
35633
|
+
jsxs: import_jsx_runtime16.jsxs,
|
|
35411
35634
|
passKeys: true,
|
|
35412
35635
|
passNode: true
|
|
35413
35636
|
});
|
|
@@ -38530,16 +38753,16 @@ function remarkGfm(options) {
|
|
|
38530
38753
|
}
|
|
38531
38754
|
|
|
38532
38755
|
// source/gui/client/components/MarkdownContent.tsx
|
|
38533
|
-
var
|
|
38756
|
+
var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
|
|
38534
38757
|
var components = {
|
|
38535
|
-
p: ({ children }) => /* @__PURE__ */ (0,
|
|
38536
|
-
ul: ({ children }) => /* @__PURE__ */ (0,
|
|
38537
|
-
ol: ({ children }) => /* @__PURE__ */ (0,
|
|
38538
|
-
li: ({ children }) => /* @__PURE__ */ (0,
|
|
38539
|
-
h1: ({ children }) => /* @__PURE__ */ (0,
|
|
38540
|
-
h2: ({ children }) => /* @__PURE__ */ (0,
|
|
38541
|
-
h3: ({ children }) => /* @__PURE__ */ (0,
|
|
38542
|
-
a: ({ children, href }) => /* @__PURE__ */ (0,
|
|
38758
|
+
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { margin: "0 0 14px" }, children }),
|
|
38759
|
+
ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ul", { style: { margin: "0 0 14px", paddingLeft: 20 }, children }),
|
|
38760
|
+
ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ol", { style: { margin: "0 0 14px", paddingLeft: 20 }, children }),
|
|
38761
|
+
li: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("li", { style: { margin: "2px 0" }, children }),
|
|
38762
|
+
h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h1", { style: { fontSize: 16, margin: "0 0 14px" }, children }),
|
|
38763
|
+
h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { style: { fontSize: 14, margin: "0 0 14px" }, children }),
|
|
38764
|
+
h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h3", { style: { fontSize: 13, margin: "0 0 14px" }, children }),
|
|
38765
|
+
a: ({ children, href }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38543
38766
|
"a",
|
|
38544
38767
|
{
|
|
38545
38768
|
href,
|
|
@@ -38549,7 +38772,7 @@ var components = {
|
|
|
38549
38772
|
children
|
|
38550
38773
|
}
|
|
38551
38774
|
),
|
|
38552
|
-
blockquote: ({ children }) => /* @__PURE__ */ (0,
|
|
38775
|
+
blockquote: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38553
38776
|
"blockquote",
|
|
38554
38777
|
{
|
|
38555
38778
|
style: {
|
|
@@ -38563,7 +38786,7 @@ var components = {
|
|
|
38563
38786
|
),
|
|
38564
38787
|
code: ({ children, className }) => {
|
|
38565
38788
|
const isBlock = Boolean(className);
|
|
38566
|
-
return /* @__PURE__ */ (0,
|
|
38789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38567
38790
|
"code",
|
|
38568
38791
|
{
|
|
38569
38792
|
style: {
|
|
@@ -38580,18 +38803,22 @@ var components = {
|
|
|
38580
38803
|
}
|
|
38581
38804
|
);
|
|
38582
38805
|
},
|
|
38583
|
-
pre: ({ children }) => /* @__PURE__ */ (0,
|
|
38584
|
-
hr: () => /* @__PURE__ */ (0,
|
|
38806
|
+
pre: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { style: { margin: "0 0 14px" }, children }),
|
|
38807
|
+
hr: () => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38585
38808
|
"hr",
|
|
38586
38809
|
{
|
|
38587
|
-
style: {
|
|
38810
|
+
style: {
|
|
38811
|
+
border: "none",
|
|
38812
|
+
borderTop: `1px solid ${GUI_THEME.line}`,
|
|
38813
|
+
margin: "12px 0"
|
|
38814
|
+
}
|
|
38588
38815
|
}
|
|
38589
38816
|
)
|
|
38590
38817
|
};
|
|
38591
38818
|
var MarkdownContent = ({
|
|
38592
38819
|
content: content3,
|
|
38593
38820
|
softBreaks = false
|
|
38594
|
-
}) => /* @__PURE__ */ (0,
|
|
38821
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38595
38822
|
"div",
|
|
38596
38823
|
{
|
|
38597
38824
|
style: {
|
|
@@ -38604,7 +38831,7 @@ var MarkdownContent = ({
|
|
|
38604
38831
|
// collapsing, so the container doesn't end in dead whitespace.
|
|
38605
38832
|
marginBottom: -14
|
|
38606
38833
|
},
|
|
38607
|
-
children: /* @__PURE__ */ (0,
|
|
38834
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38608
38835
|
Markdown,
|
|
38609
38836
|
{
|
|
38610
38837
|
remarkPlugins: softBreaks ? [remarkGfm, remarkBreaks] : [remarkGfm],
|
|
@@ -38616,7 +38843,7 @@ var MarkdownContent = ({
|
|
|
38616
38843
|
);
|
|
38617
38844
|
|
|
38618
38845
|
// source/gui/client/components/IssueComments.tsx
|
|
38619
|
-
var
|
|
38846
|
+
var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
|
|
38620
38847
|
var IssueComments = ({
|
|
38621
38848
|
whoAmI,
|
|
38622
38849
|
issueId,
|
|
@@ -38625,15 +38852,15 @@ var IssueComments = ({
|
|
|
38625
38852
|
onAddComment,
|
|
38626
38853
|
onDeleteComment
|
|
38627
38854
|
}) => {
|
|
38628
|
-
const [body, setBody] = (0,
|
|
38855
|
+
const [body, setBody] = (0, import_react9.useState)("");
|
|
38629
38856
|
const addComment = () => {
|
|
38630
38857
|
const nextBody = body.trim();
|
|
38631
38858
|
if (!nextBody) return;
|
|
38632
38859
|
onAddComment?.(issueId, nextBody);
|
|
38633
38860
|
setBody("");
|
|
38634
38861
|
};
|
|
38635
|
-
return /* @__PURE__ */ (0,
|
|
38636
|
-
comments.length === 0 ? /* @__PURE__ */ (0,
|
|
38862
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
|
|
38863
|
+
comments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Empty, { children: "No comments" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: comments.map((comment) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
38637
38864
|
"div",
|
|
38638
38865
|
{
|
|
38639
38866
|
style: {
|
|
@@ -38643,7 +38870,7 @@ var IssueComments = ({
|
|
|
38643
38870
|
background: GUI_THEME.tertiary
|
|
38644
38871
|
},
|
|
38645
38872
|
children: [
|
|
38646
|
-
/* @__PURE__ */ (0,
|
|
38873
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
38647
38874
|
"div",
|
|
38648
38875
|
{
|
|
38649
38876
|
style: {
|
|
@@ -38653,15 +38880,15 @@ var IssueComments = ({
|
|
|
38653
38880
|
marginBottom: 8
|
|
38654
38881
|
},
|
|
38655
38882
|
children: [
|
|
38656
|
-
/* @__PURE__ */ (0,
|
|
38883
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { color: GUI_THEME.secondary, fontSize: 11 }, children: [
|
|
38657
38884
|
comment.author.name ?? "unknown",
|
|
38658
|
-
comment.createdAt && /* @__PURE__ */ (0,
|
|
38885
|
+
comment.createdAt && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { color: GUI_THEME.dim2 }, children: [
|
|
38659
38886
|
" ",
|
|
38660
38887
|
"\xB7 ",
|
|
38661
38888
|
timeAgo(comment.createdAt)
|
|
38662
38889
|
] })
|
|
38663
38890
|
] }),
|
|
38664
|
-
comment.author.id === whoAmI.id && onDeleteComment && /* @__PURE__ */ (0,
|
|
38891
|
+
!readonly && comment.author.id === whoAmI.id && onDeleteComment && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
38665
38892
|
Button,
|
|
38666
38893
|
{
|
|
38667
38894
|
variant: "ghost",
|
|
@@ -38676,13 +38903,13 @@ var IssueComments = ({
|
|
|
38676
38903
|
]
|
|
38677
38904
|
}
|
|
38678
38905
|
),
|
|
38679
|
-
/* @__PURE__ */ (0,
|
|
38906
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownContent, { content: comment.body, softBreaks: true })
|
|
38680
38907
|
]
|
|
38681
38908
|
},
|
|
38682
38909
|
comment.id
|
|
38683
38910
|
)) }),
|
|
38684
|
-
!readonly && /* @__PURE__ */ (0,
|
|
38685
|
-
/* @__PURE__ */ (0,
|
|
38911
|
+
!readonly && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginTop: 20 }, children: [
|
|
38912
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
38686
38913
|
Textarea,
|
|
38687
38914
|
{
|
|
38688
38915
|
maxLength: 120,
|
|
@@ -38702,18 +38929,18 @@ var IssueComments = ({
|
|
|
38702
38929
|
}
|
|
38703
38930
|
}
|
|
38704
38931
|
),
|
|
38705
|
-
/* @__PURE__ */ (0,
|
|
38932
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ActionRow, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: addComment, children: "comment" }) })
|
|
38706
38933
|
] })
|
|
38707
38934
|
] });
|
|
38708
38935
|
};
|
|
38709
38936
|
|
|
38710
38937
|
// source/gui/client/components/Tabs.tsx
|
|
38711
|
-
var
|
|
38938
|
+
var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
|
|
38712
38939
|
var Tabs = ({
|
|
38713
38940
|
activeTab,
|
|
38714
38941
|
tabs,
|
|
38715
38942
|
onChange
|
|
38716
|
-
}) => /* @__PURE__ */ (0,
|
|
38943
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
38717
38944
|
"div",
|
|
38718
38945
|
{
|
|
38719
38946
|
style: {
|
|
@@ -38724,7 +38951,7 @@ var Tabs = ({
|
|
|
38724
38951
|
},
|
|
38725
38952
|
children: tabs.map((tab2) => {
|
|
38726
38953
|
const active = tab2.id === activeTab;
|
|
38727
|
-
return /* @__PURE__ */ (0,
|
|
38954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
38728
38955
|
"button",
|
|
38729
38956
|
{
|
|
38730
38957
|
type: "button",
|
|
@@ -38742,7 +38969,7 @@ var Tabs = ({
|
|
|
38742
38969
|
},
|
|
38743
38970
|
children: [
|
|
38744
38971
|
tab2.label,
|
|
38745
|
-
typeof tab2.count === "number" && /* @__PURE__ */ (0,
|
|
38972
|
+
typeof tab2.count === "number" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
38746
38973
|
"span",
|
|
38747
38974
|
{
|
|
38748
38975
|
style: { color: tab2.count ? GUI_THEME.secondary : GUI_THEME.dim },
|
|
@@ -38763,7 +38990,7 @@ var Tabs = ({
|
|
|
38763
38990
|
);
|
|
38764
38991
|
|
|
38765
38992
|
// source/gui/client/components/IssueDetails.tsx
|
|
38766
|
-
var
|
|
38993
|
+
var import_jsx_runtime20 = __toESM(require_jsx_runtime(), 1);
|
|
38767
38994
|
var IssueDetails = ({
|
|
38768
38995
|
whoAmI,
|
|
38769
38996
|
comments,
|
|
@@ -38776,6 +39003,8 @@ var IssueDetails = ({
|
|
|
38776
39003
|
onAddTag,
|
|
38777
39004
|
onRemoveTag,
|
|
38778
39005
|
onAddAssignee,
|
|
39006
|
+
onAddExternalAssignee,
|
|
39007
|
+
onRemoveContributor,
|
|
38779
39008
|
onRemoveAssignee,
|
|
38780
39009
|
onCloseIssue,
|
|
38781
39010
|
onReopenIssue,
|
|
@@ -38786,28 +39015,30 @@ var IssueDetails = ({
|
|
|
38786
39015
|
onUploadAttachments,
|
|
38787
39016
|
onDeleteAttachment,
|
|
38788
39017
|
knownTags: tags,
|
|
38789
|
-
knownAssignees: assignees
|
|
39018
|
+
knownAssignees: assignees,
|
|
39019
|
+
onOpenAssigneePicker
|
|
38790
39020
|
}) => {
|
|
38791
|
-
const [title, setTitle] = (0,
|
|
38792
|
-
const [description, setDescription] = (0,
|
|
38793
|
-
const [tagName, setTagName] = (0,
|
|
38794
|
-
const [assigneeName, setAssigneeName] = (0,
|
|
38795
|
-
const [
|
|
38796
|
-
const [
|
|
38797
|
-
const [
|
|
38798
|
-
const [
|
|
38799
|
-
const
|
|
38800
|
-
const
|
|
39021
|
+
const [title, setTitle] = (0, import_react10.useState)("");
|
|
39022
|
+
const [description, setDescription] = (0, import_react10.useState)("");
|
|
39023
|
+
const [tagName, setTagName] = (0, import_react10.useState)("");
|
|
39024
|
+
const [assigneeName, setAssigneeName] = (0, import_react10.useState)("");
|
|
39025
|
+
const [managingContributors, setManagingContributors] = (0, import_react10.useState)(false);
|
|
39026
|
+
const [editingTitle, setEditingTitle] = (0, import_react10.useState)(false);
|
|
39027
|
+
const [editingDescription, setEditingDescription] = (0, import_react10.useState)(false);
|
|
39028
|
+
const [addingTag, setAddingTag] = (0, import_react10.useState)(false);
|
|
39029
|
+
const [addingAssignee, setAddingAssignee] = (0, import_react10.useState)(false);
|
|
39030
|
+
const panelRef = (0, import_react10.useRef)(null);
|
|
39031
|
+
const titleTextareaRef = (0, import_react10.useRef)(null);
|
|
38801
39032
|
const resizeTitleTextarea = () => {
|
|
38802
39033
|
const el = titleTextareaRef.current;
|
|
38803
39034
|
if (!el) return;
|
|
38804
39035
|
el.style.height = "auto";
|
|
38805
39036
|
el.style.height = `${el.scrollHeight}px`;
|
|
38806
39037
|
};
|
|
38807
|
-
(0,
|
|
39038
|
+
(0, import_react10.useEffect)(() => {
|
|
38808
39039
|
if (editingTitle) resizeTitleTextarea();
|
|
38809
39040
|
}, [editingTitle]);
|
|
38810
|
-
(0,
|
|
39041
|
+
(0, import_react10.useEffect)(() => {
|
|
38811
39042
|
if (!issue) return;
|
|
38812
39043
|
const handleClickOutside = (event) => {
|
|
38813
39044
|
if (panelRef.current && !panelRef.current.contains(event.target)) {
|
|
@@ -38817,7 +39048,7 @@ var IssueDetails = ({
|
|
|
38817
39048
|
document.addEventListener("mousedown", handleClickOutside);
|
|
38818
39049
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
38819
39050
|
}, [issue, onClose]);
|
|
38820
|
-
(0,
|
|
39051
|
+
(0, import_react10.useEffect)(() => {
|
|
38821
39052
|
setTitle(issue?.title ?? "");
|
|
38822
39053
|
setDescription(issue?.description ?? "");
|
|
38823
39054
|
setTagName("");
|
|
@@ -38867,317 +39098,360 @@ var IssueDetails = ({
|
|
|
38867
39098
|
};
|
|
38868
39099
|
const addAssignee = () => {
|
|
38869
39100
|
if (disabled || !issue || !assigneeName.trim()) return;
|
|
38870
|
-
|
|
39101
|
+
onAddExternalAssignee(issue.id, assigneeName.trim());
|
|
38871
39102
|
setAssigneeName("");
|
|
38872
39103
|
setAddingAssignee(false);
|
|
38873
39104
|
};
|
|
38874
39105
|
const availableTags = tags.filter(
|
|
38875
39106
|
(tag) => !issue?.tags.some((issueTag) => issueTag.id === tag.id)
|
|
38876
39107
|
);
|
|
39108
|
+
const assigneeRank = (assignee) => assignee.isSelf ? 0 : assignee.hasAuthoredAnywhere ? 1 : 2;
|
|
38877
39109
|
const availableAssignees = assignees.filter(
|
|
38878
|
-
(assignee) => !issue?.assignees.some(
|
|
39110
|
+
(assignee) => !issue?.assignees.some(
|
|
39111
|
+
(issueAssignee) => issueAssignee.id === assignee.id
|
|
39112
|
+
)
|
|
39113
|
+
).filter((assignee) => !assignee.isRemoved).sort(
|
|
39114
|
+
(a, b) => assigneeRank(a) - assigneeRank(b) || a.name.localeCompare(b.name)
|
|
38879
39115
|
);
|
|
38880
|
-
return /* @__PURE__ */ (0,
|
|
38881
|
-
/* @__PURE__ */ (0,
|
|
38882
|
-
/* @__PURE__ */ (0,
|
|
38883
|
-
|
|
39116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Aside, { ref: panelRef, children: [
|
|
39117
|
+
issue ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
39118
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(FormHeader, { children: [
|
|
39119
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39120
|
+
"span",
|
|
39121
|
+
{
|
|
39122
|
+
style: {
|
|
39123
|
+
color: GUI_THEME.secondary,
|
|
39124
|
+
fontSize: 10,
|
|
39125
|
+
textTransform: "uppercase",
|
|
39126
|
+
letterSpacing: "0.08em"
|
|
39127
|
+
},
|
|
39128
|
+
children: issue.ref && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CopyRef, { refValue: issue.ref })
|
|
39129
|
+
}
|
|
39130
|
+
),
|
|
39131
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { variant: "ghost", onClick: onClose, children: "\xD7" })
|
|
39132
|
+
] }),
|
|
39133
|
+
editingTitle ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39134
|
+
"textarea",
|
|
38884
39135
|
{
|
|
38885
|
-
|
|
38886
|
-
|
|
38887
|
-
|
|
38888
|
-
|
|
38889
|
-
|
|
39136
|
+
ref: titleTextareaRef,
|
|
39137
|
+
value: title,
|
|
39138
|
+
autoFocus: true,
|
|
39139
|
+
rows: 1,
|
|
39140
|
+
onChange: (event) => {
|
|
39141
|
+
setTitle(event.target.value);
|
|
39142
|
+
resizeTitleTextarea();
|
|
38890
39143
|
},
|
|
38891
|
-
|
|
38892
|
-
|
|
38893
|
-
|
|
38894
|
-
|
|
38895
|
-
|
|
38896
|
-
|
|
38897
|
-
|
|
38898
|
-
|
|
38899
|
-
|
|
38900
|
-
|
|
38901
|
-
|
|
38902
|
-
|
|
38903
|
-
|
|
38904
|
-
|
|
38905
|
-
|
|
38906
|
-
|
|
38907
|
-
|
|
38908
|
-
|
|
38909
|
-
|
|
38910
|
-
|
|
39144
|
+
onKeyDown: (event) => {
|
|
39145
|
+
if (event.key === "Enter") {
|
|
39146
|
+
event.preventDefault();
|
|
39147
|
+
event.currentTarget.blur();
|
|
39148
|
+
}
|
|
39149
|
+
if (event.key === "Escape") cancelTitle();
|
|
39150
|
+
},
|
|
39151
|
+
onBlur: saveTitle,
|
|
39152
|
+
style: {
|
|
39153
|
+
display: "block",
|
|
39154
|
+
width: "100%",
|
|
39155
|
+
boxSizing: "border-box",
|
|
39156
|
+
resize: "none",
|
|
39157
|
+
overflow: "hidden",
|
|
39158
|
+
background: GUI_THEME.bg,
|
|
39159
|
+
color: GUI_THEME.primary,
|
|
39160
|
+
border: `1px solid ${GUI_THEME.line}`,
|
|
39161
|
+
borderRadius: 8,
|
|
39162
|
+
padding: "6px 10px",
|
|
39163
|
+
outline: "none",
|
|
39164
|
+
font: "inherit",
|
|
39165
|
+
fontSize: 18,
|
|
39166
|
+
fontWeight: 600,
|
|
39167
|
+
lineHeight: 1.35,
|
|
39168
|
+
marginBottom: 20
|
|
38911
39169
|
}
|
|
38912
|
-
if (event.key === "Escape") cancelTitle();
|
|
38913
|
-
},
|
|
38914
|
-
onBlur: saveTitle,
|
|
38915
|
-
style: {
|
|
38916
|
-
display: "block",
|
|
38917
|
-
width: "100%",
|
|
38918
|
-
boxSizing: "border-box",
|
|
38919
|
-
resize: "none",
|
|
38920
|
-
overflow: "hidden",
|
|
38921
|
-
background: GUI_THEME.bg,
|
|
38922
|
-
color: GUI_THEME.primary,
|
|
38923
|
-
border: `1px solid ${GUI_THEME.line}`,
|
|
38924
|
-
borderRadius: 8,
|
|
38925
|
-
padding: "6px 10px",
|
|
38926
|
-
outline: "none",
|
|
38927
|
-
font: "inherit",
|
|
38928
|
-
fontSize: 18,
|
|
38929
|
-
fontWeight: 600,
|
|
38930
|
-
lineHeight: 1.35,
|
|
38931
|
-
marginBottom: 20
|
|
38932
39170
|
}
|
|
38933
|
-
|
|
38934
|
-
|
|
38935
|
-
"div",
|
|
38936
|
-
{
|
|
38937
|
-
onClick: () => !issue.readonly && setEditingTitle(true),
|
|
38938
|
-
style: {
|
|
38939
|
-
marginBottom: 18,
|
|
38940
|
-
color: GUI_THEME.primary,
|
|
38941
|
-
fontSize: 18,
|
|
38942
|
-
fontWeight: 600,
|
|
38943
|
-
lineHeight: 1.35,
|
|
38944
|
-
wordBreak: "break-word",
|
|
38945
|
-
cursor: issue.readonly ? "default" : "text"
|
|
38946
|
-
},
|
|
38947
|
-
children: issue.title
|
|
38948
|
-
}
|
|
38949
|
-
),
|
|
38950
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Tabs, { tabs, activeTab, onChange: onChangeTab }),
|
|
38951
|
-
activeTab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
38952
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38953
|
-
Section,
|
|
39171
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39172
|
+
"div",
|
|
38954
39173
|
{
|
|
38955
|
-
|
|
38956
|
-
|
|
38957
|
-
|
|
38958
|
-
|
|
38959
|
-
|
|
38960
|
-
|
|
38961
|
-
|
|
38962
|
-
|
|
38963
|
-
|
|
38964
|
-
|
|
38965
|
-
children:
|
|
38966
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38967
|
-
Textarea,
|
|
38968
|
-
{
|
|
38969
|
-
value: description,
|
|
38970
|
-
autoFocus: true,
|
|
38971
|
-
placeholder: "",
|
|
38972
|
-
onChange: (event) => setDescription(event.target.value),
|
|
38973
|
-
onKeyDown: (event) => {
|
|
38974
|
-
if (event.key === "Escape") cancelDescription();
|
|
38975
|
-
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
38976
|
-
saveDescription();
|
|
38977
|
-
}
|
|
38978
|
-
},
|
|
38979
|
-
style: {
|
|
38980
|
-
font: "inherit",
|
|
38981
|
-
fontFamily: CONTENT_FONT,
|
|
38982
|
-
fontSize: 13,
|
|
38983
|
-
maxHeight: 320,
|
|
38984
|
-
overflowY: "auto"
|
|
38985
|
-
}
|
|
38986
|
-
}
|
|
38987
|
-
),
|
|
38988
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(ActionRow, { children: [
|
|
38989
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: saveDescription, children: "save" }),
|
|
38990
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { variant: "ghost", onClick: cancelDescription, children: "cancel" })
|
|
38991
|
-
] })
|
|
38992
|
-
] }) : issue.description ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
38993
|
-
"div",
|
|
38994
|
-
{
|
|
38995
|
-
style: {
|
|
38996
|
-
marginTop: 8,
|
|
38997
|
-
padding: "12px 16px",
|
|
38998
|
-
maxHeight: 320,
|
|
38999
|
-
overflowY: "auto",
|
|
39000
|
-
background: GUI_THEME.tertiary,
|
|
39001
|
-
borderRadius: 8
|
|
39002
|
-
},
|
|
39003
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarkdownContent, { content: issue.description })
|
|
39004
|
-
}
|
|
39005
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Empty, { children: "No description" })
|
|
39174
|
+
onClick: () => !issue.readonly && setEditingTitle(true),
|
|
39175
|
+
style: {
|
|
39176
|
+
marginBottom: 18,
|
|
39177
|
+
color: GUI_THEME.primary,
|
|
39178
|
+
fontSize: 18,
|
|
39179
|
+
fontWeight: 600,
|
|
39180
|
+
lineHeight: 1.35,
|
|
39181
|
+
wordBreak: "break-word",
|
|
39182
|
+
cursor: issue.readonly ? "default" : "text"
|
|
39183
|
+
},
|
|
39184
|
+
children: issue.title
|
|
39006
39185
|
}
|
|
39007
39186
|
),
|
|
39008
|
-
/* @__PURE__ */ (0,
|
|
39009
|
-
|
|
39010
|
-
|
|
39011
|
-
|
|
39012
|
-
|
|
39013
|
-
|
|
39014
|
-
|
|
39015
|
-
|
|
39016
|
-
{
|
|
39017
|
-
variant: "chip",
|
|
39018
|
-
disabled: issue.readonly,
|
|
39019
|
-
onClick: () => onRemoveTag(issue.id, tag.id),
|
|
39020
|
-
title: "Remove tag",
|
|
39021
|
-
style: { color: tag.color },
|
|
39022
|
-
children: [
|
|
39023
|
-
tag.name,
|
|
39024
|
-
" ",
|
|
39025
|
-
!issue.readonly && "\xD7"
|
|
39026
|
-
]
|
|
39027
|
-
},
|
|
39028
|
-
tag.id
|
|
39029
|
-
)) }),
|
|
39030
|
-
addingTag && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChipRow, { children: availableTags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
39187
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Tabs, { tabs, activeTab, onChange: onChangeTab }),
|
|
39188
|
+
activeTab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
39189
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39190
|
+
Section,
|
|
39191
|
+
{
|
|
39192
|
+
first: true,
|
|
39193
|
+
title: "Description",
|
|
39194
|
+
action: !issue.readonly && !editingDescription && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39031
39195
|
Button,
|
|
39032
39196
|
{
|
|
39033
|
-
variant: "
|
|
39034
|
-
|
|
39035
|
-
|
|
39036
|
-
|
|
39037
|
-
|
|
39038
|
-
|
|
39039
|
-
|
|
39040
|
-
|
|
39041
|
-
]
|
|
39042
|
-
},
|
|
39043
|
-
tag.id
|
|
39044
|
-
)) }),
|
|
39045
|
-
addingTag && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(AddRow, { children: [
|
|
39046
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
39047
|
-
Input,
|
|
39197
|
+
variant: "ghost",
|
|
39198
|
+
onClick: () => setEditingDescription(true),
|
|
39199
|
+
children: "edit"
|
|
39200
|
+
}
|
|
39201
|
+
),
|
|
39202
|
+
children: editingDescription ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
39203
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39204
|
+
Textarea,
|
|
39048
39205
|
{
|
|
39049
|
-
value:
|
|
39206
|
+
value: description,
|
|
39050
39207
|
autoFocus: true,
|
|
39051
|
-
placeholder: "
|
|
39052
|
-
onChange: (event) =>
|
|
39208
|
+
placeholder: "",
|
|
39209
|
+
onChange: (event) => setDescription(event.target.value),
|
|
39053
39210
|
onKeyDown: (event) => {
|
|
39054
|
-
if (event.key === "
|
|
39055
|
-
if (event.key === "
|
|
39056
|
-
|
|
39057
|
-
setAddingTag(false);
|
|
39211
|
+
if (event.key === "Escape") cancelDescription();
|
|
39212
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
39213
|
+
saveDescription();
|
|
39058
39214
|
}
|
|
39215
|
+
},
|
|
39216
|
+
style: {
|
|
39217
|
+
font: "inherit",
|
|
39218
|
+
fontFamily: CONTENT_FONT,
|
|
39219
|
+
fontSize: 13,
|
|
39220
|
+
maxHeight: 320,
|
|
39221
|
+
overflowY: "auto"
|
|
39059
39222
|
}
|
|
39060
39223
|
}
|
|
39061
39224
|
),
|
|
39062
|
-
/* @__PURE__ */ (0,
|
|
39063
|
-
|
|
39064
|
-
|
|
39065
|
-
|
|
39066
|
-
|
|
39067
|
-
|
|
39068
|
-
|
|
39069
|
-
|
|
39070
|
-
|
|
39071
|
-
|
|
39072
|
-
|
|
39073
|
-
|
|
39074
|
-
|
|
39075
|
-
|
|
39076
|
-
|
|
39077
|
-
|
|
39078
|
-
|
|
39079
|
-
|
|
39080
|
-
|
|
39081
|
-
|
|
39082
|
-
|
|
39083
|
-
|
|
39084
|
-
|
|
39085
|
-
|
|
39086
|
-
|
|
39087
|
-
|
|
39225
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(ActionRow, { children: [
|
|
39226
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { onClick: saveDescription, children: "save" }),
|
|
39227
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { variant: "ghost", onClick: cancelDescription, children: "cancel" })
|
|
39228
|
+
] })
|
|
39229
|
+
] }) : issue.description ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39230
|
+
"div",
|
|
39231
|
+
{
|
|
39232
|
+
style: {
|
|
39233
|
+
marginTop: 8,
|
|
39234
|
+
padding: "12px 16px",
|
|
39235
|
+
maxHeight: 320,
|
|
39236
|
+
overflowY: "auto",
|
|
39237
|
+
background: GUI_THEME.tertiary,
|
|
39238
|
+
borderRadius: 8
|
|
39239
|
+
},
|
|
39240
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MarkdownContent, { content: issue.description })
|
|
39241
|
+
}
|
|
39242
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Empty, { children: "No description" })
|
|
39243
|
+
}
|
|
39244
|
+
),
|
|
39245
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
39246
|
+
Section,
|
|
39247
|
+
{
|
|
39248
|
+
title: "Tags",
|
|
39249
|
+
action: !issue.readonly && !addingTag && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { variant: "ghost", onClick: () => setAddingTag(true), children: "+" }) || addingTag && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { variant: "ghost", onClick: () => setAddingTag(false), children: "-" }),
|
|
39250
|
+
children: [
|
|
39251
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChipRow, { children: issue.tags.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Empty, { children: "No tags" }) : issue.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
39252
|
+
Button,
|
|
39253
|
+
{
|
|
39254
|
+
variant: "chip",
|
|
39255
|
+
disabled: issue.readonly,
|
|
39256
|
+
onClick: () => onRemoveTag(issue.id, tag.id),
|
|
39257
|
+
title: "Remove tag",
|
|
39258
|
+
style: { color: tag.color },
|
|
39259
|
+
children: [
|
|
39260
|
+
tag.name,
|
|
39261
|
+
" ",
|
|
39262
|
+
!issue.readonly && "\xD7"
|
|
39263
|
+
]
|
|
39264
|
+
},
|
|
39265
|
+
tag.id
|
|
39266
|
+
)) }),
|
|
39267
|
+
addingTag && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChipRow, { children: availableTags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
39268
|
+
Button,
|
|
39269
|
+
{
|
|
39270
|
+
variant: "chip",
|
|
39271
|
+
disabled: issue.readonly,
|
|
39272
|
+
onClick: () => onAddTag(issue.id, tag.name),
|
|
39273
|
+
title: "Add existing tag",
|
|
39274
|
+
style: { color: tag.color, opacity: 0.55 },
|
|
39275
|
+
children: [
|
|
39276
|
+
"+ ",
|
|
39277
|
+
tag.name
|
|
39278
|
+
]
|
|
39279
|
+
},
|
|
39280
|
+
tag.id
|
|
39281
|
+
)) }),
|
|
39282
|
+
addingTag && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(AddRow, { children: [
|
|
39283
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39284
|
+
Input,
|
|
39285
|
+
{
|
|
39286
|
+
value: tagName,
|
|
39287
|
+
autoFocus: true,
|
|
39288
|
+
placeholder: "tag name",
|
|
39289
|
+
onChange: (event) => setTagName(event.target.value),
|
|
39290
|
+
onKeyDown: (event) => {
|
|
39291
|
+
if (event.key === "Enter") addTag();
|
|
39292
|
+
if (event.key === "Escape") {
|
|
39293
|
+
setTagName("");
|
|
39294
|
+
setAddingTag(false);
|
|
39295
|
+
}
|
|
39296
|
+
}
|
|
39297
|
+
}
|
|
39298
|
+
),
|
|
39299
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { onClick: addTag, children: "add" })
|
|
39300
|
+
] })
|
|
39301
|
+
]
|
|
39302
|
+
}
|
|
39303
|
+
),
|
|
39304
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
39305
|
+
Section,
|
|
39306
|
+
{
|
|
39307
|
+
title: "Assignees",
|
|
39308
|
+
action: !issue.readonly && !addingAssignee && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39088
39309
|
Button,
|
|
39089
39310
|
{
|
|
39090
|
-
variant: "
|
|
39091
|
-
|
|
39092
|
-
|
|
39093
|
-
|
|
39094
|
-
|
|
39095
|
-
children:
|
|
39096
|
-
|
|
39097
|
-
|
|
39098
|
-
" ",
|
|
39099
|
-
!issue.readonly && "\xD7"
|
|
39100
|
-
]
|
|
39101
|
-
},
|
|
39102
|
-
assignee.id
|
|
39103
|
-
)) }),
|
|
39104
|
-
addingAssignee && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChipRow, { children: availableAssignees.map((assignee) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
39311
|
+
variant: "ghost",
|
|
39312
|
+
onClick: () => {
|
|
39313
|
+
setAddingAssignee(true);
|
|
39314
|
+
onOpenAssigneePicker();
|
|
39315
|
+
},
|
|
39316
|
+
children: "+"
|
|
39317
|
+
}
|
|
39318
|
+
) || addingAssignee && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39105
39319
|
Button,
|
|
39106
39320
|
{
|
|
39107
|
-
variant: "
|
|
39108
|
-
|
|
39109
|
-
|
|
39110
|
-
|
|
39111
|
-
|
|
39112
|
-
|
|
39113
|
-
|
|
39114
|
-
|
|
39115
|
-
]
|
|
39116
|
-
},
|
|
39117
|
-
assignee.id
|
|
39118
|
-
)) }),
|
|
39119
|
-
addingAssignee && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(AddRow, { children: [
|
|
39120
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
39121
|
-
Input,
|
|
39321
|
+
variant: "ghost",
|
|
39322
|
+
onClick: () => setAddingAssignee(false),
|
|
39323
|
+
children: "-"
|
|
39324
|
+
}
|
|
39325
|
+
),
|
|
39326
|
+
children: [
|
|
39327
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChipRow, { children: issue.assignees.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Empty, { children: "No assignees" }) : issue.assignees.map((assignee) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
39328
|
+
Button,
|
|
39122
39329
|
{
|
|
39123
|
-
|
|
39124
|
-
|
|
39125
|
-
|
|
39126
|
-
|
|
39127
|
-
|
|
39128
|
-
|
|
39129
|
-
|
|
39130
|
-
|
|
39131
|
-
|
|
39330
|
+
variant: "chip",
|
|
39331
|
+
disabled: issue.readonly,
|
|
39332
|
+
onClick: () => onRemoveAssignee(issue.id, assignee.id),
|
|
39333
|
+
title: "Remove assignee",
|
|
39334
|
+
style: { color: assignee.color },
|
|
39335
|
+
children: [
|
|
39336
|
+
"@",
|
|
39337
|
+
assignee.name,
|
|
39338
|
+
" ",
|
|
39339
|
+
!issue.readonly && "\xD7"
|
|
39340
|
+
]
|
|
39341
|
+
},
|
|
39342
|
+
assignee.id
|
|
39343
|
+
)) }),
|
|
39344
|
+
addingAssignee && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChipRow, { children: availableAssignees.map((assignee) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
39345
|
+
Button,
|
|
39346
|
+
{
|
|
39347
|
+
variant: "chip",
|
|
39348
|
+
disabled: issue.readonly,
|
|
39349
|
+
onClick: () => onAddAssignee(issue.id, assignee.id),
|
|
39350
|
+
title: assignee.isSelf ? "Assign yourself" : !assignee.hasAuthoredAnywhere ? "Has not contributed to this project" : "Add existing assignee",
|
|
39351
|
+
style: {
|
|
39352
|
+
color: assignee.isSelf ? GUI_THEME.accent : assignee.color,
|
|
39353
|
+
opacity: assignee.isSelf ? 1 : 0.55,
|
|
39354
|
+
fontWeight: assignee.isSelf ? 600 : void 0,
|
|
39355
|
+
borderColor: assignee.isSelf ? GUI_THEME.accent : void 0
|
|
39356
|
+
},
|
|
39357
|
+
children: [
|
|
39358
|
+
"+ @",
|
|
39359
|
+
assignee.isSelf ? "me" : assignee.name,
|
|
39360
|
+
!assignee.hasAuthoredAnywhere ? " \u2197" : ""
|
|
39361
|
+
]
|
|
39362
|
+
},
|
|
39363
|
+
assignee.id
|
|
39364
|
+
)) }),
|
|
39365
|
+
addingAssignee && assignees.some(
|
|
39366
|
+
(a) => !a.hasAuthoredAnywhere && !a.isRemoved
|
|
39367
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChipRow, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39368
|
+
Button,
|
|
39369
|
+
{
|
|
39370
|
+
variant: "ghost",
|
|
39371
|
+
disabled: issue.readonly,
|
|
39372
|
+
onClick: () => setManagingContributors(true),
|
|
39373
|
+
title: "Review and remove external contributors across the whole workspace",
|
|
39374
|
+
children: "manage contributors\u2026"
|
|
39375
|
+
}
|
|
39376
|
+
) }),
|
|
39377
|
+
addingAssignee && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(AddRow, { children: [
|
|
39378
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39379
|
+
Input,
|
|
39380
|
+
{
|
|
39381
|
+
value: assigneeName,
|
|
39382
|
+
autoFocus: true,
|
|
39383
|
+
placeholder: "name of unknown contributor",
|
|
39384
|
+
onChange: (event) => setAssigneeName(event.target.value),
|
|
39385
|
+
onKeyDown: (event) => {
|
|
39386
|
+
if (event.key === "Enter") addAssignee();
|
|
39387
|
+
if (event.key === "Escape") {
|
|
39388
|
+
setAssigneeName("");
|
|
39389
|
+
setAddingAssignee(false);
|
|
39390
|
+
}
|
|
39132
39391
|
}
|
|
39133
39392
|
}
|
|
39134
|
-
|
|
39135
|
-
|
|
39136
|
-
|
|
39137
|
-
|
|
39138
|
-
|
|
39139
|
-
|
|
39140
|
-
|
|
39141
|
-
|
|
39142
|
-
|
|
39393
|
+
),
|
|
39394
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39395
|
+
Button,
|
|
39396
|
+
{
|
|
39397
|
+
onClick: addAssignee,
|
|
39398
|
+
title: "Add someone who has not contributed to this board",
|
|
39399
|
+
children: "add"
|
|
39400
|
+
}
|
|
39401
|
+
)
|
|
39402
|
+
] })
|
|
39403
|
+
]
|
|
39404
|
+
}
|
|
39405
|
+
),
|
|
39406
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39407
|
+
IssueAttachments,
|
|
39408
|
+
{
|
|
39409
|
+
issueId: issue.id,
|
|
39410
|
+
readonly: Boolean(issue.readonly),
|
|
39411
|
+
attachments,
|
|
39412
|
+
uploadStatus: attachmentUploadStatus,
|
|
39413
|
+
onUploadFiles: onUploadAttachments,
|
|
39414
|
+
onDeleteAttachment
|
|
39415
|
+
}
|
|
39416
|
+
),
|
|
39417
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39418
|
+
Section,
|
|
39419
|
+
{
|
|
39420
|
+
title: "Actions",
|
|
39421
|
+
action: !issue.readonly && (issue.isClosed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { onClick: () => onReopenIssue(issue.id), children: "reopen issue" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Button, { onClick: () => onCloseIssue(issue.id), children: "close issue" })),
|
|
39422
|
+
children: ""
|
|
39423
|
+
}
|
|
39424
|
+
)
|
|
39425
|
+
] }),
|
|
39426
|
+
activeTab === "comments" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39427
|
+
IssueComments,
|
|
39143
39428
|
{
|
|
39429
|
+
whoAmI,
|
|
39144
39430
|
issueId: issue.id,
|
|
39145
|
-
readonly:
|
|
39146
|
-
|
|
39147
|
-
|
|
39148
|
-
|
|
39149
|
-
onDeleteAttachment
|
|
39150
|
-
}
|
|
39151
|
-
),
|
|
39152
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
39153
|
-
Section,
|
|
39154
|
-
{
|
|
39155
|
-
title: "Actions",
|
|
39156
|
-
action: issue.isClosed ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: () => onReopenIssue(issue.id), children: "reopen issue" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: () => onCloseIssue(issue.id), children: "close issue" }),
|
|
39157
|
-
children: ""
|
|
39431
|
+
readonly: issue.readonly,
|
|
39432
|
+
comments,
|
|
39433
|
+
onAddComment,
|
|
39434
|
+
onDeleteComment
|
|
39158
39435
|
}
|
|
39159
39436
|
)
|
|
39160
|
-
] }),
|
|
39161
|
-
|
|
39162
|
-
|
|
39437
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Empty, { children: "Select an issue" }),
|
|
39438
|
+
managingContributors && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
39439
|
+
ManageContributorsModal,
|
|
39163
39440
|
{
|
|
39164
|
-
|
|
39165
|
-
|
|
39166
|
-
|
|
39167
|
-
comments,
|
|
39168
|
-
onAddComment,
|
|
39169
|
-
onDeleteComment
|
|
39441
|
+
contributors: assignees,
|
|
39442
|
+
onRemove: onRemoveContributor,
|
|
39443
|
+
onClose: () => setManagingContributors(false)
|
|
39170
39444
|
}
|
|
39171
39445
|
)
|
|
39172
|
-
] })
|
|
39446
|
+
] });
|
|
39173
39447
|
};
|
|
39174
39448
|
|
|
39175
39449
|
// source/gui/client/components/SwimlaneColumn.tsx
|
|
39176
|
-
var
|
|
39450
|
+
var import_react11 = __toESM(require_react(), 1);
|
|
39177
39451
|
|
|
39178
39452
|
// source/gui/client/components/IconComment.tsx
|
|
39179
|
-
var
|
|
39180
|
-
var IconComment = ({ size = 16 }) => /* @__PURE__ */ (0,
|
|
39453
|
+
var import_jsx_runtime21 = __toESM(require_jsx_runtime(), 1);
|
|
39454
|
+
var IconComment = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
39181
39455
|
"svg",
|
|
39182
39456
|
{
|
|
39183
39457
|
width: size,
|
|
@@ -39185,7 +39459,7 @@ var IconComment = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime18.js
|
|
|
39185
39459
|
viewBox: "0 0 16 16",
|
|
39186
39460
|
fill: "none",
|
|
39187
39461
|
"aria-hidden": "true",
|
|
39188
|
-
children: /* @__PURE__ */ (0,
|
|
39462
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
39189
39463
|
"path",
|
|
39190
39464
|
{
|
|
39191
39465
|
d: "M3.9 2.6h5.2a2.4 2.4 0 0 1 2.4 2.4v2.5a2.4 2.4 0 0 1-2.4 2.4H6.6l-1.8 2.1.2-2.1H3.9a2.4 2.4 0 0 1-2.4-2.4V5a2.4 2.4 0 0 1 2.4-2.4Z",
|
|
@@ -39200,7 +39474,7 @@ var IconComment = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime18.js
|
|
|
39200
39474
|
);
|
|
39201
39475
|
|
|
39202
39476
|
// source/gui/client/components/TicketCard.tsx
|
|
39203
|
-
var
|
|
39477
|
+
var import_jsx_runtime22 = __toESM(require_jsx_runtime(), 1);
|
|
39204
39478
|
var TicketCard = ({
|
|
39205
39479
|
ticket,
|
|
39206
39480
|
index: index2,
|
|
@@ -39213,7 +39487,7 @@ var TicketCard = ({
|
|
|
39213
39487
|
onDropIssueAt
|
|
39214
39488
|
}) => {
|
|
39215
39489
|
const getVisualTargetIndex = (isAfterMiddle) => index2 + (isAfterMiddle ? 1 : 0);
|
|
39216
|
-
return /* @__PURE__ */ (0,
|
|
39490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
39217
39491
|
"div",
|
|
39218
39492
|
{
|
|
39219
39493
|
draggable: !ticket.readonly,
|
|
@@ -39254,7 +39528,7 @@ var TicketCard = ({
|
|
|
39254
39528
|
border: `1px solid ${isSelected ? GUI_THEME.accent : "transparent"}`
|
|
39255
39529
|
},
|
|
39256
39530
|
children: [
|
|
39257
|
-
/* @__PURE__ */ (0,
|
|
39531
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39258
39532
|
"div",
|
|
39259
39533
|
{
|
|
39260
39534
|
style: {
|
|
@@ -39268,7 +39542,7 @@ var TicketCard = ({
|
|
|
39268
39542
|
children: isSelected ? "\u276F" : index2 + 1
|
|
39269
39543
|
}
|
|
39270
39544
|
),
|
|
39271
|
-
/* @__PURE__ */ (0,
|
|
39545
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
39272
39546
|
"div",
|
|
39273
39547
|
{
|
|
39274
39548
|
style: {
|
|
@@ -39280,7 +39554,7 @@ var TicketCard = ({
|
|
|
39280
39554
|
paddingLeft: 8
|
|
39281
39555
|
},
|
|
39282
39556
|
children: [
|
|
39283
|
-
/* @__PURE__ */ (0,
|
|
39557
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
39284
39558
|
"div",
|
|
39285
39559
|
{
|
|
39286
39560
|
style: {
|
|
@@ -39291,7 +39565,7 @@ var TicketCard = ({
|
|
|
39291
39565
|
flex: 1
|
|
39292
39566
|
},
|
|
39293
39567
|
children: [
|
|
39294
|
-
/* @__PURE__ */ (0,
|
|
39568
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39295
39569
|
"div",
|
|
39296
39570
|
{
|
|
39297
39571
|
style: {
|
|
@@ -39307,17 +39581,17 @@ var TicketCard = ({
|
|
|
39307
39581
|
children: ticket.title
|
|
39308
39582
|
}
|
|
39309
39583
|
),
|
|
39310
|
-
ticket.ref && /* @__PURE__ */ (0,
|
|
39584
|
+
ticket.ref && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39311
39585
|
"div",
|
|
39312
39586
|
{
|
|
39313
39587
|
style: {
|
|
39314
39588
|
color: GUI_THEME.dim2,
|
|
39315
39589
|
fontSize: 10
|
|
39316
39590
|
},
|
|
39317
|
-
children: /* @__PURE__ */ (0,
|
|
39591
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CopyRef, { refValue: ticket.ref })
|
|
39318
39592
|
}
|
|
39319
39593
|
),
|
|
39320
|
-
/* @__PURE__ */ (0,
|
|
39594
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39321
39595
|
"div",
|
|
39322
39596
|
{
|
|
39323
39597
|
style: {
|
|
@@ -39326,7 +39600,7 @@ var TicketCard = ({
|
|
|
39326
39600
|
gap: 6,
|
|
39327
39601
|
alignItems: "center"
|
|
39328
39602
|
},
|
|
39329
|
-
children: ticket.tags.map((tag) => /* @__PURE__ */ (0,
|
|
39603
|
+
children: ticket.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39330
39604
|
"span",
|
|
39331
39605
|
{
|
|
39332
39606
|
style: {
|
|
@@ -39346,7 +39620,7 @@ var TicketCard = ({
|
|
|
39346
39620
|
]
|
|
39347
39621
|
}
|
|
39348
39622
|
),
|
|
39349
|
-
/* @__PURE__ */ (0,
|
|
39623
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39350
39624
|
"div",
|
|
39351
39625
|
{
|
|
39352
39626
|
style: {
|
|
@@ -39356,7 +39630,7 @@ var TicketCard = ({
|
|
|
39356
39630
|
flexShrink: 0,
|
|
39357
39631
|
paddingTop: 2
|
|
39358
39632
|
},
|
|
39359
|
-
children: commentCount > 0 && /* @__PURE__ */ (0,
|
|
39633
|
+
children: commentCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
39360
39634
|
"button",
|
|
39361
39635
|
{
|
|
39362
39636
|
type: "button",
|
|
@@ -39394,14 +39668,14 @@ var TicketCard = ({
|
|
|
39394
39668
|
event.currentTarget.style.transform = "translateY(0)";
|
|
39395
39669
|
},
|
|
39396
39670
|
children: [
|
|
39397
|
-
/* @__PURE__ */ (0,
|
|
39398
|
-
/* @__PURE__ */ (0,
|
|
39671
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(IconComment, {}),
|
|
39672
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: commentCount })
|
|
39399
39673
|
]
|
|
39400
39674
|
}
|
|
39401
39675
|
)
|
|
39402
39676
|
}
|
|
39403
39677
|
),
|
|
39404
|
-
ticket.assignees.length > 0 && /* @__PURE__ */ (0,
|
|
39678
|
+
ticket.assignees.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
39405
39679
|
"div",
|
|
39406
39680
|
{
|
|
39407
39681
|
style: {
|
|
@@ -39411,7 +39685,7 @@ var TicketCard = ({
|
|
|
39411
39685
|
paddingTop: 2,
|
|
39412
39686
|
marginTop: "-4px"
|
|
39413
39687
|
},
|
|
39414
|
-
children: ticket.assignees.map((assignee, idx) => /* @__PURE__ */ (0,
|
|
39688
|
+
children: ticket.assignees.map((assignee, idx) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(User, { user: assignee, index: idx, isFocus: isSelected }))
|
|
39415
39689
|
}
|
|
39416
39690
|
)
|
|
39417
39691
|
]
|
|
@@ -39423,7 +39697,10 @@ var TicketCard = ({
|
|
|
39423
39697
|
};
|
|
39424
39698
|
|
|
39425
39699
|
// source/gui/client/components/SwimlaneColumn.tsx
|
|
39426
|
-
var
|
|
39700
|
+
var import_jsx_runtime23 = __toESM(require_jsx_runtime(), 1);
|
|
39701
|
+
var COLUMN_GLOW_COLOR = "rgb(140, 176, 232)";
|
|
39702
|
+
var COLUMN_PADDING = 14;
|
|
39703
|
+
var SCROLLBAR_GUTTER_INSET = COLUMN_PADDING / 2;
|
|
39427
39704
|
var SwimlaneColumn = ({
|
|
39428
39705
|
swimlane,
|
|
39429
39706
|
selected,
|
|
@@ -39439,20 +39716,27 @@ var SwimlaneColumn = ({
|
|
|
39439
39716
|
onDragOverIssue,
|
|
39440
39717
|
onDragLeave
|
|
39441
39718
|
}) => {
|
|
39442
|
-
return /* @__PURE__ */ (0,
|
|
39719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
39443
39720
|
Panel,
|
|
39444
39721
|
{
|
|
39445
39722
|
as: "section",
|
|
39446
39723
|
active: dragOver,
|
|
39447
39724
|
borderColor: selected || dragOver ? GUI_THEME.accent : GUI_THEME.line,
|
|
39448
|
-
|
|
39725
|
+
glowColor: COLUMN_GLOW_COLOR,
|
|
39726
|
+
glowOpacity: 0.41,
|
|
39727
|
+
glowRadius: 370,
|
|
39728
|
+
proximityReach: 200,
|
|
39449
39729
|
style: {
|
|
39450
39730
|
zIndex: 0,
|
|
39451
39731
|
width: 360,
|
|
39452
39732
|
minWidth: 360,
|
|
39453
|
-
|
|
39733
|
+
// Fills the board row rather than guessing at the chrome above with a
|
|
39734
|
+
// viewport calc; the scrubber's height changes as it is used.
|
|
39735
|
+
height: "100%",
|
|
39736
|
+
// Panel's 1px border would otherwise add to the 100% and overflow the row.
|
|
39737
|
+
boxSizing: "border-box",
|
|
39454
39738
|
background: dragOver ? "#14202a" : GUI_THEME.bg,
|
|
39455
|
-
padding:
|
|
39739
|
+
padding: `0 ${COLUMN_PADDING}px`,
|
|
39456
39740
|
display: "flex",
|
|
39457
39741
|
flexDirection: "column"
|
|
39458
39742
|
},
|
|
@@ -39479,7 +39763,7 @@ var SwimlaneColumn = ({
|
|
|
39479
39763
|
onDragLeave();
|
|
39480
39764
|
},
|
|
39481
39765
|
children: [
|
|
39482
|
-
/* @__PURE__ */ (0,
|
|
39766
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
39483
39767
|
"header",
|
|
39484
39768
|
{
|
|
39485
39769
|
style: {
|
|
@@ -39491,7 +39775,7 @@ var SwimlaneColumn = ({
|
|
|
39491
39775
|
alignItems: "center"
|
|
39492
39776
|
},
|
|
39493
39777
|
children: [
|
|
39494
|
-
/* @__PURE__ */ (0,
|
|
39778
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
39495
39779
|
"div",
|
|
39496
39780
|
{
|
|
39497
39781
|
style: {
|
|
@@ -39500,30 +39784,37 @@ var SwimlaneColumn = ({
|
|
|
39500
39784
|
gap: 8
|
|
39501
39785
|
},
|
|
39502
39786
|
children: [
|
|
39503
|
-
/* @__PURE__ */ (0,
|
|
39787
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39504
39788
|
"span",
|
|
39505
39789
|
{
|
|
39506
39790
|
style: { color: selected ? GUI_THEME.accent : GUI_THEME.secondary },
|
|
39507
39791
|
children: selected ? "\u276F" : " "
|
|
39508
39792
|
}
|
|
39509
39793
|
),
|
|
39510
|
-
/* @__PURE__ */ (0,
|
|
39794
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39511
39795
|
"strong",
|
|
39512
39796
|
{
|
|
39513
39797
|
style: { color: selected ? GUI_THEME.accent : GUI_THEME.primary },
|
|
39514
39798
|
children: swimlane.title
|
|
39515
39799
|
}
|
|
39516
39800
|
),
|
|
39517
|
-
/* @__PURE__ */ (0,
|
|
39801
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { style: { color: GUI_THEME.dim }, children: [
|
|
39518
39802
|
"(",
|
|
39519
39803
|
swimlane.issues.length,
|
|
39520
39804
|
")"
|
|
39521
39805
|
] }),
|
|
39522
|
-
swimlane.readonly && /* @__PURE__ */ (0,
|
|
39806
|
+
swimlane.readonly && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39807
|
+
"span",
|
|
39808
|
+
{
|
|
39809
|
+
title: "Read-only",
|
|
39810
|
+
style: { display: "flex", color: GUI_THEME.dim },
|
|
39811
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(IconLock, {})
|
|
39812
|
+
}
|
|
39813
|
+
)
|
|
39523
39814
|
]
|
|
39524
39815
|
}
|
|
39525
39816
|
),
|
|
39526
|
-
/* @__PURE__ */ (0,
|
|
39817
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39527
39818
|
Button,
|
|
39528
39819
|
{
|
|
39529
39820
|
variant: "ghost",
|
|
@@ -39536,48 +39827,1602 @@ var SwimlaneColumn = ({
|
|
|
39536
39827
|
]
|
|
39537
39828
|
}
|
|
39538
39829
|
),
|
|
39539
|
-
/* @__PURE__ */ (0,
|
|
39540
|
-
|
|
39541
|
-
|
|
39542
|
-
|
|
39543
|
-
|
|
39544
|
-
|
|
39545
|
-
|
|
39546
|
-
|
|
39547
|
-
|
|
39548
|
-
|
|
39549
|
-
|
|
39550
|
-
|
|
39551
|
-
|
|
39552
|
-
|
|
39553
|
-
|
|
39554
|
-
|
|
39555
|
-
|
|
39556
|
-
|
|
39557
|
-
|
|
39558
|
-
|
|
39559
|
-
|
|
39560
|
-
|
|
39561
|
-
|
|
39562
|
-
onSelect: () => onSelectIssue(ticket.id),
|
|
39563
|
-
onDragStart: (issueId) => onSelectIssue(issueId),
|
|
39564
|
-
onOpenComments: onSelectIssueComments,
|
|
39565
|
-
commentCount: commentsByIssueId[ticket.id].length ?? 0,
|
|
39566
|
-
onDragOverIssue: (targetIndex) => onDragOverIssue(swimlane.id, targetIndex),
|
|
39567
|
-
onDropIssueAt: (issueId, targetIndex) => {
|
|
39568
|
-
onDropIssue(issueId, swimlane.id, targetIndex);
|
|
39569
|
-
onDragLeave();
|
|
39830
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39831
|
+
"div",
|
|
39832
|
+
{
|
|
39833
|
+
style: {
|
|
39834
|
+
overflow: "auto",
|
|
39835
|
+
paddingTop: 4,
|
|
39836
|
+
marginRight: -SCROLLBAR_GUTTER_INSET,
|
|
39837
|
+
paddingRight: SCROLLBAR_GUTTER_INSET,
|
|
39838
|
+
flex: 1,
|
|
39839
|
+
minHeight: 0
|
|
39840
|
+
},
|
|
39841
|
+
children: swimlane.issues.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
39842
|
+
dropIndex === 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DropIndicator, {}),
|
|
39843
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39844
|
+
"div",
|
|
39845
|
+
{
|
|
39846
|
+
style: {
|
|
39847
|
+
padding: 24,
|
|
39848
|
+
textAlign: "center",
|
|
39849
|
+
color: GUI_THEME.dim,
|
|
39850
|
+
fontSize: 12
|
|
39851
|
+
},
|
|
39852
|
+
children: "Drop issue here"
|
|
39570
39853
|
}
|
|
39571
|
-
|
|
39572
|
-
)
|
|
39573
|
-
|
|
39574
|
-
|
|
39575
|
-
|
|
39854
|
+
)
|
|
39855
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
39856
|
+
swimlane.issues.map((ticket, index2) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react11.default.Fragment, { children: [
|
|
39857
|
+
dropIndex === index2 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DropIndicator, {}),
|
|
39858
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
39859
|
+
TicketCard,
|
|
39860
|
+
{
|
|
39861
|
+
ticket,
|
|
39862
|
+
index: index2,
|
|
39863
|
+
isSelected: ticket.id === selectedIssueId,
|
|
39864
|
+
onSelect: () => onSelectIssue(ticket.id),
|
|
39865
|
+
onDragStart: (issueId) => onSelectIssue(issueId),
|
|
39866
|
+
onOpenComments: onSelectIssueComments,
|
|
39867
|
+
commentCount: commentsByIssueId[ticket.id]?.length ?? 0,
|
|
39868
|
+
onDragOverIssue: (targetIndex) => onDragOverIssue(swimlane.id, targetIndex),
|
|
39869
|
+
onDropIssueAt: (issueId, targetIndex) => {
|
|
39870
|
+
onDropIssue(issueId, swimlane.id, targetIndex);
|
|
39871
|
+
onDragLeave();
|
|
39872
|
+
}
|
|
39873
|
+
}
|
|
39874
|
+
)
|
|
39875
|
+
] }, ticket.id)),
|
|
39876
|
+
dropIndex === swimlane.issues.length && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DropIndicator, {})
|
|
39877
|
+
] })
|
|
39878
|
+
}
|
|
39879
|
+
)
|
|
39880
|
+
]
|
|
39881
|
+
}
|
|
39882
|
+
);
|
|
39883
|
+
};
|
|
39884
|
+
|
|
39885
|
+
// source/gui/client/components/GlobalScrollbarStyles.tsx
|
|
39886
|
+
var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1);
|
|
39887
|
+
var SCROLLBAR_SIZE = 3;
|
|
39888
|
+
var GlobalScrollbarStyles = () => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("style", { children: `
|
|
39889
|
+
/* Gated deliberately: Chrome implements scrollbar-width/-color too, and
|
|
39890
|
+
setting either makes it ignore the ::-webkit-scrollbar rules below. */
|
|
39891
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
39892
|
+
* {
|
|
39893
|
+
scrollbar-width: thin;
|
|
39894
|
+
scrollbar-color: ${GUI_THEME.dim} transparent;
|
|
39895
|
+
}
|
|
39896
|
+
}
|
|
39897
|
+
|
|
39898
|
+
::-webkit-scrollbar {
|
|
39899
|
+
width: ${SCROLLBAR_SIZE}px;
|
|
39900
|
+
height: ${SCROLLBAR_SIZE}px;
|
|
39901
|
+
}
|
|
39902
|
+
|
|
39903
|
+
/* Transparent, or the track draws a permanent stripe down every edge. */
|
|
39904
|
+
::-webkit-scrollbar-track {
|
|
39905
|
+
background: transparent;
|
|
39906
|
+
}
|
|
39907
|
+
|
|
39908
|
+
::-webkit-scrollbar-thumb {
|
|
39909
|
+
background: ${GUI_THEME.dim};
|
|
39910
|
+
border-radius: 999px;
|
|
39911
|
+
/* Insets the thumb below the track's hit target; 2px here would leave
|
|
39912
|
+
it 2px wide and lost against the panel. */
|
|
39913
|
+
border: 1px solid transparent;
|
|
39914
|
+
background-clip: content-box;
|
|
39915
|
+
}
|
|
39916
|
+
|
|
39917
|
+
::-webkit-scrollbar-thumb:hover {
|
|
39918
|
+
background: ${GUI_THEME.secondary};
|
|
39919
|
+
background-clip: content-box;
|
|
39920
|
+
}
|
|
39921
|
+
|
|
39922
|
+
/* Unpainted, or the corner shows as a lighter square. */
|
|
39923
|
+
::-webkit-scrollbar-corner {
|
|
39924
|
+
background: transparent;
|
|
39925
|
+
}
|
|
39926
|
+
` });
|
|
39927
|
+
|
|
39928
|
+
// source/gui/client/components/ErrorToast.tsx
|
|
39929
|
+
var import_jsx_runtime25 = __toESM(require_jsx_runtime(), 1);
|
|
39930
|
+
var ErrorToast = ({ message, onDismiss }) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
39931
|
+
"div",
|
|
39932
|
+
{
|
|
39933
|
+
style: {
|
|
39934
|
+
position: "fixed",
|
|
39935
|
+
bottom: 20,
|
|
39936
|
+
right: 20,
|
|
39937
|
+
zIndex: 1e3,
|
|
39938
|
+
maxWidth: 360,
|
|
39939
|
+
display: "flex",
|
|
39940
|
+
alignItems: "flex-start",
|
|
39941
|
+
gap: 8,
|
|
39942
|
+
fontSize: 12,
|
|
39943
|
+
color: GUI_THEME.primary,
|
|
39944
|
+
background: GUI_THEME.panel,
|
|
39945
|
+
border: `1px solid ${GUI_THEME.red}`,
|
|
39946
|
+
borderRadius: 8,
|
|
39947
|
+
padding: "10px 12px",
|
|
39948
|
+
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.4)"
|
|
39949
|
+
},
|
|
39950
|
+
children: [
|
|
39951
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { flex: 1, minWidth: 0, overflowWrap: "anywhere" }, children: message }),
|
|
39952
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
39953
|
+
"button",
|
|
39954
|
+
{
|
|
39955
|
+
onClick: onDismiss,
|
|
39956
|
+
style: {
|
|
39957
|
+
background: "transparent",
|
|
39958
|
+
border: "none",
|
|
39959
|
+
color: GUI_THEME.dim,
|
|
39960
|
+
cursor: "pointer",
|
|
39961
|
+
fontSize: 14,
|
|
39962
|
+
lineHeight: 1,
|
|
39963
|
+
padding: 0
|
|
39964
|
+
},
|
|
39965
|
+
children: "\xD7"
|
|
39966
|
+
}
|
|
39967
|
+
)
|
|
39968
|
+
]
|
|
39969
|
+
}
|
|
39970
|
+
);
|
|
39971
|
+
|
|
39972
|
+
// source/gui/client/components/TimeScrubber.tsx
|
|
39973
|
+
var import_react14 = __toESM(require_react(), 1);
|
|
39974
|
+
|
|
39975
|
+
// source/lib/utils/date.utils.ts
|
|
39976
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
39977
|
+
var formatDateTime = (date) => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
39978
|
+
var formatTimeOfDay = (date) => `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
39979
|
+
var isSameDay = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
39980
|
+
|
|
39981
|
+
// source/lib/utils/minmax.ts
|
|
39982
|
+
var minOf = (values, seed) => values.reduce((min, value) => value < min ? value : min, seed);
|
|
39983
|
+
var maxOf = (values, seed) => values.reduce((max, value) => value > max ? value : max, seed);
|
|
39984
|
+
|
|
39985
|
+
// source/gui/client/lib/scrubber.ts
|
|
39986
|
+
var import_react12 = __toESM(require_react(), 1);
|
|
39987
|
+
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
39988
|
+
var TRACK_HEIGHT = 24;
|
|
39989
|
+
var EVENTS_MODE_TOTAL_HEIGHT = 8 + TRACK_HEIGHT * 2;
|
|
39990
|
+
var EVENTS_SCATTER_HEIGHT = TRACK_HEIGHT + 16;
|
|
39991
|
+
var EVENTS_MODE_VERTICAL_PADDING = (EVENTS_MODE_TOTAL_HEIGHT - EVENTS_SCATTER_HEIGHT) / 2;
|
|
39992
|
+
var HOVER_HINT_WIDTH = 220;
|
|
39993
|
+
var SEGMENT_HIGHLIGHT_COLOR = "rgba(122, 158, 214, 0.07)";
|
|
39994
|
+
var BUCKET_HIGHLIGHT_COLOR = "rgba(255, 255, 255, 0.06)";
|
|
39995
|
+
var NEEDLE_COLOR = "rgba(255, 255, 255, 0.62)";
|
|
39996
|
+
var MIN_BUCKET_COUNT_FOR_GAP = 300;
|
|
39997
|
+
var barWidthCss = (bucketCount) => bucketCount < MIN_BUCKET_COUNT_FOR_GAP ? `calc(${100 / bucketCount}% - 1px)` : `${100 / bucketCount}%`;
|
|
39998
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
39999
|
+
var MIN_TIME_BUCKETS = 60;
|
|
40000
|
+
var MAX_TIME_BUCKETS = 900;
|
|
40001
|
+
var bucketCountForSpan = (spanMs) => {
|
|
40002
|
+
const days = Math.max(1, spanMs / DAY_MS);
|
|
40003
|
+
return Math.round(
|
|
40004
|
+
clamp(116.5 * Math.pow(days, 0.3265), MIN_TIME_BUCKETS, MAX_TIME_BUCKETS)
|
|
40005
|
+
);
|
|
40006
|
+
};
|
|
40007
|
+
var buildAxis = (timeline, commits, now = Date.now()) => {
|
|
40008
|
+
const commitBounds = commits.length ? commits.map((c) => c.time) : [now];
|
|
40009
|
+
const earliest = minOf(
|
|
40010
|
+
commitBounds,
|
|
40011
|
+
timeline?.buckets[0]?.t ?? timeline?.earliest ?? now
|
|
40012
|
+
);
|
|
40013
|
+
const latest = maxOf(commitBounds, timeline?.latest ?? now);
|
|
40014
|
+
const span = Math.max(1, latest - earliest);
|
|
40015
|
+
const bucketCount = bucketCountForSpan(span);
|
|
40016
|
+
const bucketMs = span / bucketCount;
|
|
40017
|
+
return {
|
|
40018
|
+
earliest,
|
|
40019
|
+
latest,
|
|
40020
|
+
span,
|
|
40021
|
+
bucketCount,
|
|
40022
|
+
bucketMs,
|
|
40023
|
+
bucketIndexForTime: (time) => clamp(Math.floor((time - earliest) / bucketMs), 0, bucketCount - 1),
|
|
40024
|
+
bucketTimeAt: (index2) => earliest + index2 * bucketMs,
|
|
40025
|
+
fractionForTime: (time) => clamp((time - earliest) / span, 0, 1),
|
|
40026
|
+
fractionToTime: (fraction) => Math.round(earliest + clamp(fraction, 0, 1) * span)
|
|
40027
|
+
};
|
|
40028
|
+
};
|
|
40029
|
+
var bucketIssueCounts = (axis, timeline) => {
|
|
40030
|
+
const counts = new Array(axis.bucketCount).fill(0);
|
|
40031
|
+
for (const sparseBucket of timeline?.buckets ?? []) {
|
|
40032
|
+
counts[axis.bucketIndexForTime(sparseBucket.t)] += sparseBucket.count;
|
|
40033
|
+
}
|
|
40034
|
+
return counts;
|
|
40035
|
+
};
|
|
40036
|
+
var bucketCommitStats = (axis, commits) => {
|
|
40037
|
+
const byIndex = /* @__PURE__ */ new Map();
|
|
40038
|
+
for (const commit of commits) {
|
|
40039
|
+
const index2 = axis.bucketIndexForTime(commit.time);
|
|
40040
|
+
const existing = byIndex.get(index2) ?? { count: 0, linesChanged: 0 };
|
|
40041
|
+
byIndex.set(index2, {
|
|
40042
|
+
count: existing.count + 1,
|
|
40043
|
+
linesChanged: existing.linesChanged + commit.linesChanged
|
|
40044
|
+
});
|
|
40045
|
+
}
|
|
40046
|
+
return byIndex;
|
|
40047
|
+
};
|
|
40048
|
+
var populatedRange = (bars) => bars.length > 0 ? [
|
|
40049
|
+
bars.reduce((min, bar) => Math.min(min, bar.index), Infinity),
|
|
40050
|
+
bars.reduce((max, bar) => Math.max(max, bar.index), -Infinity)
|
|
40051
|
+
] : [0, 0];
|
|
40052
|
+
var hourFractionForTime = (time) => {
|
|
40053
|
+
const date = new Date(time);
|
|
40054
|
+
return (date.getHours() * 60 + date.getMinutes()) / (24 * 60);
|
|
40055
|
+
};
|
|
40056
|
+
var SEGMENT_UNIT_ORDER = ["day", "week", "month", "year"];
|
|
40057
|
+
var APPROX_UNIT_MS = {
|
|
40058
|
+
day: 24 * 60 * 60 * 1e3,
|
|
40059
|
+
week: 7 * 24 * 60 * 60 * 1e3,
|
|
40060
|
+
month: 30.44 * 24 * 60 * 60 * 1e3,
|
|
40061
|
+
year: 365.25 * 24 * 60 * 60 * 1e3
|
|
40062
|
+
};
|
|
40063
|
+
var MAX_SEGMENTS = 35;
|
|
40064
|
+
var chooseSegmentUnit = (spanMs) => SEGMENT_UNIT_ORDER.find(
|
|
40065
|
+
(unit) => spanMs / APPROX_UNIT_MS[unit] <= MAX_SEGMENTS
|
|
40066
|
+
) ?? "year";
|
|
40067
|
+
var WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
40068
|
+
var MONTH_LABELS = [
|
|
40069
|
+
"Jan",
|
|
40070
|
+
"Feb",
|
|
40071
|
+
"Mar",
|
|
40072
|
+
"Apr",
|
|
40073
|
+
"May",
|
|
40074
|
+
"Jun",
|
|
40075
|
+
"Jul",
|
|
40076
|
+
"Aug",
|
|
40077
|
+
"Sep",
|
|
40078
|
+
"Oct",
|
|
40079
|
+
"Nov",
|
|
40080
|
+
"Dec"
|
|
40081
|
+
];
|
|
40082
|
+
var advanceByUnit = (date, unit) => {
|
|
40083
|
+
if (unit === "day") date.setDate(date.getDate() + 1);
|
|
40084
|
+
else if (unit === "week") date.setDate(date.getDate() + 7);
|
|
40085
|
+
else if (unit === "month") date.setMonth(date.getMonth() + 1);
|
|
40086
|
+
else date.setFullYear(date.getFullYear() + 1);
|
|
40087
|
+
};
|
|
40088
|
+
var segmentAt = (time, unit) => {
|
|
40089
|
+
const start2 = new Date(time);
|
|
40090
|
+
start2.setHours(0, 0, 0, 0);
|
|
40091
|
+
if (unit === "week") {
|
|
40092
|
+
start2.setDate(start2.getDate() - (start2.getDay() + 6) % 7);
|
|
40093
|
+
} else if (unit === "month") {
|
|
40094
|
+
start2.setDate(1);
|
|
40095
|
+
} else if (unit === "year") {
|
|
40096
|
+
start2.setMonth(0, 1);
|
|
40097
|
+
}
|
|
40098
|
+
const end = new Date(start2);
|
|
40099
|
+
advanceByUnit(end, unit);
|
|
40100
|
+
const lastDay = new Date(end.getTime() - 1);
|
|
40101
|
+
const label = unit === "day" ? `${WEEKDAY_LABELS[start2.getDay()]} ${start2.getDate()} ${MONTH_LABELS[start2.getMonth()]}` : unit === "week" ? start2.getMonth() === lastDay.getMonth() ? `${start2.getDate()}\u2013${lastDay.getDate()} ${MONTH_LABELS[start2.getMonth()]}` : `${start2.getDate()} ${MONTH_LABELS[start2.getMonth()]} \u2013 ${lastDay.getDate()} ${MONTH_LABELS[lastDay.getMonth()]}` : unit === "month" ? `${MONTH_LABELS[start2.getMonth()]} ${start2.getFullYear()}` : `${start2.getFullYear()}`;
|
|
40102
|
+
return { start: start2.getTime(), end: end.getTime(), label };
|
|
40103
|
+
};
|
|
40104
|
+
var formatInterval = (start2, end) => {
|
|
40105
|
+
const startDate = new Date(start2);
|
|
40106
|
+
const endDate = new Date(end);
|
|
40107
|
+
const endLabel = isSameDay(startDate, endDate) ? formatTimeOfDay(endDate) : formatDateTime(endDate);
|
|
40108
|
+
return `${formatDateTime(startDate)} \u2013 ${endLabel}`;
|
|
40109
|
+
};
|
|
40110
|
+
var SCOPES = ["week", "month", "year", "all"];
|
|
40111
|
+
var SCOPE_DURATION_MS = {
|
|
40112
|
+
week: 7 * 24 * 60 * 60 * 1e3,
|
|
40113
|
+
month: 30 * 24 * 60 * 60 * 1e3,
|
|
40114
|
+
year: 365 * 24 * 60 * 60 * 1e3
|
|
40115
|
+
};
|
|
40116
|
+
var isScope = (value) => SCOPES.includes(value ?? "");
|
|
40117
|
+
var getPeriodRange = (scope, offset) => {
|
|
40118
|
+
if (scope === "all") return null;
|
|
40119
|
+
const durationMs = SCOPE_DURATION_MS[scope];
|
|
40120
|
+
const end = Date.now() - offset * durationMs;
|
|
40121
|
+
return { start: end - durationMs, end };
|
|
40122
|
+
};
|
|
40123
|
+
var formatPeriodLabel = (scope, offset, range) => {
|
|
40124
|
+
if (scope === "all" || !range) return "All time";
|
|
40125
|
+
if (offset === 0) {
|
|
40126
|
+
return scope === "week" ? "Last 7 days" : scope === "month" ? "Last 30 days" : "Last 365 days";
|
|
40127
|
+
}
|
|
40128
|
+
const start2 = new Date(range.start);
|
|
40129
|
+
const end = new Date(range.end);
|
|
40130
|
+
return `${start2.getMonth() + 1}/${start2.getDate()} \u2013 ${end.getMonth() + 1}/${end.getDate()}`;
|
|
40131
|
+
};
|
|
40132
|
+
var scopeButtonLabel = (scope) => scope === "all" ? "All" : scope[0].toUpperCase() + scope.slice(1);
|
|
40133
|
+
var hashUnitInterval = (key) => {
|
|
40134
|
+
let hash = 2166136261;
|
|
40135
|
+
for (let index2 = 0; index2 < key.length; index2++) {
|
|
40136
|
+
hash ^= key.charCodeAt(index2);
|
|
40137
|
+
hash = Math.imul(hash, 16777619);
|
|
40138
|
+
}
|
|
40139
|
+
return (hash >>> 0) % 1e4 / 1e4;
|
|
40140
|
+
};
|
|
40141
|
+
var DOT_APPEAR_MS = 260;
|
|
40142
|
+
var DOT_APPEAR_SCATTER_MS = 620;
|
|
40143
|
+
var dotDelayMs = (key) => Math.round(hashUnitInterval(key) * DOT_APPEAR_SCATTER_MS);
|
|
40144
|
+
var dotAppearAnimation = (key) => `epiqScrubberTwinkle ${DOT_APPEAR_MS}ms ease-out ${dotDelayMs(
|
|
40145
|
+
key
|
|
40146
|
+
)}ms backwards`;
|
|
40147
|
+
var dotExitAnimation = (key) => `epiqScrubberRetract ${DOT_APPEAR_MS}ms ease-in ${DOT_APPEAR_SCATTER_MS - dotDelayMs(key)}ms both`;
|
|
40148
|
+
var DOT_EXIT_TOTAL_MS = DOT_APPEAR_SCATTER_MS + DOT_APPEAR_MS;
|
|
40149
|
+
var BAR_GROW_MS = 200;
|
|
40150
|
+
var BAR_GROW_SWEEP_MS = 560;
|
|
40151
|
+
var barGrowAnimation = (index2, firstIndex, lastIndex) => {
|
|
40152
|
+
const span = lastIndex - firstIndex;
|
|
40153
|
+
const delay = span > 0 ? (index2 - firstIndex) / span * BAR_GROW_SWEEP_MS : 0;
|
|
40154
|
+
return `epiqScrubberGrow ${BAR_GROW_MS}ms ease-out ${delay.toFixed(
|
|
40155
|
+
0
|
|
40156
|
+
)}ms backwards`;
|
|
40157
|
+
};
|
|
40158
|
+
var FADE_IN_ANIMATION = "epiqScrubberFadeIn 320ms ease-out";
|
|
40159
|
+
var SCRUBBER_KEYFRAMES = `
|
|
40160
|
+
/* Must animate the standalone 'scale' property, not 'transform': the dots
|
|
40161
|
+
carry a 'transform: translate(...)' to centre themselves, and animating
|
|
40162
|
+
'transform' would replace it and fling them off position. */
|
|
40163
|
+
@keyframes epiqScrubberTwinkle {
|
|
40164
|
+
from { scale: 0; }
|
|
40165
|
+
to { scale: 1; }
|
|
40166
|
+
}
|
|
40167
|
+
|
|
40168
|
+
/* Not the twinkle reversed \u2014 see dotExitAnimation for why. */
|
|
40169
|
+
@keyframes epiqScrubberRetract {
|
|
40170
|
+
from { scale: 1; }
|
|
40171
|
+
to { scale: 0; }
|
|
40172
|
+
}
|
|
40173
|
+
|
|
40174
|
+
@keyframes epiqScrubberGrow {
|
|
40175
|
+
from { transform: scaleY(0); }
|
|
40176
|
+
to { transform: scaleY(1); }
|
|
40177
|
+
}
|
|
40178
|
+
|
|
40179
|
+
@keyframes epiqScrubberFadeIn {
|
|
40180
|
+
/* Starts faint rather than transparent: from zero the whole chart reads
|
|
40181
|
+
as blinking on a mere data refresh. */
|
|
40182
|
+
from { opacity: 0.2; }
|
|
40183
|
+
to { opacity: 1; }
|
|
40184
|
+
}
|
|
40185
|
+
`;
|
|
40186
|
+
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
40187
|
+
var usePrefersReducedMotion = () => {
|
|
40188
|
+
const [reduced, setReduced] = (0, import_react12.useState)(
|
|
40189
|
+
() => window.matchMedia(REDUCED_MOTION_QUERY).matches
|
|
40190
|
+
);
|
|
40191
|
+
(0, import_react12.useEffect)(() => {
|
|
40192
|
+
const query = window.matchMedia(REDUCED_MOTION_QUERY);
|
|
40193
|
+
const onChange = () => setReduced(query.matches);
|
|
40194
|
+
query.addEventListener("change", onChange);
|
|
40195
|
+
return () => query.removeEventListener("change", onChange);
|
|
40196
|
+
}, []);
|
|
40197
|
+
return reduced;
|
|
40198
|
+
};
|
|
40199
|
+
var useExitTransition = (visible, durationMs) => {
|
|
40200
|
+
const [mounted, setMounted] = (0, import_react12.useState)(visible);
|
|
40201
|
+
const [leaving, setLeaving] = (0, import_react12.useState)(false);
|
|
40202
|
+
const wasVisible = (0, import_react12.useRef)(visible);
|
|
40203
|
+
const duration = (0, import_react12.useRef)(durationMs);
|
|
40204
|
+
duration.current = durationMs;
|
|
40205
|
+
(0, import_react12.useEffect)(() => {
|
|
40206
|
+
if (visible === wasVisible.current) return;
|
|
40207
|
+
wasVisible.current = visible;
|
|
40208
|
+
if (visible) {
|
|
40209
|
+
setLeaving(false);
|
|
40210
|
+
setMounted(true);
|
|
40211
|
+
return;
|
|
40212
|
+
}
|
|
40213
|
+
if (duration.current === 0) {
|
|
40214
|
+
setMounted(false);
|
|
40215
|
+
return;
|
|
40216
|
+
}
|
|
40217
|
+
setLeaving(true);
|
|
40218
|
+
const timeout = setTimeout(() => {
|
|
40219
|
+
setLeaving(false);
|
|
40220
|
+
setMounted(false);
|
|
40221
|
+
}, duration.current);
|
|
40222
|
+
return () => clearTimeout(timeout);
|
|
40223
|
+
}, [visible]);
|
|
40224
|
+
return { mounted, leaving };
|
|
40225
|
+
};
|
|
40226
|
+
var usePersistedFlag = (key, fallback) => {
|
|
40227
|
+
const [value, setValue] = (0, import_react12.useState)(() => {
|
|
40228
|
+
const stored = localStorage.getItem(key);
|
|
40229
|
+
return stored === null ? fallback : stored === "true";
|
|
40230
|
+
});
|
|
40231
|
+
return [
|
|
40232
|
+
value,
|
|
40233
|
+
(next) => {
|
|
40234
|
+
setValue(next);
|
|
40235
|
+
localStorage.setItem(key, String(next));
|
|
40236
|
+
}
|
|
40237
|
+
];
|
|
40238
|
+
};
|
|
40239
|
+
|
|
40240
|
+
// source/gui/client/components/ScrubberParts.tsx
|
|
40241
|
+
var import_react13 = __toESM(require_react(), 1);
|
|
40242
|
+
|
|
40243
|
+
// source/gui/client/components/Checkbox.tsx
|
|
40244
|
+
var import_jsx_runtime26 = __toESM(require_jsx_runtime(), 1);
|
|
40245
|
+
var Checkbox = ({
|
|
40246
|
+
label,
|
|
40247
|
+
checked,
|
|
40248
|
+
onChange,
|
|
40249
|
+
activeColor = GUI_THEME.accent,
|
|
40250
|
+
disabled,
|
|
40251
|
+
title
|
|
40252
|
+
}) => {
|
|
40253
|
+
const color2 = checked ? activeColor : GUI_THEME.dim;
|
|
40254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
40255
|
+
"label",
|
|
40256
|
+
{
|
|
40257
|
+
title,
|
|
40258
|
+
style: {
|
|
40259
|
+
display: "flex",
|
|
40260
|
+
alignItems: "center",
|
|
40261
|
+
gap: 5,
|
|
40262
|
+
fontSize: 10,
|
|
40263
|
+
color: color2,
|
|
40264
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
40265
|
+
opacity: disabled ? 0.4 : 1
|
|
40266
|
+
},
|
|
40267
|
+
children: [
|
|
40268
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
40269
|
+
"span",
|
|
40270
|
+
{
|
|
40271
|
+
style: {
|
|
40272
|
+
position: "relative",
|
|
40273
|
+
display: "inline-flex",
|
|
40274
|
+
alignItems: "center",
|
|
40275
|
+
justifyContent: "center",
|
|
40276
|
+
width: 12,
|
|
40277
|
+
height: 12,
|
|
40278
|
+
// Smaller than the buttons' 6px: at 12px square, 6 rounds to a circle.
|
|
40279
|
+
borderRadius: 4,
|
|
40280
|
+
border: `1px solid ${color2}`,
|
|
40281
|
+
background: "transparent",
|
|
40282
|
+
flexShrink: 0
|
|
40283
|
+
},
|
|
40284
|
+
children: [
|
|
40285
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
40286
|
+
"input",
|
|
40287
|
+
{
|
|
40288
|
+
type: "checkbox",
|
|
40289
|
+
checked,
|
|
40290
|
+
disabled,
|
|
40291
|
+
onChange: (event) => onChange(event.target.checked),
|
|
40292
|
+
style: {
|
|
40293
|
+
position: "absolute",
|
|
40294
|
+
inset: 0,
|
|
40295
|
+
width: "100%",
|
|
40296
|
+
height: "100%",
|
|
40297
|
+
margin: 0,
|
|
40298
|
+
opacity: 0,
|
|
40299
|
+
cursor: "inherit"
|
|
40300
|
+
}
|
|
40301
|
+
}
|
|
40302
|
+
),
|
|
40303
|
+
checked && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
40304
|
+
"span",
|
|
40305
|
+
{
|
|
40306
|
+
style: {
|
|
40307
|
+
width: 6,
|
|
40308
|
+
height: 6,
|
|
40309
|
+
borderRadius: 1,
|
|
40310
|
+
background: activeColor
|
|
40311
|
+
}
|
|
40312
|
+
}
|
|
40313
|
+
)
|
|
40314
|
+
]
|
|
40315
|
+
}
|
|
40316
|
+
),
|
|
40317
|
+
label
|
|
40318
|
+
]
|
|
40319
|
+
}
|
|
40320
|
+
);
|
|
40321
|
+
};
|
|
40322
|
+
|
|
40323
|
+
// source/gui/client/components/IconChevronDown.tsx
|
|
40324
|
+
var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
|
|
40325
|
+
var IconChevronDown = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
40326
|
+
"svg",
|
|
40327
|
+
{
|
|
40328
|
+
width: size,
|
|
40329
|
+
height: size,
|
|
40330
|
+
viewBox: "0 0 24 24",
|
|
40331
|
+
fill: "none",
|
|
40332
|
+
stroke: "currentColor",
|
|
40333
|
+
strokeWidth: "2",
|
|
40334
|
+
strokeLinecap: "round",
|
|
40335
|
+
strokeLinejoin: "round",
|
|
40336
|
+
"aria-hidden": "true",
|
|
40337
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("polyline", { points: "6 9 12 15 18 9" })
|
|
40338
|
+
}
|
|
40339
|
+
);
|
|
40340
|
+
|
|
40341
|
+
// source/gui/client/components/IconChevronRight.tsx
|
|
40342
|
+
var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
|
|
40343
|
+
var IconChevronRight = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
40344
|
+
"svg",
|
|
40345
|
+
{
|
|
40346
|
+
width: size,
|
|
40347
|
+
height: size,
|
|
40348
|
+
viewBox: "0 0 24 24",
|
|
40349
|
+
fill: "none",
|
|
40350
|
+
stroke: "currentColor",
|
|
40351
|
+
strokeWidth: "2",
|
|
40352
|
+
strokeLinecap: "round",
|
|
40353
|
+
strokeLinejoin: "round",
|
|
40354
|
+
"aria-hidden": "true",
|
|
40355
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("polyline", { points: "9 18 15 12 9 6" })
|
|
40356
|
+
}
|
|
40357
|
+
);
|
|
40358
|
+
|
|
40359
|
+
// source/gui/client/components/ScrubberParts.tsx
|
|
40360
|
+
var import_jsx_runtime29 = __toESM(require_jsx_runtime(), 1);
|
|
40361
|
+
var toggleButtonStyle = (active) => ({
|
|
40362
|
+
background: "transparent",
|
|
40363
|
+
border: `1px solid ${active ? GUI_THEME.accent : GUI_THEME.dim}`,
|
|
40364
|
+
color: active ? GUI_THEME.accent : GUI_THEME.dim,
|
|
40365
|
+
borderRadius: 6,
|
|
40366
|
+
fontSize: 10,
|
|
40367
|
+
padding: "2px 8px",
|
|
40368
|
+
cursor: "pointer"
|
|
40369
|
+
});
|
|
40370
|
+
var navButtonStyle = {
|
|
40371
|
+
background: "transparent",
|
|
40372
|
+
border: `1px solid ${GUI_THEME.dim}`,
|
|
40373
|
+
color: GUI_THEME.dim,
|
|
40374
|
+
borderRadius: 6,
|
|
40375
|
+
fontSize: 10,
|
|
40376
|
+
padding: "2px 6px",
|
|
40377
|
+
cursor: "pointer",
|
|
40378
|
+
lineHeight: 1
|
|
40379
|
+
};
|
|
40380
|
+
var ScrubberControls = ({
|
|
40381
|
+
scope,
|
|
40382
|
+
offset,
|
|
40383
|
+
periodRange,
|
|
40384
|
+
layoutMode,
|
|
40385
|
+
showIssues,
|
|
40386
|
+
showCommits,
|
|
40387
|
+
allBoards,
|
|
40388
|
+
isScrubbing,
|
|
40389
|
+
nowLabel,
|
|
40390
|
+
onChangeScope,
|
|
40391
|
+
onChangeOffset,
|
|
40392
|
+
onChangeLayoutMode,
|
|
40393
|
+
onChangeShowIssues,
|
|
40394
|
+
onChangeShowCommits,
|
|
40395
|
+
onChangeAllBoards,
|
|
40396
|
+
onReturnToLive
|
|
40397
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
|
|
40398
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
40399
|
+
scope !== "all" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 2 }, children: [
|
|
40400
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40401
|
+
"button",
|
|
40402
|
+
{
|
|
40403
|
+
title: "Earlier",
|
|
40404
|
+
onClick: () => onChangeOffset(offset + 1),
|
|
40405
|
+
style: navButtonStyle,
|
|
40406
|
+
children: "\u25C0"
|
|
40407
|
+
}
|
|
40408
|
+
),
|
|
40409
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40410
|
+
"span",
|
|
40411
|
+
{
|
|
40412
|
+
style: {
|
|
40413
|
+
fontSize: 10,
|
|
40414
|
+
color: GUI_THEME.dim,
|
|
40415
|
+
whiteSpace: "nowrap",
|
|
40416
|
+
overflow: "hidden",
|
|
40417
|
+
// Fixed, not min, so the changing label never shifts the
|
|
40418
|
+
// buttons around it.
|
|
40419
|
+
width: 88,
|
|
40420
|
+
flexShrink: 0,
|
|
40421
|
+
textAlign: "center"
|
|
40422
|
+
},
|
|
40423
|
+
children: formatPeriodLabel(scope, offset, periodRange)
|
|
40424
|
+
}
|
|
40425
|
+
),
|
|
40426
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40427
|
+
"button",
|
|
40428
|
+
{
|
|
40429
|
+
title: "Later",
|
|
40430
|
+
disabled: offset === 0,
|
|
40431
|
+
onClick: () => onChangeOffset(Math.max(0, offset - 1)),
|
|
40432
|
+
style: {
|
|
40433
|
+
...navButtonStyle,
|
|
40434
|
+
opacity: offset === 0 ? 0.35 : 1,
|
|
40435
|
+
cursor: offset === 0 ? "default" : "pointer"
|
|
40436
|
+
},
|
|
40437
|
+
children: "\u25B6"
|
|
40438
|
+
}
|
|
40439
|
+
)
|
|
40440
|
+
] }),
|
|
40441
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { style: { display: "flex", gap: 2 }, children: SCOPES.map((option) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40442
|
+
"button",
|
|
40443
|
+
{
|
|
40444
|
+
onClick: () => onChangeScope(option),
|
|
40445
|
+
style: toggleButtonStyle(scope === option),
|
|
40446
|
+
children: scopeButtonLabel(option)
|
|
40447
|
+
},
|
|
40448
|
+
option
|
|
40449
|
+
)) })
|
|
40450
|
+
] }),
|
|
40451
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { style: { display: "flex", gap: 2 }, children: [
|
|
40452
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40453
|
+
"button",
|
|
40454
|
+
{
|
|
40455
|
+
title: "How much happened, per equal-width period \u2014 no empty gaps for quiet stretches",
|
|
40456
|
+
onClick: () => onChangeLayoutMode("even"),
|
|
40457
|
+
style: toggleButtonStyle(layoutMode === "even"),
|
|
40458
|
+
children: "Volume"
|
|
40459
|
+
}
|
|
40460
|
+
),
|
|
40461
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40462
|
+
"button",
|
|
40463
|
+
{
|
|
40464
|
+
title: "Individual events by exact moment \u2014 x is elapsed time, y is time of day",
|
|
40465
|
+
onClick: () => onChangeLayoutMode("real"),
|
|
40466
|
+
style: toggleButtonStyle(layoutMode === "real"),
|
|
40467
|
+
children: "Events"
|
|
40468
|
+
}
|
|
40469
|
+
)
|
|
40470
|
+
] }),
|
|
40471
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { style: { display: "flex", gap: 10 }, children: [
|
|
40472
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40473
|
+
Checkbox,
|
|
40474
|
+
{
|
|
40475
|
+
label: "Board",
|
|
40476
|
+
checked: showIssues,
|
|
40477
|
+
activeColor: GUI_THEME.accent,
|
|
40478
|
+
onChange: onChangeShowIssues
|
|
40479
|
+
}
|
|
40480
|
+
),
|
|
40481
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40482
|
+
Checkbox,
|
|
40483
|
+
{
|
|
40484
|
+
label: "Code",
|
|
40485
|
+
checked: showCommits,
|
|
40486
|
+
activeColor: GUI_THEME.green,
|
|
40487
|
+
onChange: onChangeShowCommits
|
|
40488
|
+
}
|
|
40489
|
+
),
|
|
40490
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40491
|
+
Checkbox,
|
|
40492
|
+
{
|
|
40493
|
+
label: "All boards",
|
|
40494
|
+
checked: allBoards,
|
|
40495
|
+
activeColor: GUI_THEME.accent,
|
|
40496
|
+
onChange: onChangeAllBoards
|
|
40497
|
+
}
|
|
40498
|
+
)
|
|
40499
|
+
] }),
|
|
40500
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40501
|
+
"div",
|
|
40502
|
+
{
|
|
40503
|
+
style: {
|
|
40504
|
+
display: "flex",
|
|
40505
|
+
justifyContent: "flex-end",
|
|
40506
|
+
alignItems: "center",
|
|
40507
|
+
// Fixed, not min, so swapping between "Now" and "Return to live"
|
|
40508
|
+
// never resizes the controls row.
|
|
40509
|
+
width: 100,
|
|
40510
|
+
flexShrink: 0
|
|
40511
|
+
},
|
|
40512
|
+
children: isScrubbing ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40513
|
+
"button",
|
|
40514
|
+
{
|
|
40515
|
+
onClick: onReturnToLive,
|
|
40516
|
+
style: {
|
|
40517
|
+
background: "transparent",
|
|
40518
|
+
border: `1px solid ${GUI_THEME.accent}`,
|
|
40519
|
+
color: GUI_THEME.accent,
|
|
40520
|
+
borderRadius: 6,
|
|
40521
|
+
fontSize: 11,
|
|
40522
|
+
padding: "2px 8px",
|
|
40523
|
+
cursor: "pointer",
|
|
40524
|
+
whiteSpace: "nowrap"
|
|
40525
|
+
},
|
|
40526
|
+
children: "Return to live"
|
|
40527
|
+
}
|
|
40528
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40529
|
+
"span",
|
|
40530
|
+
{
|
|
40531
|
+
style: {
|
|
40532
|
+
fontSize: 11,
|
|
40533
|
+
color: GUI_THEME.dim,
|
|
40534
|
+
overflow: "hidden",
|
|
40535
|
+
textAlign: "right",
|
|
40536
|
+
whiteSpace: "nowrap"
|
|
40537
|
+
},
|
|
40538
|
+
children: nowLabel
|
|
40539
|
+
}
|
|
40540
|
+
)
|
|
40541
|
+
}
|
|
40542
|
+
)
|
|
40543
|
+
] });
|
|
40544
|
+
var ScrubberHeader = ({
|
|
40545
|
+
collapsed,
|
|
40546
|
+
onToggleCollapsed,
|
|
40547
|
+
scrubbingAsOf
|
|
40548
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
40549
|
+
"div",
|
|
40550
|
+
{
|
|
40551
|
+
style: {
|
|
40552
|
+
display: "flex",
|
|
40553
|
+
alignItems: "center",
|
|
40554
|
+
gap: 8,
|
|
40555
|
+
fontSize: 11,
|
|
40556
|
+
whiteSpace: "nowrap"
|
|
40557
|
+
},
|
|
40558
|
+
children: [
|
|
40559
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
40560
|
+
"button",
|
|
40561
|
+
{
|
|
40562
|
+
onClick: onToggleCollapsed,
|
|
40563
|
+
title: collapsed ? "Show time travel" : "Hide time travel",
|
|
40564
|
+
style: {
|
|
40565
|
+
background: "transparent",
|
|
40566
|
+
border: "none",
|
|
40567
|
+
color: GUI_THEME.dim,
|
|
40568
|
+
fontSize: 11,
|
|
40569
|
+
padding: 0,
|
|
40570
|
+
cursor: "pointer",
|
|
40571
|
+
display: "flex",
|
|
40572
|
+
alignItems: "center",
|
|
40573
|
+
gap: 4
|
|
40574
|
+
},
|
|
40575
|
+
children: [
|
|
40576
|
+
"Time travel",
|
|
40577
|
+
collapsed ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(IconChevronRight, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(IconChevronDown, { size: 12 })
|
|
40578
|
+
]
|
|
40579
|
+
}
|
|
40580
|
+
),
|
|
40581
|
+
scrubbingAsOf !== null && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
40582
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { style: { color: GUI_THEME.accent, fontWeight: 700 }, children: "Read-only" }),
|
|
40583
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { style: { color: GUI_THEME.primary }, children: scrubbingAsOf })
|
|
40584
|
+
] })
|
|
40585
|
+
]
|
|
40586
|
+
}
|
|
40587
|
+
);
|
|
40588
|
+
var SegmentHighlight = ({
|
|
40589
|
+
segment,
|
|
40590
|
+
fractionForTime
|
|
40591
|
+
}) => {
|
|
40592
|
+
const left = fractionForTime(segment.start);
|
|
40593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40594
|
+
"div",
|
|
40595
|
+
{
|
|
40596
|
+
style: {
|
|
40597
|
+
position: "absolute",
|
|
40598
|
+
left: `${left * 100}%`,
|
|
40599
|
+
width: `${(fractionForTime(segment.end) - left) * 100}%`,
|
|
40600
|
+
top: 0,
|
|
40601
|
+
bottom: 0,
|
|
40602
|
+
background: SEGMENT_HIGHLIGHT_COLOR,
|
|
40603
|
+
pointerEvents: "none",
|
|
40604
|
+
display: "flex",
|
|
40605
|
+
justifyContent: "center",
|
|
40606
|
+
paddingTop: 3,
|
|
40607
|
+
// With top and bottom both pinned, content-box would add the padding
|
|
40608
|
+
// on top of the resolved height and push the block past the wrapper
|
|
40609
|
+
// it spans.
|
|
40610
|
+
boxSizing: "border-box",
|
|
40611
|
+
fontSize: 9,
|
|
40612
|
+
color: GUI_THEME.dim2,
|
|
40613
|
+
whiteSpace: "nowrap",
|
|
40614
|
+
// The label is wider than its block at month and year scopes; only
|
|
40615
|
+
// one segment is ever highlighted, so it has nothing to overlap.
|
|
40616
|
+
overflow: "visible"
|
|
40617
|
+
},
|
|
40618
|
+
children: segment.label
|
|
40619
|
+
}
|
|
40620
|
+
);
|
|
40621
|
+
};
|
|
40622
|
+
var TrackBaseline = ({
|
|
40623
|
+
color: color2,
|
|
40624
|
+
anchor
|
|
40625
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40626
|
+
"div",
|
|
40627
|
+
{
|
|
40628
|
+
style: {
|
|
40629
|
+
position: "absolute",
|
|
40630
|
+
left: 0,
|
|
40631
|
+
right: 0,
|
|
40632
|
+
...anchor === "bottom" ? { bottom: 0 } : {},
|
|
40633
|
+
...anchor === "top" ? { top: 0 } : {},
|
|
40634
|
+
height: anchor === "top" ? 1 : 2,
|
|
40635
|
+
borderRadius: 999,
|
|
40636
|
+
background: color2,
|
|
40637
|
+
opacity: 0.2
|
|
40638
|
+
}
|
|
40639
|
+
}
|
|
40640
|
+
);
|
|
40641
|
+
var HourAxisLabels = () => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_jsx_runtime29.Fragment, { children: [
|
|
40642
|
+
["00:00", { top: EVENTS_MODE_VERTICAL_PADDING }],
|
|
40643
|
+
["12:00", { top: "50%", transform: "translateY(-50%)" }],
|
|
40644
|
+
["24:00", { bottom: EVENTS_MODE_VERTICAL_PADDING }]
|
|
40645
|
+
].map(([label, position3]) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40646
|
+
"span",
|
|
40647
|
+
{
|
|
40648
|
+
style: {
|
|
40649
|
+
position: "absolute",
|
|
40650
|
+
left: 2,
|
|
40651
|
+
fontSize: 9,
|
|
40652
|
+
color: GUI_THEME.dim,
|
|
40653
|
+
pointerEvents: "none",
|
|
40654
|
+
...position3
|
|
40655
|
+
},
|
|
40656
|
+
children: label
|
|
40657
|
+
},
|
|
40658
|
+
label
|
|
40659
|
+
)) });
|
|
40660
|
+
var SeriesLayer = ({
|
|
40661
|
+
animate,
|
|
40662
|
+
children
|
|
40663
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40664
|
+
"div",
|
|
40665
|
+
{
|
|
40666
|
+
style: {
|
|
40667
|
+
position: "absolute",
|
|
40668
|
+
inset: 0,
|
|
40669
|
+
pointerEvents: "none",
|
|
40670
|
+
animation: animate ? FADE_IN_ANIMATION : void 0
|
|
40671
|
+
},
|
|
40672
|
+
children
|
|
40673
|
+
}
|
|
40674
|
+
);
|
|
40675
|
+
var VolumeBars = ({
|
|
40676
|
+
bars,
|
|
40677
|
+
bucketCount,
|
|
40678
|
+
firstBar,
|
|
40679
|
+
lastBar,
|
|
40680
|
+
highlightedIndex,
|
|
40681
|
+
color: color2,
|
|
40682
|
+
direction,
|
|
40683
|
+
animate
|
|
40684
|
+
}) => {
|
|
40685
|
+
const widthPercent = 100 / bucketCount;
|
|
40686
|
+
const barWidth = barWidthCss(bucketCount);
|
|
40687
|
+
const growsUp = direction === "up";
|
|
40688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
40689
|
+
highlightedIndex !== null && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40690
|
+
"div",
|
|
40691
|
+
{
|
|
40692
|
+
style: {
|
|
40693
|
+
position: "absolute",
|
|
40694
|
+
left: `${highlightedIndex * widthPercent}%`,
|
|
40695
|
+
top: 0,
|
|
40696
|
+
bottom: 0,
|
|
40697
|
+
width: `${widthPercent}%`,
|
|
40698
|
+
// A bucket can be thinner than a pixel at wide spans.
|
|
40699
|
+
minWidth: 2,
|
|
40700
|
+
background: BUCKET_HIGHLIGHT_COLOR,
|
|
40701
|
+
pointerEvents: "none"
|
|
40702
|
+
}
|
|
40703
|
+
}
|
|
40704
|
+
),
|
|
40705
|
+
bars.map(({ index: index2, intensity }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40706
|
+
"div",
|
|
40707
|
+
{
|
|
40708
|
+
style: {
|
|
40709
|
+
position: "absolute",
|
|
40710
|
+
left: `${index2 * widthPercent}%`,
|
|
40711
|
+
...growsUp ? { bottom: 0 } : { top: 0 },
|
|
40712
|
+
width: barWidth,
|
|
40713
|
+
height: 3 + intensity * (TRACK_HEIGHT - 3),
|
|
40714
|
+
borderRadius: growsUp ? "1px 1px 0 0" : "0 0 1px 1px",
|
|
40715
|
+
background: color2,
|
|
40716
|
+
opacity: 0.35 + intensity * 0.65,
|
|
40717
|
+
transformOrigin: growsUp ? "bottom" : "top",
|
|
40718
|
+
animation: animate ? barGrowAnimation(index2, firstBar, lastBar) : void 0,
|
|
40719
|
+
pointerEvents: "none"
|
|
40720
|
+
}
|
|
40721
|
+
},
|
|
40722
|
+
index2
|
|
40723
|
+
))
|
|
40724
|
+
] });
|
|
40725
|
+
};
|
|
40726
|
+
var ScatterDot = ({
|
|
40727
|
+
fraction,
|
|
40728
|
+
hourFraction,
|
|
40729
|
+
size,
|
|
40730
|
+
color: color2,
|
|
40731
|
+
opacity,
|
|
40732
|
+
zIndex,
|
|
40733
|
+
title,
|
|
40734
|
+
animation,
|
|
40735
|
+
interactive = true,
|
|
40736
|
+
onMouseEnter,
|
|
40737
|
+
onMouseLeave,
|
|
40738
|
+
onClick
|
|
40739
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40740
|
+
"div",
|
|
40741
|
+
{
|
|
40742
|
+
title,
|
|
40743
|
+
onPointerDown: onClick && ((event) => event.stopPropagation()),
|
|
40744
|
+
onClick: onClick && ((event) => {
|
|
40745
|
+
event.stopPropagation();
|
|
40746
|
+
onClick();
|
|
40747
|
+
}),
|
|
40748
|
+
onMouseEnter,
|
|
40749
|
+
onMouseLeave,
|
|
40750
|
+
style: {
|
|
40751
|
+
position: "absolute",
|
|
40752
|
+
left: `${fraction * 100}%`,
|
|
40753
|
+
top: EVENTS_MODE_VERTICAL_PADDING + hourFraction * EVENTS_SCATTER_HEIGHT,
|
|
40754
|
+
width: size,
|
|
40755
|
+
height: size,
|
|
40756
|
+
borderRadius: "50%",
|
|
40757
|
+
background: color2,
|
|
40758
|
+
opacity,
|
|
40759
|
+
zIndex,
|
|
40760
|
+
transform: `translate(${-size / 2}px, -50%)`,
|
|
40761
|
+
animation,
|
|
40762
|
+
pointerEvents: interactive ? "auto" : "none",
|
|
40763
|
+
cursor: onClick ? "pointer" : void 0
|
|
40764
|
+
}
|
|
40765
|
+
}
|
|
40766
|
+
);
|
|
40767
|
+
var ScrubberNeedle = ({ fraction }) => {
|
|
40768
|
+
const [hovered, setHovered] = (0, import_react13.useState)(false);
|
|
40769
|
+
const hover = {
|
|
40770
|
+
onMouseEnter: () => setHovered(true),
|
|
40771
|
+
onMouseLeave: () => setHovered(false)
|
|
40772
|
+
};
|
|
40773
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
40774
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40775
|
+
"div",
|
|
40776
|
+
{
|
|
40777
|
+
...hover,
|
|
40778
|
+
style: {
|
|
40779
|
+
position: "absolute",
|
|
40780
|
+
left: `${fraction * 100}%`,
|
|
40781
|
+
top: 0,
|
|
40782
|
+
bottom: 0,
|
|
40783
|
+
// A hairline, no glow: the needle marks an exact instant, and a
|
|
40784
|
+
// soft edge blooms over bars that can be ~2px wide.
|
|
40785
|
+
width: 1,
|
|
40786
|
+
background: NEEDLE_COLOR,
|
|
40787
|
+
zIndex: 3,
|
|
40788
|
+
transform: "translateX(-0.5px)",
|
|
40789
|
+
pointerEvents: "auto",
|
|
40790
|
+
cursor: "pointer"
|
|
40791
|
+
}
|
|
40792
|
+
}
|
|
40793
|
+
),
|
|
40794
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40795
|
+
"div",
|
|
40796
|
+
{
|
|
40797
|
+
...hover,
|
|
40798
|
+
style: {
|
|
40799
|
+
position: "absolute",
|
|
40800
|
+
left: `${fraction * 100}%`,
|
|
40801
|
+
top: hovered ? -9 : -7,
|
|
40802
|
+
width: 0,
|
|
40803
|
+
height: 0,
|
|
40804
|
+
borderLeft: `${hovered ? 6 : 5}px solid transparent`,
|
|
40805
|
+
borderRight: `${hovered ? 6 : 5}px solid transparent`,
|
|
40806
|
+
borderTop: `${hovered ? 8 : 7}px solid ${NEEDLE_COLOR}`,
|
|
40807
|
+
zIndex: 3,
|
|
40808
|
+
transform: `translateX(${hovered ? -6 : -5}px)`,
|
|
40809
|
+
pointerEvents: "auto",
|
|
40810
|
+
cursor: "pointer"
|
|
40811
|
+
}
|
|
40812
|
+
}
|
|
40813
|
+
)
|
|
40814
|
+
] });
|
|
40815
|
+
};
|
|
40816
|
+
var ScrubberHoverHint = ({
|
|
40817
|
+
label,
|
|
40818
|
+
rows,
|
|
40819
|
+
segmentLabel,
|
|
40820
|
+
stripeColor,
|
|
40821
|
+
fraction,
|
|
40822
|
+
trackWidthPx,
|
|
40823
|
+
empty: empty3 = false
|
|
40824
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
40825
|
+
"div",
|
|
40826
|
+
{
|
|
40827
|
+
style: {
|
|
40828
|
+
position: "absolute",
|
|
40829
|
+
top: "100%",
|
|
40830
|
+
marginTop: 6,
|
|
40831
|
+
left: clamp(
|
|
40832
|
+
fraction * trackWidthPx - HOVER_HINT_WIDTH / 2,
|
|
40833
|
+
0,
|
|
40834
|
+
Math.max(0, trackWidthPx - HOVER_HINT_WIDTH)
|
|
40835
|
+
),
|
|
40836
|
+
width: HOVER_HINT_WIDTH,
|
|
40837
|
+
// Border-box so `width` matches what the clamp math assumes; otherwise
|
|
40838
|
+
// border and padding push the box past the track's edge.
|
|
40839
|
+
boxSizing: "border-box",
|
|
40840
|
+
display: "flex",
|
|
40841
|
+
flexDirection: "column",
|
|
40842
|
+
gap: 2,
|
|
40843
|
+
textAlign: "left",
|
|
40844
|
+
background: GUI_THEME.panel,
|
|
40845
|
+
border: `1px solid ${GUI_THEME.line}`,
|
|
40846
|
+
borderLeft: `3px solid ${empty3 ? GUI_THEME.dim : stripeColor}`,
|
|
40847
|
+
// Smaller than the 6px used elsewhere: a rounder corner clips the 3px
|
|
40848
|
+
// stripe into a visible wedge.
|
|
40849
|
+
borderRadius: 3,
|
|
40850
|
+
padding: "6px 10px",
|
|
40851
|
+
pointerEvents: "none",
|
|
40852
|
+
// Above the board content this overhangs.
|
|
40853
|
+
zIndex: 5
|
|
40854
|
+
},
|
|
40855
|
+
children: [
|
|
40856
|
+
segmentLabel && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { style: { fontSize: 10, color: GUI_THEME.dim }, children: segmentLabel }),
|
|
40857
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40858
|
+
"div",
|
|
40859
|
+
{
|
|
40860
|
+
style: {
|
|
40861
|
+
fontSize: 11,
|
|
40862
|
+
fontWeight: 600,
|
|
40863
|
+
color: empty3 ? GUI_THEME.secondary : GUI_THEME.primary,
|
|
40864
|
+
whiteSpace: "normal",
|
|
40865
|
+
wordBreak: "break-word"
|
|
40866
|
+
},
|
|
40867
|
+
children: label
|
|
40868
|
+
}
|
|
40869
|
+
),
|
|
40870
|
+
rows.map((row, index2) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
40871
|
+
"div",
|
|
40872
|
+
{
|
|
40873
|
+
style: {
|
|
40874
|
+
fontSize: 11,
|
|
40875
|
+
color: empty3 ? GUI_THEME.dim : GUI_THEME.secondary,
|
|
40876
|
+
whiteSpace: "normal",
|
|
40877
|
+
wordBreak: "break-word"
|
|
40878
|
+
},
|
|
40879
|
+
children: row
|
|
40880
|
+
},
|
|
40881
|
+
index2
|
|
40882
|
+
))
|
|
40883
|
+
]
|
|
40884
|
+
}
|
|
40885
|
+
);
|
|
40886
|
+
|
|
40887
|
+
// source/gui/client/components/ScrubberLayout.tsx
|
|
40888
|
+
var import_jsx_runtime30 = __toESM(require_jsx_runtime(), 1);
|
|
40889
|
+
var dotAnimation = (key, animate, leaving) => !animate ? void 0 : leaving ? dotExitAnimation(key) : dotAppearAnimation(key);
|
|
40890
|
+
var ScrubberLayout = ({
|
|
40891
|
+
collapsed,
|
|
40892
|
+
onToggleCollapsed,
|
|
40893
|
+
scrubbingAsOf,
|
|
40894
|
+
controls,
|
|
40895
|
+
chart
|
|
40896
|
+
}) => {
|
|
40897
|
+
const { axis, layoutMode, animate, windowKey, on } = chart;
|
|
40898
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
40899
|
+
Panel,
|
|
40900
|
+
{
|
|
40901
|
+
as: "div",
|
|
40902
|
+
borderColor: GUI_THEME.line,
|
|
40903
|
+
borderRadius: 0,
|
|
40904
|
+
style: {
|
|
40905
|
+
borderLeft: "none",
|
|
40906
|
+
borderRight: "none",
|
|
40907
|
+
borderTop: "none",
|
|
40908
|
+
padding: "10px 30px",
|
|
40909
|
+
// Panel clips children to keep its glow inside its rounded corners,
|
|
40910
|
+
// which would lop off the overhanging hint. Safe to disable only
|
|
40911
|
+
// because this panel is square.
|
|
40912
|
+
overflow: "visible"
|
|
40913
|
+
},
|
|
40914
|
+
children: [
|
|
40915
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("style", { children: SCRUBBER_KEYFRAMES }),
|
|
40916
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
40917
|
+
"div",
|
|
40918
|
+
{
|
|
40919
|
+
style: {
|
|
40920
|
+
display: "flex",
|
|
40921
|
+
flexDirection: "column",
|
|
40922
|
+
gap: collapsed ? 0 : 8
|
|
40923
|
+
},
|
|
40924
|
+
children: [
|
|
40925
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
40926
|
+
"div",
|
|
40927
|
+
{
|
|
40928
|
+
style: {
|
|
40929
|
+
display: "flex",
|
|
40930
|
+
alignItems: "center",
|
|
40931
|
+
justifyContent: "space-between",
|
|
40932
|
+
// Fixed whether or not the banner renders, so the track below
|
|
40933
|
+
// never shifts vertically.
|
|
40934
|
+
minHeight: 22
|
|
40935
|
+
},
|
|
40936
|
+
children: [
|
|
40937
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
40938
|
+
ScrubberHeader,
|
|
40939
|
+
{
|
|
40940
|
+
collapsed,
|
|
40941
|
+
onToggleCollapsed,
|
|
40942
|
+
scrubbingAsOf
|
|
40943
|
+
}
|
|
40944
|
+
),
|
|
40945
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ScrubberControls, { ...controls })
|
|
40946
|
+
]
|
|
40947
|
+
}
|
|
40948
|
+
),
|
|
40949
|
+
!collapsed && // Wraps both charts so the period highlight can be one tall block
|
|
40950
|
+
// spanning them and the gap between. Pointer handlers belong here
|
|
40951
|
+
// rather than on either chart, so a drag or hover anywhere across
|
|
40952
|
+
// the pair — the gap included — counts as one timeline.
|
|
40953
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
40954
|
+
"div",
|
|
40955
|
+
{
|
|
40956
|
+
onPointerDown: on.onPointerDown,
|
|
40957
|
+
onPointerMove: on.onPointerMove,
|
|
40958
|
+
onPointerUp: on.onPointerEnd,
|
|
40959
|
+
onPointerCancel: on.onPointerEnd,
|
|
40960
|
+
onMouseMove: on.onTrackMouseMove,
|
|
40961
|
+
onMouseLeave: on.onTrackMouseLeave,
|
|
40962
|
+
style: {
|
|
40963
|
+
position: "relative",
|
|
40964
|
+
display: "flex",
|
|
40965
|
+
flexDirection: "column",
|
|
40966
|
+
gap: 8,
|
|
40967
|
+
cursor: "pointer"
|
|
40968
|
+
},
|
|
40969
|
+
children: [
|
|
40970
|
+
chart.hoveredSegment && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
40971
|
+
SegmentHighlight,
|
|
40972
|
+
{
|
|
40973
|
+
segment: chart.hoveredSegment,
|
|
40974
|
+
fractionForTime: axis.fractionForTime
|
|
40975
|
+
}
|
|
40976
|
+
),
|
|
40977
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
40978
|
+
"div",
|
|
40979
|
+
{
|
|
40980
|
+
ref: chart.trackRef,
|
|
40981
|
+
style: {
|
|
40982
|
+
position: "relative",
|
|
40983
|
+
width: "100%",
|
|
40984
|
+
height: layoutMode === "real" ? EVENTS_SCATTER_HEIGHT : TRACK_HEIGHT,
|
|
40985
|
+
paddingTop: layoutMode === "real" ? EVENTS_MODE_VERTICAL_PADDING : 0,
|
|
40986
|
+
paddingBottom: layoutMode === "real" ? EVENTS_MODE_VERTICAL_PADDING : 0,
|
|
40987
|
+
boxSizing: "content-box",
|
|
40988
|
+
display: "flex",
|
|
40989
|
+
alignItems: "center"
|
|
40990
|
+
},
|
|
40991
|
+
children: [
|
|
40992
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
40993
|
+
TrackBaseline,
|
|
40994
|
+
{
|
|
40995
|
+
color: GUI_THEME.accent,
|
|
40996
|
+
anchor: layoutMode === "even" ? "bottom" : "centre"
|
|
40997
|
+
}
|
|
40998
|
+
),
|
|
40999
|
+
layoutMode === "real" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(HourAxisLabels, {}),
|
|
41000
|
+
chart.showIssues && layoutMode === "even" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(SeriesLayer, { animate, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41001
|
+
VolumeBars,
|
|
41002
|
+
{
|
|
41003
|
+
bars: chart.issueBars,
|
|
41004
|
+
bucketCount: axis.bucketCount,
|
|
41005
|
+
firstBar: chart.issueBarRange[0],
|
|
41006
|
+
lastBar: chart.issueBarRange[1],
|
|
41007
|
+
highlightedIndex: chart.hoveredBucketIndex,
|
|
41008
|
+
color: GUI_THEME.accent,
|
|
41009
|
+
direction: "up",
|
|
41010
|
+
animate
|
|
41011
|
+
}
|
|
41012
|
+
) }, `issues-${windowKey}`),
|
|
41013
|
+
chart.issueScatter.mounted && layoutMode === "real" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41014
|
+
SeriesLayer,
|
|
41015
|
+
{
|
|
41016
|
+
animate: animate && !chart.issueScatter.leaving,
|
|
41017
|
+
children: chart.eventBuckets.map((bucket) => {
|
|
41018
|
+
const intensity = bucket.count / chart.maxEventCount;
|
|
41019
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41020
|
+
ScatterDot,
|
|
41021
|
+
{
|
|
41022
|
+
fraction: axis.fractionForTime(bucket.t),
|
|
41023
|
+
hourFraction: hourFractionForTime(bucket.t),
|
|
41024
|
+
size: 3 + intensity * 6,
|
|
41025
|
+
color: GUI_THEME.accent,
|
|
41026
|
+
opacity: 0.3 + intensity * 0.5,
|
|
41027
|
+
zIndex: 2,
|
|
41028
|
+
title: `${bucket.count} change${bucket.count === 1 ? "" : "s"}, ${formatDateTime(new Date(bucket.t))}`,
|
|
41029
|
+
animation: dotAnimation(
|
|
41030
|
+
String(bucket.t),
|
|
41031
|
+
animate,
|
|
41032
|
+
chart.issueScatter.leaving
|
|
41033
|
+
),
|
|
41034
|
+
interactive: !chart.issueScatter.leaving,
|
|
41035
|
+
onMouseEnter: () => on.onIssueDotEnter(bucket),
|
|
41036
|
+
onMouseLeave: on.onIssueDotLeave
|
|
41037
|
+
},
|
|
41038
|
+
bucket.t
|
|
41039
|
+
);
|
|
41040
|
+
})
|
|
41041
|
+
},
|
|
41042
|
+
`issues-${windowKey}`
|
|
41043
|
+
),
|
|
41044
|
+
chart.commitScatter.mounted && layoutMode === "real" && chart.commits.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41045
|
+
SeriesLayer,
|
|
41046
|
+
{
|
|
41047
|
+
animate: animate && !chart.commitScatter.leaving,
|
|
41048
|
+
children: chart.commits.map((commit) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41049
|
+
ScatterDot,
|
|
41050
|
+
{
|
|
41051
|
+
fraction: axis.fractionForTime(commit.time),
|
|
41052
|
+
hourFraction: hourFractionForTime(commit.time),
|
|
41053
|
+
size: 4,
|
|
41054
|
+
color: GUI_THEME.green,
|
|
41055
|
+
opacity: chart.hoveredCommitSha === commit.sha ? 1 : 0.55,
|
|
41056
|
+
zIndex: 1,
|
|
41057
|
+
title: `${formatDateTime(new Date(commit.time))} \u2014 ${commit.subject} \u2014 ${commit.author} (${commit.linesChanged.toLocaleString()} lines)`,
|
|
41058
|
+
animation: dotAnimation(
|
|
41059
|
+
commit.sha,
|
|
41060
|
+
animate,
|
|
41061
|
+
chart.commitScatter.leaving
|
|
41062
|
+
),
|
|
41063
|
+
interactive: !chart.commitScatter.leaving,
|
|
41064
|
+
onClick: () => on.onInspectCommit(commit.sha),
|
|
41065
|
+
onMouseEnter: () => on.onCommitDotEnter(commit),
|
|
41066
|
+
onMouseLeave: on.onCommitDotLeave
|
|
41067
|
+
},
|
|
41068
|
+
commit.sha
|
|
41069
|
+
))
|
|
41070
|
+
},
|
|
41071
|
+
`commits-${windowKey}`
|
|
41072
|
+
)
|
|
41073
|
+
]
|
|
41074
|
+
}
|
|
41075
|
+
),
|
|
41076
|
+
chart.showCommits && layoutMode === "even" && chart.commits.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
41077
|
+
"div",
|
|
41078
|
+
{
|
|
41079
|
+
onMouseEnter: on.onCommitTrackMouseEnter,
|
|
41080
|
+
onMouseMove: on.onCommitTrackMouseMove,
|
|
41081
|
+
onMouseLeave: on.onCommitTrackMouseLeave,
|
|
41082
|
+
style: {
|
|
41083
|
+
position: "relative",
|
|
41084
|
+
width: "100%",
|
|
41085
|
+
height: TRACK_HEIGHT,
|
|
41086
|
+
animation: animate ? FADE_IN_ANIMATION : void 0
|
|
41087
|
+
},
|
|
41088
|
+
children: [
|
|
41089
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TrackBaseline, { color: GUI_THEME.green, anchor: "top" }),
|
|
41090
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41091
|
+
VolumeBars,
|
|
41092
|
+
{
|
|
41093
|
+
bars: chart.commitBars,
|
|
41094
|
+
bucketCount: axis.bucketCount,
|
|
41095
|
+
firstBar: chart.commitBarRange[0],
|
|
41096
|
+
lastBar: chart.commitBarRange[1],
|
|
41097
|
+
highlightedIndex: chart.hoveredCommitBucketIndex,
|
|
41098
|
+
color: GUI_THEME.green,
|
|
41099
|
+
direction: "down",
|
|
41100
|
+
animate
|
|
41101
|
+
}
|
|
41102
|
+
)
|
|
41103
|
+
]
|
|
41104
|
+
},
|
|
41105
|
+
`commits-${windowKey}`
|
|
41106
|
+
),
|
|
41107
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ScrubberNeedle, { fraction: chart.thumbFraction }),
|
|
41108
|
+
chart.boardHint && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41109
|
+
ScrubberHoverHint,
|
|
41110
|
+
{
|
|
41111
|
+
...chart.boardHint,
|
|
41112
|
+
segmentLabel: chart.hoveredSegment?.label,
|
|
41113
|
+
stripeColor: GUI_THEME.accent,
|
|
41114
|
+
trackWidthPx: chart.trackWidthPx
|
|
41115
|
+
}
|
|
41116
|
+
),
|
|
41117
|
+
chart.commitHint && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
41118
|
+
ScrubberHoverHint,
|
|
41119
|
+
{
|
|
41120
|
+
...chart.commitHint,
|
|
41121
|
+
segmentLabel: chart.hoveredSegment?.label,
|
|
41122
|
+
stripeColor: GUI_THEME.green,
|
|
41123
|
+
trackWidthPx: chart.trackWidthPx
|
|
41124
|
+
}
|
|
41125
|
+
)
|
|
41126
|
+
]
|
|
41127
|
+
}
|
|
41128
|
+
)
|
|
41129
|
+
]
|
|
41130
|
+
}
|
|
41131
|
+
)
|
|
39576
41132
|
]
|
|
39577
41133
|
}
|
|
39578
41134
|
);
|
|
39579
41135
|
};
|
|
39580
41136
|
|
|
41137
|
+
// source/gui/client/components/TimeScrubber.tsx
|
|
41138
|
+
var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1);
|
|
41139
|
+
var SCRUB_THROTTLE_MS = 120;
|
|
41140
|
+
var COLLAPSED_STORAGE_KEY = "epiq.timeScrubber.collapsed";
|
|
41141
|
+
var SCOPE_STORAGE_KEY = "epiq.timeScrubber.scope";
|
|
41142
|
+
var SHOW_ISSUES_STORAGE_KEY = "epiq.timeScrubber.showIssues";
|
|
41143
|
+
var SHOW_COMMITS_STORAGE_KEY = "epiq.timeScrubber.showCommits";
|
|
41144
|
+
var ALL_BOARDS_STORAGE_KEY = "epiq.timeScrubber.allBoards";
|
|
41145
|
+
var readStoredScope = () => {
|
|
41146
|
+
const stored = localStorage.getItem(SCOPE_STORAGE_KEY);
|
|
41147
|
+
return isScope(stored) ? stored : "all";
|
|
41148
|
+
};
|
|
41149
|
+
var TimeScrubber = ({
|
|
41150
|
+
timeline,
|
|
41151
|
+
commits,
|
|
41152
|
+
timeTravel,
|
|
41153
|
+
onScrub,
|
|
41154
|
+
onReturnToLive,
|
|
41155
|
+
onRequestHistory,
|
|
41156
|
+
boardId,
|
|
41157
|
+
connected,
|
|
41158
|
+
onInspectCommit
|
|
41159
|
+
}) => {
|
|
41160
|
+
const animate = !usePrefersReducedMotion();
|
|
41161
|
+
const trackRef = (0, import_react14.useRef)(null);
|
|
41162
|
+
const lastDispatchRef = (0, import_react14.useRef)(0);
|
|
41163
|
+
const [layoutMode, setLayoutMode] = (0, import_react14.useState)("even");
|
|
41164
|
+
const [scope, setScope] = (0, import_react14.useState)(readStoredScope);
|
|
41165
|
+
const [offset, setOffset] = (0, import_react14.useState)(0);
|
|
41166
|
+
const [dragFraction, setDragFraction] = (0, import_react14.useState)(null);
|
|
41167
|
+
const [collapsed, setCollapsed] = usePersistedFlag(
|
|
41168
|
+
COLLAPSED_STORAGE_KEY,
|
|
41169
|
+
false
|
|
41170
|
+
);
|
|
41171
|
+
const [showIssues, setShowIssues] = usePersistedFlag(
|
|
41172
|
+
SHOW_ISSUES_STORAGE_KEY,
|
|
41173
|
+
true
|
|
41174
|
+
);
|
|
41175
|
+
const [showCommits, setShowCommits] = usePersistedFlag(
|
|
41176
|
+
SHOW_COMMITS_STORAGE_KEY,
|
|
41177
|
+
true
|
|
41178
|
+
);
|
|
41179
|
+
const [allBoards, setAllBoards] = usePersistedFlag(
|
|
41180
|
+
ALL_BOARDS_STORAGE_KEY,
|
|
41181
|
+
false
|
|
41182
|
+
);
|
|
41183
|
+
const exitMs = layoutMode === "real" && animate ? DOT_EXIT_TOTAL_MS : 0;
|
|
41184
|
+
const issueScatter = useExitTransition(showIssues, exitMs);
|
|
41185
|
+
const commitScatter = useExitTransition(showCommits, exitMs);
|
|
41186
|
+
const [hoveredEvent, setHoveredEvent] = (0, import_react14.useState)(null);
|
|
41187
|
+
const [pointerFraction, setPointerFraction] = (0, import_react14.useState)(null);
|
|
41188
|
+
const [hoveredCommit, setHoveredCommit] = (0, import_react14.useState)(null);
|
|
41189
|
+
const [hoveredBucketIndex, setHoveredBucketIndex] = (0, import_react14.useState)(
|
|
41190
|
+
null
|
|
41191
|
+
);
|
|
41192
|
+
const [hoveredCommitBucketIndex, setHoveredCommitBucketIndex] = (0, import_react14.useState)(null);
|
|
41193
|
+
const periodRange = getPeriodRange(scope, offset);
|
|
41194
|
+
(0, import_react14.useEffect)(() => {
|
|
41195
|
+
if (!connected) return;
|
|
41196
|
+
onRequestHistory(periodRange?.start, periodRange?.end, allBoards);
|
|
41197
|
+
}, [scope, offset, boardId, allBoards, connected]);
|
|
41198
|
+
const changeScope = (nextScope) => {
|
|
41199
|
+
setScope(nextScope);
|
|
41200
|
+
setOffset(0);
|
|
41201
|
+
localStorage.setItem(SCOPE_STORAGE_KEY, nextScope);
|
|
41202
|
+
};
|
|
41203
|
+
const axis = buildAxis(timeline, commits);
|
|
41204
|
+
const issueCounts = bucketIssueCounts(axis, timeline);
|
|
41205
|
+
const commitStats = bucketCommitStats(axis, commits);
|
|
41206
|
+
const eventBuckets = timeline?.buckets ?? [];
|
|
41207
|
+
const maxIssueBucketCount = maxOf(issueCounts, 1);
|
|
41208
|
+
const maxEventCount = maxOf(
|
|
41209
|
+
eventBuckets.map((bucket) => bucket.count),
|
|
41210
|
+
1
|
|
41211
|
+
);
|
|
41212
|
+
const maxCommitCount = maxOf(
|
|
41213
|
+
Array.from(commitStats.values(), (stats) => stats.count),
|
|
41214
|
+
1
|
|
41215
|
+
);
|
|
41216
|
+
const issueBars = issueCounts.flatMap(
|
|
41217
|
+
(count, index2) => count > 0 ? [{ index: index2, intensity: count / maxIssueBucketCount }] : []
|
|
41218
|
+
);
|
|
41219
|
+
const commitBars = Array.from(commitStats, ([index2, stats]) => ({
|
|
41220
|
+
index: index2,
|
|
41221
|
+
intensity: stats.count / maxCommitCount
|
|
41222
|
+
}));
|
|
41223
|
+
const [animationGeneration, setAnimationGeneration] = (0, import_react14.useState)(0);
|
|
41224
|
+
const hasData = timeline !== null;
|
|
41225
|
+
(0, import_react14.useEffect)(() => {
|
|
41226
|
+
setAnimationGeneration((generation) => generation + 1);
|
|
41227
|
+
}, [scope, offset, boardId, allBoards, layoutMode, hasData]);
|
|
41228
|
+
const confirmedFraction = timeTravel.mode === "scrub" && timeTravel.asOfTime !== null ? axis.fractionForTime(timeTravel.asOfTime) : 1;
|
|
41229
|
+
const fractionFromClientX = (clientX) => {
|
|
41230
|
+
const track = trackRef.current;
|
|
41231
|
+
if (!track) return 0;
|
|
41232
|
+
const rect = track.getBoundingClientRect();
|
|
41233
|
+
return clamp((clientX - rect.left) / Math.max(1, rect.width), 0, 1);
|
|
41234
|
+
};
|
|
41235
|
+
const dispatchScrub = (fraction, force) => {
|
|
41236
|
+
const now = Date.now();
|
|
41237
|
+
if (!force && now - lastDispatchRef.current < SCRUB_THROTTLE_MS) return;
|
|
41238
|
+
lastDispatchRef.current = now;
|
|
41239
|
+
onScrub(axis.fractionToTime(fraction));
|
|
41240
|
+
};
|
|
41241
|
+
const endDrag = () => {
|
|
41242
|
+
if (dragFraction === null) return;
|
|
41243
|
+
dispatchScrub(dragFraction, true);
|
|
41244
|
+
setDragFraction(null);
|
|
41245
|
+
};
|
|
41246
|
+
const fractionFromEvent = (event) => {
|
|
41247
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
41248
|
+
return clamp((event.clientX - rect.left) / Math.max(1, rect.width), 0, 1);
|
|
41249
|
+
};
|
|
41250
|
+
const bucketIndexFromEvent = (event) => clamp(
|
|
41251
|
+
Math.floor(fractionFromEvent(event) * axis.bucketCount),
|
|
41252
|
+
0,
|
|
41253
|
+
axis.bucketCount - 1
|
|
41254
|
+
);
|
|
41255
|
+
const bucketTimeAt = (index2) => index2 !== null && index2 < axis.bucketCount ? axis.bucketTimeAt(index2) : void 0;
|
|
41256
|
+
const centreFraction = (index2) => (index2 + 0.5) / axis.bucketCount;
|
|
41257
|
+
const boardEventRow = (count) => `${count} board event${count === 1 ? "" : "s"}`;
|
|
41258
|
+
const hoveredBucketTime = bucketTimeAt(hoveredBucketIndex);
|
|
41259
|
+
const hoveredBucketCount = hoveredBucketIndex !== null ? issueCounts[hoveredBucketIndex] : void 0;
|
|
41260
|
+
const boardHint = layoutMode === "even" ? hoveredBucketTime !== void 0 && hoveredBucketCount !== void 0 ? {
|
|
41261
|
+
label: formatInterval(
|
|
41262
|
+
hoveredBucketTime,
|
|
41263
|
+
hoveredBucketTime + axis.bucketMs
|
|
41264
|
+
),
|
|
41265
|
+
rows: [boardEventRow(hoveredBucketCount)],
|
|
41266
|
+
fraction: centreFraction(hoveredBucketIndex),
|
|
41267
|
+
empty: hoveredBucketCount === 0
|
|
41268
|
+
} : null : hoveredEvent ? {
|
|
41269
|
+
label: hoveredEvent.label,
|
|
41270
|
+
rows: [boardEventRow(hoveredEvent.count)],
|
|
41271
|
+
fraction: hoveredEvent.fraction
|
|
41272
|
+
} : null;
|
|
41273
|
+
const hoveredCommitStats = hoveredCommitBucketIndex !== null ? commitStats.get(hoveredCommitBucketIndex) : void 0;
|
|
41274
|
+
const hoveredCommitBucketTime = bucketTimeAt(hoveredCommitBucketIndex);
|
|
41275
|
+
const commitHint = layoutMode === "even" ? hoveredCommitStats && hoveredCommitBucketTime !== void 0 ? {
|
|
41276
|
+
label: formatInterval(
|
|
41277
|
+
hoveredCommitBucketTime,
|
|
41278
|
+
hoveredCommitBucketTime + axis.bucketMs
|
|
41279
|
+
),
|
|
41280
|
+
rows: [
|
|
41281
|
+
`${hoveredCommitStats.count} commit${hoveredCommitStats.count === 1 ? "" : "s"}`,
|
|
41282
|
+
`${hoveredCommitStats.linesChanged.toLocaleString()} lines changed`
|
|
41283
|
+
],
|
|
41284
|
+
fraction: centreFraction(hoveredCommitBucketIndex)
|
|
41285
|
+
} : null : hoveredCommit ? {
|
|
41286
|
+
label: formatDateTime(new Date(hoveredCommit.commit.time)),
|
|
41287
|
+
rows: [
|
|
41288
|
+
hoveredCommit.commit.subject,
|
|
41289
|
+
`${hoveredCommit.commit.author} \u2022 ${hoveredCommit.commit.linesChanged.toLocaleString()} lines`
|
|
41290
|
+
],
|
|
41291
|
+
fraction: hoveredCommit.fraction
|
|
41292
|
+
} : null;
|
|
41293
|
+
const hoveredSegmentTime = (layoutMode === "even" ? hoveredBucketTime ?? bucketTimeAt(hoveredCommitBucketIndex) : (
|
|
41294
|
+
// A hovered point wins over the raw pointer, so the highlight agrees
|
|
41295
|
+
// with the tooltip's own moment.
|
|
41296
|
+
hoveredEvent?.t ?? hoveredCommit?.commit.time ?? (pointerFraction !== null ? axis.fractionToTime(pointerFraction) : void 0)
|
|
41297
|
+
)) ?? null;
|
|
41298
|
+
const segmentUnit = chooseSegmentUnit(axis.span);
|
|
41299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
41300
|
+
ScrubberLayout,
|
|
41301
|
+
{
|
|
41302
|
+
collapsed,
|
|
41303
|
+
onToggleCollapsed: () => setCollapsed(!collapsed),
|
|
41304
|
+
scrubbingAsOf: timeTravel.mode === "scrub" ? timeTravel.asOfTime ? formatDateTime(new Date(timeTravel.asOfTime)) : "" : null,
|
|
41305
|
+
controls: {
|
|
41306
|
+
scope,
|
|
41307
|
+
offset,
|
|
41308
|
+
periodRange,
|
|
41309
|
+
layoutMode,
|
|
41310
|
+
showIssues,
|
|
41311
|
+
showCommits,
|
|
41312
|
+
allBoards,
|
|
41313
|
+
isScrubbing: timeTravel.mode === "scrub",
|
|
41314
|
+
nowLabel: scope === "all" || offset === 0 ? "Now" : formatDateTime(new Date(axis.latest)),
|
|
41315
|
+
onChangeScope: changeScope,
|
|
41316
|
+
onChangeOffset: setOffset,
|
|
41317
|
+
onChangeLayoutMode: setLayoutMode,
|
|
41318
|
+
onChangeShowIssues: setShowIssues,
|
|
41319
|
+
onChangeShowCommits: setShowCommits,
|
|
41320
|
+
onChangeAllBoards: setAllBoards,
|
|
41321
|
+
onReturnToLive
|
|
41322
|
+
},
|
|
41323
|
+
chart: {
|
|
41324
|
+
trackRef,
|
|
41325
|
+
axis,
|
|
41326
|
+
layoutMode,
|
|
41327
|
+
animate,
|
|
41328
|
+
windowKey: `${layoutMode}-${animationGeneration}`,
|
|
41329
|
+
showIssues,
|
|
41330
|
+
showCommits,
|
|
41331
|
+
issueScatter,
|
|
41332
|
+
commitScatter,
|
|
41333
|
+
issueBars,
|
|
41334
|
+
issueBarRange: populatedRange(issueBars),
|
|
41335
|
+
commitBars,
|
|
41336
|
+
commitBarRange: populatedRange(commitBars),
|
|
41337
|
+
eventBuckets,
|
|
41338
|
+
maxEventCount,
|
|
41339
|
+
commits,
|
|
41340
|
+
hoveredCommitSha: hoveredCommit?.commit.sha ?? null,
|
|
41341
|
+
hoveredBucketIndex,
|
|
41342
|
+
hoveredCommitBucketIndex,
|
|
41343
|
+
hoveredSegment: hoveredSegmentTime !== null ? segmentAt(hoveredSegmentTime, segmentUnit) : null,
|
|
41344
|
+
thumbFraction: dragFraction ?? confirmedFraction,
|
|
41345
|
+
trackWidthPx: trackRef.current?.clientWidth ?? 0,
|
|
41346
|
+
boardHint,
|
|
41347
|
+
commitHint,
|
|
41348
|
+
on: {
|
|
41349
|
+
onPointerDown: (event) => {
|
|
41350
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
41351
|
+
const fraction = fractionFromClientX(event.clientX);
|
|
41352
|
+
setDragFraction(fraction);
|
|
41353
|
+
dispatchScrub(fraction, true);
|
|
41354
|
+
},
|
|
41355
|
+
onPointerMove: (event) => {
|
|
41356
|
+
if (dragFraction === null) return;
|
|
41357
|
+
const fraction = fractionFromClientX(event.clientX);
|
|
41358
|
+
setDragFraction(fraction);
|
|
41359
|
+
dispatchScrub(fraction, false);
|
|
41360
|
+
},
|
|
41361
|
+
onPointerEnd: endDrag,
|
|
41362
|
+
onTrackMouseMove: (event) => {
|
|
41363
|
+
if (layoutMode === "even") {
|
|
41364
|
+
setHoveredBucketIndex(bucketIndexFromEvent(event));
|
|
41365
|
+
return;
|
|
41366
|
+
}
|
|
41367
|
+
setPointerFraction(fractionFromEvent(event));
|
|
41368
|
+
},
|
|
41369
|
+
onTrackMouseLeave: () => {
|
|
41370
|
+
setHoveredBucketIndex(null);
|
|
41371
|
+
setPointerFraction(null);
|
|
41372
|
+
},
|
|
41373
|
+
onCommitTrackMouseEnter: () => setHoveredBucketIndex(null),
|
|
41374
|
+
onCommitTrackMouseMove: (event) => {
|
|
41375
|
+
event.stopPropagation();
|
|
41376
|
+
setHoveredCommitBucketIndex(bucketIndexFromEvent(event));
|
|
41377
|
+
},
|
|
41378
|
+
onCommitTrackMouseLeave: () => setHoveredCommitBucketIndex(null),
|
|
41379
|
+
onIssueDotEnter: (bucket) => setHoveredEvent({
|
|
41380
|
+
label: formatDateTime(new Date(bucket.t)),
|
|
41381
|
+
count: bucket.count,
|
|
41382
|
+
t: bucket.t,
|
|
41383
|
+
fraction: axis.fractionForTime(bucket.t)
|
|
41384
|
+
}),
|
|
41385
|
+
onIssueDotLeave: () => setHoveredEvent(null),
|
|
41386
|
+
onCommitDotEnter: (commit) => setHoveredCommit({
|
|
41387
|
+
commit,
|
|
41388
|
+
fraction: axis.fractionForTime(commit.time)
|
|
41389
|
+
}),
|
|
41390
|
+
onCommitDotLeave: () => setHoveredCommit(null),
|
|
41391
|
+
onInspectCommit
|
|
41392
|
+
}
|
|
41393
|
+
}
|
|
41394
|
+
}
|
|
41395
|
+
);
|
|
41396
|
+
};
|
|
41397
|
+
|
|
41398
|
+
// source/gui/client/lib/socket-send.ts
|
|
41399
|
+
var pending = /* @__PURE__ */ new WeakMap();
|
|
41400
|
+
var sendSocketJson = (socket, data2) => {
|
|
41401
|
+
if (!socket) return;
|
|
41402
|
+
const message = JSON.stringify(data2);
|
|
41403
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
41404
|
+
socket.send(message);
|
|
41405
|
+
return;
|
|
41406
|
+
}
|
|
41407
|
+
if (socket.readyState !== WebSocket.CONNECTING) return;
|
|
41408
|
+
const queued = pending.get(socket);
|
|
41409
|
+
if (queued) {
|
|
41410
|
+
queued.push(message);
|
|
41411
|
+
return;
|
|
41412
|
+
}
|
|
41413
|
+
pending.set(socket, [message]);
|
|
41414
|
+
socket.addEventListener(
|
|
41415
|
+
"open",
|
|
41416
|
+
() => {
|
|
41417
|
+
for (const queuedMessage of pending.get(socket) ?? []) {
|
|
41418
|
+
socket.send(queuedMessage);
|
|
41419
|
+
}
|
|
41420
|
+
pending.delete(socket);
|
|
41421
|
+
},
|
|
41422
|
+
{ once: true }
|
|
41423
|
+
);
|
|
41424
|
+
};
|
|
41425
|
+
|
|
39581
41426
|
// source/gui/client/lib/gui-move-issue.tsx
|
|
39582
41427
|
var toMovePosition = (targetIssues, targetIndex) => {
|
|
39583
41428
|
if (targetIssues.length === 0) return { at: "start" };
|
|
@@ -39655,16 +41500,14 @@ var moveIssue = (setState, socketRef) => (issueId, parentId, targetIndex) => {
|
|
|
39655
41500
|
};
|
|
39656
41501
|
});
|
|
39657
41502
|
if (!position3) return;
|
|
39658
|
-
socketRef.current
|
|
39659
|
-
|
|
39660
|
-
|
|
39661
|
-
|
|
39662
|
-
|
|
39663
|
-
|
|
39664
|
-
|
|
39665
|
-
|
|
39666
|
-
})
|
|
39667
|
-
);
|
|
41503
|
+
sendSocketJson(socketRef.current, {
|
|
41504
|
+
type: "issues:move",
|
|
41505
|
+
payload: {
|
|
41506
|
+
issueId,
|
|
41507
|
+
parentId,
|
|
41508
|
+
position: position3
|
|
41509
|
+
}
|
|
41510
|
+
});
|
|
39668
41511
|
};
|
|
39669
41512
|
|
|
39670
41513
|
// source/lib/utils/node-ref.ts
|
|
@@ -39709,6 +41552,30 @@ var updateIssueInGuiState = (state, issueId, updateIssue) => ({
|
|
|
39709
41552
|
}))
|
|
39710
41553
|
});
|
|
39711
41554
|
|
|
41555
|
+
// source/gui/client/lib/history-buffer.ts
|
|
41556
|
+
var createHistoryBuffer = (publish) => {
|
|
41557
|
+
let lastRequestId = 0;
|
|
41558
|
+
let pending2 = {};
|
|
41559
|
+
return {
|
|
41560
|
+
/** Starts a new window, abandoning whatever the previous one buffered. */
|
|
41561
|
+
open() {
|
|
41562
|
+
lastRequestId += 1;
|
|
41563
|
+
pending2 = { requestId: lastRequestId };
|
|
41564
|
+
return lastRequestId;
|
|
41565
|
+
},
|
|
41566
|
+
/** Files one half, ignoring replies to any request but the open one. */
|
|
41567
|
+
accept(requestId, half) {
|
|
41568
|
+
if (requestId === void 0) return;
|
|
41569
|
+
if (requestId !== pending2.requestId) return;
|
|
41570
|
+
pending2 = { ...pending2, ...half };
|
|
41571
|
+
const { timeline, commits } = pending2;
|
|
41572
|
+
if (!timeline || !commits) return;
|
|
41573
|
+
pending2 = {};
|
|
41574
|
+
publish({ timeline, commits });
|
|
41575
|
+
}
|
|
41576
|
+
};
|
|
41577
|
+
};
|
|
41578
|
+
|
|
39712
41579
|
// source/gui/client/lib/compress-image.ts
|
|
39713
41580
|
var MAX_LONG_EDGE = 1600;
|
|
39714
41581
|
var DEFAULT_MAX_KB = 500;
|
|
@@ -39774,8 +41641,8 @@ var blobToBase64 = (blob) => new Promise((resolve, reject) => {
|
|
|
39774
41641
|
});
|
|
39775
41642
|
|
|
39776
41643
|
// source/gui/client/App.tsx
|
|
39777
|
-
var
|
|
39778
|
-
var DropIndicator = () => /* @__PURE__ */ (0,
|
|
41644
|
+
var import_jsx_runtime32 = __toESM(require_jsx_runtime(), 1);
|
|
41645
|
+
var DropIndicator = () => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
39779
41646
|
"div",
|
|
39780
41647
|
{
|
|
39781
41648
|
style: {
|
|
@@ -39790,26 +41657,36 @@ var DropIndicator = () => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
|
39790
41657
|
var App = () => {
|
|
39791
41658
|
const { boardId, issueId } = useParams();
|
|
39792
41659
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
39793
|
-
const [connected, setConnected] = (0,
|
|
39794
|
-
const [syncStatus, setSyncStatus] = (0,
|
|
41660
|
+
const [connected, setConnected] = (0, import_react15.useState)(false);
|
|
41661
|
+
const [syncStatus, setSyncStatus] = (0, import_react15.useState)({
|
|
39795
41662
|
status: "synced",
|
|
39796
41663
|
msg: "idle"
|
|
39797
41664
|
});
|
|
39798
|
-
const [state, setState] = (0,
|
|
39799
|
-
const [
|
|
41665
|
+
const [state, setState] = (0, import_react15.useState)(null);
|
|
41666
|
+
const [contributors, setContributors] = (0, import_react15.useState)([]);
|
|
41667
|
+
const [history, setHistory] = (0, import_react15.useState)({ timeline: null, commits: [] });
|
|
41668
|
+
const [historyBuffer] = (0, import_react15.useState)(() => createHistoryBuffer(setHistory));
|
|
41669
|
+
const [commitInspectError, setCommitInspectError] = (0, import_react15.useState)(
|
|
41670
|
+
null
|
|
41671
|
+
);
|
|
41672
|
+
const [removeError, setRemoveError] = (0, import_react15.useState)(null);
|
|
41673
|
+
const [dragOverSwimlaneId, setDragOverSwimlaneId] = (0, import_react15.useState)(
|
|
39800
41674
|
null
|
|
39801
41675
|
);
|
|
39802
|
-
const [dropTarget, setDropTarget] = (0,
|
|
39803
|
-
const [boardMenuOpen, setBoardMenuOpen] = (0,
|
|
39804
|
-
const [createIssueModal, setCreateIssueModal] = (0,
|
|
39805
|
-
const boardMenuRef = (0,
|
|
39806
|
-
const socketRef = (0,
|
|
41676
|
+
const [dropTarget, setDropTarget] = (0, import_react15.useState)(null);
|
|
41677
|
+
const [boardMenuOpen, setBoardMenuOpen] = (0, import_react15.useState)(false);
|
|
41678
|
+
const [createIssueModal, setCreateIssueModal] = (0, import_react15.useState)(null);
|
|
41679
|
+
const boardMenuRef = (0, import_react15.useRef)(null);
|
|
41680
|
+
const socketRef = (0, import_react15.useRef)(null);
|
|
39807
41681
|
const selectedTab = searchParams.get("tab") === "comments" ? "comments" : "overview";
|
|
39808
41682
|
const navigate = useNavigate();
|
|
39809
41683
|
const selectedBoard = (state && boardId ? findBoard(state, boardId) : null) ?? state?.boards[0] ?? null;
|
|
41684
|
+
const selectedBoardId = selectedBoard?.id ?? null;
|
|
41685
|
+
const selectedBoardIdRef = (0, import_react15.useRef)(selectedBoardId);
|
|
41686
|
+
selectedBoardIdRef.current = selectedBoardId;
|
|
39810
41687
|
const boardSlug = selectedBoard?.ref ?? boardId;
|
|
39811
41688
|
const selectedIssue = state && issueId ? findIssue(state, issueId) : null;
|
|
39812
|
-
(0,
|
|
41689
|
+
(0, import_react15.useEffect)(() => {
|
|
39813
41690
|
const onPaste = (event) => {
|
|
39814
41691
|
if (!selectedIssue || selectedIssue.readonly) return;
|
|
39815
41692
|
const target = event.target;
|
|
@@ -39830,18 +41707,18 @@ var App = () => {
|
|
|
39830
41707
|
};
|
|
39831
41708
|
const commentsByIssueId = state?.commentsByIssueId ?? {};
|
|
39832
41709
|
const attachmentsByIssueId = state?.attachmentsByIssueId ?? {};
|
|
39833
|
-
const [attachmentUploadStatus, setAttachmentUploadStatus] = (0,
|
|
41710
|
+
const [attachmentUploadStatus, setAttachmentUploadStatus] = (0, import_react15.useState)({ state: "idle" });
|
|
39834
41711
|
const requestState = () => {
|
|
39835
|
-
socketRef.current
|
|
41712
|
+
sendSocketJson(socketRef.current, { type: "state:get" });
|
|
39836
41713
|
};
|
|
39837
|
-
(0,
|
|
41714
|
+
(0, import_react15.useEffect)(() => {
|
|
39838
41715
|
const socket = new WebSocket(
|
|
39839
41716
|
`ws://${window.location.host}/ws${boardId ? `?boardId=${boardId}` : ""}`
|
|
39840
41717
|
);
|
|
39841
41718
|
socketRef.current = socket;
|
|
39842
41719
|
socket.addEventListener("open", () => {
|
|
39843
41720
|
setConnected(true);
|
|
39844
|
-
socket
|
|
41721
|
+
sendSocketJson(socket, { type: "state:get" });
|
|
39845
41722
|
});
|
|
39846
41723
|
socket.addEventListener("close", () => {
|
|
39847
41724
|
setConnected(false);
|
|
@@ -39867,6 +41744,40 @@ var App = () => {
|
|
|
39867
41744
|
console.log("Failed", message);
|
|
39868
41745
|
requestState();
|
|
39869
41746
|
}
|
|
41747
|
+
if (message.type === "timeline") {
|
|
41748
|
+
const nextTimeline = getResultValue(message.payload);
|
|
41749
|
+
if (nextTimeline) {
|
|
41750
|
+
historyBuffer.accept(message.requestId, { timeline: nextTimeline });
|
|
41751
|
+
}
|
|
41752
|
+
}
|
|
41753
|
+
if (message.type === "contributor:remove:result" || message.type === "issue:assignee:add:result") {
|
|
41754
|
+
sendSocketJson(socketRef.current, {
|
|
41755
|
+
type: "contributors:get",
|
|
41756
|
+
payload: { boardId: selectedBoardIdRef.current }
|
|
41757
|
+
});
|
|
41758
|
+
}
|
|
41759
|
+
if (message.type === "contributor:remove:result" && message.payload?.status === "fail") {
|
|
41760
|
+
setRemoveError(
|
|
41761
|
+
`Couldn't remove a contributor: ${message.payload.message}`
|
|
41762
|
+
);
|
|
41763
|
+
}
|
|
41764
|
+
if (message.type === "contributors") {
|
|
41765
|
+
const next = getResultValue(message.payload);
|
|
41766
|
+
if (next) setContributors(next);
|
|
41767
|
+
}
|
|
41768
|
+
if (message.type === "commits") {
|
|
41769
|
+
const nextCommits = getResultValue(message.payload);
|
|
41770
|
+
if (nextCommits) {
|
|
41771
|
+
historyBuffer.accept(message.requestId, { commits: nextCommits });
|
|
41772
|
+
}
|
|
41773
|
+
}
|
|
41774
|
+
if (message.type === "commit:inspect:result" && message.payload?.status === "fail") {
|
|
41775
|
+
setCommitInspectError(message.payload.message);
|
|
41776
|
+
}
|
|
41777
|
+
if (message.type === "time-travel:result" && message.payload?.status === "fail") {
|
|
41778
|
+
console.log("Time travel failed", message);
|
|
41779
|
+
requestState();
|
|
41780
|
+
}
|
|
39870
41781
|
if (message.type === "sync-status") {
|
|
39871
41782
|
setSyncStatus(message.payload);
|
|
39872
41783
|
}
|
|
@@ -39878,12 +41789,12 @@ var App = () => {
|
|
|
39878
41789
|
socket.close();
|
|
39879
41790
|
};
|
|
39880
41791
|
}, [boardId, navigate]);
|
|
39881
|
-
(0,
|
|
41792
|
+
(0, import_react15.useEffect)(() => {
|
|
39882
41793
|
if (!boardId && state?.boards[0]) {
|
|
39883
41794
|
void navigate(`/board/${state.boards[0].ref}`, { replace: true });
|
|
39884
41795
|
}
|
|
39885
41796
|
}, [boardId, state, navigate]);
|
|
39886
|
-
(0,
|
|
41797
|
+
(0, import_react15.useEffect)(() => {
|
|
39887
41798
|
const close = (event) => {
|
|
39888
41799
|
if (boardMenuRef.current && !boardMenuRef.current.contains(event.target)) {
|
|
39889
41800
|
setBoardMenuOpen(false);
|
|
@@ -39897,7 +41808,7 @@ var App = () => {
|
|
|
39897
41808
|
setDropTarget(null);
|
|
39898
41809
|
};
|
|
39899
41810
|
const send = (type, payload) => {
|
|
39900
|
-
socketRef.current
|
|
41811
|
+
sendSocketJson(socketRef.current, { type, payload });
|
|
39901
41812
|
};
|
|
39902
41813
|
const selectIssue = (nextIssueId) => {
|
|
39903
41814
|
if (!boardSlug) return;
|
|
@@ -39971,7 +41882,22 @@ var App = () => {
|
|
|
39971
41882
|
});
|
|
39972
41883
|
send("issue:tag:remove", { issueId: issueId2, tagId });
|
|
39973
41884
|
};
|
|
39974
|
-
const addIssueAssignee = (issueId2,
|
|
41885
|
+
const addIssueAssignee = (issueId2, assigneeId) => {
|
|
41886
|
+
const picked = contributors.find((c) => c.id === assigneeId);
|
|
41887
|
+
setState((prev) => {
|
|
41888
|
+
if (!prev || !picked) return prev;
|
|
41889
|
+
return updateIssueInGuiState(
|
|
41890
|
+
prev,
|
|
41891
|
+
issueId2,
|
|
41892
|
+
(issue) => issue.assignees.some((assignee) => assignee.id === assigneeId) ? issue : { ...issue, assignees: [...issue.assignees, picked] }
|
|
41893
|
+
);
|
|
41894
|
+
});
|
|
41895
|
+
send("issue:assignee:add", { issueId: issueId2, assigneeId });
|
|
41896
|
+
};
|
|
41897
|
+
const removeContributor = (contributorId) => {
|
|
41898
|
+
send("contributor:remove", { contributorId });
|
|
41899
|
+
};
|
|
41900
|
+
const addExternalIssueAssignee = (issueId2, assigneeName) => {
|
|
39975
41901
|
setState((prev) => {
|
|
39976
41902
|
if (!prev) return prev;
|
|
39977
41903
|
return updateIssueInGuiState(prev, issueId2, (issue) => {
|
|
@@ -39991,7 +41917,7 @@ var App = () => {
|
|
|
39991
41917
|
};
|
|
39992
41918
|
});
|
|
39993
41919
|
});
|
|
39994
|
-
send("issue:assignee:add", { issueId: issueId2, assigneeName });
|
|
41920
|
+
send("issue:assignee:add", { issueId: issueId2, assigneeName, createUnlinked: true });
|
|
39995
41921
|
};
|
|
39996
41922
|
const removeIssueAssignee = (issueId2, assigneeId) => {
|
|
39997
41923
|
setState((prev) => {
|
|
@@ -40025,6 +41951,53 @@ var App = () => {
|
|
|
40025
41951
|
});
|
|
40026
41952
|
send("issue:reopen", { issueId: issueId2 });
|
|
40027
41953
|
};
|
|
41954
|
+
const scrubToTime = (targetTime) => {
|
|
41955
|
+
send("time-travel:scrub", { targetTime });
|
|
41956
|
+
};
|
|
41957
|
+
const returnToLive = () => {
|
|
41958
|
+
send("time-travel:live", {});
|
|
41959
|
+
};
|
|
41960
|
+
const requestBoardHistory = (0, import_react15.useCallback)(
|
|
41961
|
+
(start2, end, allBoards) => {
|
|
41962
|
+
const window2 = start2 !== void 0 ? { start: start2, end } : void 0;
|
|
41963
|
+
const requestId = historyBuffer.open();
|
|
41964
|
+
sendSocketJson(socketRef.current, {
|
|
41965
|
+
type: "timeline:get",
|
|
41966
|
+
payload: {
|
|
41967
|
+
...window2,
|
|
41968
|
+
boardId: allBoards ? void 0 : selectedBoardId,
|
|
41969
|
+
requestId
|
|
41970
|
+
}
|
|
41971
|
+
});
|
|
41972
|
+
sendSocketJson(socketRef.current, {
|
|
41973
|
+
type: "commits:get",
|
|
41974
|
+
payload: { ...window2, requestId }
|
|
41975
|
+
});
|
|
41976
|
+
},
|
|
41977
|
+
[selectedBoardId]
|
|
41978
|
+
);
|
|
41979
|
+
const requestContributors = (0, import_react15.useCallback)(() => {
|
|
41980
|
+
sendSocketJson(socketRef.current, {
|
|
41981
|
+
type: "contributors:get",
|
|
41982
|
+
payload: { boardId: selectedBoardIdRef.current }
|
|
41983
|
+
});
|
|
41984
|
+
}, []);
|
|
41985
|
+
(0, import_react15.useEffect)(() => {
|
|
41986
|
+
setContributors([]);
|
|
41987
|
+
}, [selectedBoardId]);
|
|
41988
|
+
const inspectCommit = (0, import_react15.useCallback)((sha) => {
|
|
41989
|
+
sendSocketJson(socketRef.current, { type: "commit:inspect", payload: { sha } });
|
|
41990
|
+
}, []);
|
|
41991
|
+
(0, import_react15.useEffect)(() => {
|
|
41992
|
+
if (!commitInspectError) return;
|
|
41993
|
+
const timeout = setTimeout(() => setCommitInspectError(null), 8e3);
|
|
41994
|
+
return () => clearTimeout(timeout);
|
|
41995
|
+
}, [commitInspectError]);
|
|
41996
|
+
(0, import_react15.useEffect)(() => {
|
|
41997
|
+
if (!removeError) return;
|
|
41998
|
+
const timeout = setTimeout(() => setRemoveError(null), 8e3);
|
|
41999
|
+
return () => clearTimeout(timeout);
|
|
42000
|
+
}, [removeError]);
|
|
40028
42001
|
const selectBoard = (nextBoardId) => {
|
|
40029
42002
|
setBoardMenuOpen(false);
|
|
40030
42003
|
clearDragState();
|
|
@@ -40147,7 +42120,7 @@ var App = () => {
|
|
|
40147
42120
|
});
|
|
40148
42121
|
send("issue:comment:delete", { commentId });
|
|
40149
42122
|
};
|
|
40150
|
-
return /* @__PURE__ */ (0,
|
|
42123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
40151
42124
|
"div",
|
|
40152
42125
|
{
|
|
40153
42126
|
style: {
|
|
@@ -40159,8 +42132,37 @@ var App = () => {
|
|
|
40159
42132
|
flexDirection: "column"
|
|
40160
42133
|
},
|
|
40161
42134
|
children: [
|
|
40162
|
-
/* @__PURE__ */ (0,
|
|
40163
|
-
/* @__PURE__ */ (0,
|
|
42135
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(GlobalScrollbarStyles, {}),
|
|
42136
|
+
commitInspectError && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
42137
|
+
ErrorToast,
|
|
42138
|
+
{
|
|
42139
|
+
message: `Couldn't open commit diff: ${commitInspectError}`,
|
|
42140
|
+
onDismiss: () => setCommitInspectError(null)
|
|
42141
|
+
}
|
|
42142
|
+
),
|
|
42143
|
+
removeError && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
42144
|
+
ErrorToast,
|
|
42145
|
+
{
|
|
42146
|
+
message: removeError,
|
|
42147
|
+
onDismiss: () => setRemoveError(null)
|
|
42148
|
+
}
|
|
42149
|
+
),
|
|
42150
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Header, { state, connected, syncStatus }),
|
|
42151
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
42152
|
+
TimeScrubber,
|
|
42153
|
+
{
|
|
42154
|
+
timeline: history.timeline,
|
|
42155
|
+
commits: history.commits,
|
|
42156
|
+
boardId: selectedBoardId,
|
|
42157
|
+
connected,
|
|
42158
|
+
onRequestHistory: requestBoardHistory,
|
|
42159
|
+
onInspectCommit: inspectCommit,
|
|
42160
|
+
timeTravel: state?.timeTravel ?? { mode: "live", asOfTime: null },
|
|
42161
|
+
onScrub: scrubToTime,
|
|
42162
|
+
onReturnToLive: returnToLive
|
|
42163
|
+
}
|
|
42164
|
+
),
|
|
42165
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
40164
42166
|
"div",
|
|
40165
42167
|
{
|
|
40166
42168
|
style: {
|
|
@@ -40169,47 +42171,76 @@ var App = () => {
|
|
|
40169
42171
|
overflow: "hidden"
|
|
40170
42172
|
},
|
|
40171
42173
|
children: [
|
|
40172
|
-
/* @__PURE__ */ (0,
|
|
40173
|
-
|
|
40174
|
-
|
|
40175
|
-
{
|
|
40176
|
-
|
|
40177
|
-
|
|
40178
|
-
|
|
40179
|
-
|
|
40180
|
-
|
|
40181
|
-
|
|
40182
|
-
|
|
40183
|
-
|
|
40184
|
-
|
|
40185
|
-
|
|
40186
|
-
|
|
40187
|
-
|
|
40188
|
-
|
|
40189
|
-
|
|
40190
|
-
|
|
40191
|
-
|
|
40192
|
-
|
|
40193
|
-
|
|
40194
|
-
|
|
40195
|
-
|
|
40196
|
-
|
|
40197
|
-
|
|
40198
|
-
|
|
40199
|
-
|
|
40200
|
-
|
|
40201
|
-
|
|
40202
|
-
|
|
40203
|
-
|
|
40204
|
-
|
|
40205
|
-
|
|
40206
|
-
|
|
40207
|
-
|
|
40208
|
-
|
|
40209
|
-
|
|
40210
|
-
|
|
40211
|
-
|
|
40212
|
-
|
|
42174
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
42175
|
+
"main",
|
|
42176
|
+
{
|
|
42177
|
+
style: {
|
|
42178
|
+
// No bottom padding: the board row is the horizontal scroll
|
|
42179
|
+
// container, and a gap below it would strand its scrollbar.
|
|
42180
|
+
padding: "0 30px 0 30px",
|
|
42181
|
+
flex: 1,
|
|
42182
|
+
minHeight: 0,
|
|
42183
|
+
display: "flex",
|
|
42184
|
+
flexDirection: "column",
|
|
42185
|
+
overflow: "hidden"
|
|
42186
|
+
},
|
|
42187
|
+
children: [
|
|
42188
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { style: { padding: "20px 10px" }, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
42189
|
+
Dropdown,
|
|
42190
|
+
{
|
|
42191
|
+
testId: "board-switcher",
|
|
42192
|
+
label: "Board:",
|
|
42193
|
+
value: selectedBoard ? {
|
|
42194
|
+
id: selectedBoard.id,
|
|
42195
|
+
label: selectedBoard.title
|
|
42196
|
+
} : null,
|
|
42197
|
+
items: state?.boards.map((board) => ({
|
|
42198
|
+
id: board.id,
|
|
42199
|
+
label: board.title
|
|
42200
|
+
})) ?? [],
|
|
42201
|
+
placeholder: "Loading...",
|
|
42202
|
+
onSelect: selectBoard
|
|
42203
|
+
}
|
|
42204
|
+
) }),
|
|
42205
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
42206
|
+
"div",
|
|
42207
|
+
{
|
|
42208
|
+
style: {
|
|
42209
|
+
display: "flex",
|
|
42210
|
+
gap: 8,
|
|
42211
|
+
flex: 1,
|
|
42212
|
+
minHeight: 0,
|
|
42213
|
+
overflowX: "auto",
|
|
42214
|
+
overflowY: "hidden"
|
|
42215
|
+
},
|
|
42216
|
+
children: [
|
|
42217
|
+
selectedBoard?.swimlanes.map((swimlane) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
42218
|
+
SwimlaneColumn,
|
|
42219
|
+
{
|
|
42220
|
+
swimlane,
|
|
42221
|
+
selected: false,
|
|
42222
|
+
selectedIssueId: selectedIssue?.id ?? null,
|
|
42223
|
+
commentsByIssueId,
|
|
42224
|
+
dragOver: dragOverSwimlaneId === swimlane.id,
|
|
42225
|
+
dropIndex: dropTarget?.swimlaneId === swimlane.id ? dropTarget.index : null,
|
|
42226
|
+
onSelectIssue: selectIssue,
|
|
42227
|
+
onSelectIssueComments: selectIssueComments,
|
|
42228
|
+
onCreateIssue: openCreateIssueModal,
|
|
42229
|
+
onDropIssue: moveIssue(setState, socketRef),
|
|
42230
|
+
onDragOver: setDragOverSwimlaneId,
|
|
42231
|
+
onDragOverIssue: (swimlaneId, index2) => setDropTarget({ swimlaneId, index: index2 }),
|
|
42232
|
+
onDragLeave: clearDragState
|
|
42233
|
+
},
|
|
42234
|
+
swimlane.id
|
|
42235
|
+
)),
|
|
42236
|
+
!(selectedIssue && state?.user) && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { style: { width: ASIDE_WIDTH, flexShrink: 0 } })
|
|
42237
|
+
]
|
|
42238
|
+
}
|
|
42239
|
+
)
|
|
42240
|
+
]
|
|
42241
|
+
}
|
|
42242
|
+
),
|
|
42243
|
+
selectedIssue && state?.user && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
40213
42244
|
IssueDetails,
|
|
40214
42245
|
{
|
|
40215
42246
|
whoAmI: state.user,
|
|
@@ -40223,6 +42254,8 @@ var App = () => {
|
|
|
40223
42254
|
onAddTag: addIssueTag,
|
|
40224
42255
|
onRemoveTag: removeIssueTag,
|
|
40225
42256
|
onAddAssignee: addIssueAssignee,
|
|
42257
|
+
onAddExternalAssignee: addExternalIssueAssignee,
|
|
42258
|
+
onRemoveContributor: removeContributor,
|
|
40226
42259
|
onRemoveAssignee: removeIssueAssignee,
|
|
40227
42260
|
onAddComment: addIssueComment,
|
|
40228
42261
|
onDeleteComment: deleteIssueComment,
|
|
@@ -40233,13 +42266,14 @@ var App = () => {
|
|
|
40233
42266
|
onReopenIssue: reopenIssue,
|
|
40234
42267
|
onCloseIssue: closeIssue,
|
|
40235
42268
|
knownTags: state.tags ?? [],
|
|
40236
|
-
knownAssignees:
|
|
42269
|
+
knownAssignees: contributors,
|
|
42270
|
+
onOpenAssigneePicker: requestContributors
|
|
40237
42271
|
}
|
|
40238
42272
|
)
|
|
40239
42273
|
]
|
|
40240
42274
|
}
|
|
40241
42275
|
),
|
|
40242
|
-
createIssueModal && /* @__PURE__ */ (0,
|
|
42276
|
+
createIssueModal && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
40243
42277
|
CreateIssueModal,
|
|
40244
42278
|
{
|
|
40245
42279
|
title: createIssueModal.title,
|
|
@@ -40254,14 +42288,14 @@ var App = () => {
|
|
|
40254
42288
|
};
|
|
40255
42289
|
|
|
40256
42290
|
// source/gui/client/main.tsx
|
|
40257
|
-
var
|
|
42291
|
+
var import_jsx_runtime33 = __toESM(require_jsx_runtime(), 1);
|
|
40258
42292
|
(0, import_client.createRoot)(document.getElementById("root")).render(
|
|
40259
|
-
/* @__PURE__ */ (0,
|
|
40260
|
-
/* @__PURE__ */ (0,
|
|
40261
|
-
/* @__PURE__ */ (0,
|
|
40262
|
-
/* @__PURE__ */ (0,
|
|
40263
|
-
/* @__PURE__ */ (0,
|
|
40264
|
-
/* @__PURE__ */ (0,
|
|
42293
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(BrowserRouter, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Routes, { children: [
|
|
42294
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(App, {}) }),
|
|
42295
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Route, { path: "/board/:boardId", element: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(App, {}) }),
|
|
42296
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Route, { path: "/board/:boardId/issue/:issueId", element: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(App, {}) }),
|
|
42297
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Route, { path: "/board/:boardId/:issueId", element: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(App, {}) }),
|
|
42298
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Navigate, { to: "/", replace: true }) })
|
|
40265
42299
|
] }) })
|
|
40266
42300
|
);
|
|
40267
42301
|
/*! Bundled license information:
|