@industry-theme/backlogmd-kanban-panel 1.0.24 → 1.0.26

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.
@@ -3740,37 +3740,29 @@ const createLucideIcon = (iconName, iconNode) => {
3740
3740
  * This source code is licensed under the ISC license.
3741
3741
  * See the LICENSE file in the root directory of this source tree.
3742
3742
  */
3743
- const __iconNode$o = [
3743
+ const __iconNode$n = [
3744
3744
  ["path", { d: "M8 2v4", key: "1cmpym" }],
3745
3745
  ["path", { d: "M16 2v4", key: "4m81vk" }],
3746
3746
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
3747
3747
  ["path", { d: "M3 10h18", key: "8toen8" }]
3748
3748
  ];
3749
- const Calendar = createLucideIcon("calendar", __iconNode$o);
3749
+ const Calendar = createLucideIcon("calendar", __iconNode$n);
3750
3750
  /**
3751
3751
  * @license lucide-react v0.552.0 - ISC
3752
3752
  *
3753
3753
  * This source code is licensed under the ISC license.
3754
3754
  * See the LICENSE file in the root directory of this source tree.
3755
3755
  */
3756
- const __iconNode$n = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
3757
- const Check = createLucideIcon("check", __iconNode$n);
3756
+ const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
3757
+ const Check = createLucideIcon("check", __iconNode$m);
3758
3758
  /**
3759
3759
  * @license lucide-react v0.552.0 - ISC
3760
3760
  *
3761
3761
  * This source code is licensed under the ISC license.
3762
3762
  * See the LICENSE file in the root directory of this source tree.
3763
3763
  */
3764
- const __iconNode$m = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
3765
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$m);
3766
- /**
3767
- * @license lucide-react v0.552.0 - ISC
3768
- *
3769
- * This source code is licensed under the ISC license.
3770
- * See the LICENSE file in the root directory of this source tree.
3771
- */
3772
- const __iconNode$l = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
3773
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$l);
3764
+ const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
3765
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
3774
3766
  /**
3775
3767
  * @license lucide-react v0.552.0 - ISC
3776
3768
  *
@@ -6149,7 +6141,8 @@ function useKanbanData(options) {
6149
6141
  const TaskCard = ({
6150
6142
  task,
6151
6143
  onClick,
6152
- isDragOverlay = false
6144
+ isDragOverlay = false,
6145
+ isSelected = false
6153
6146
  }) => {
6154
6147
  const { theme: theme2 } = useTheme();
6155
6148
  const {
@@ -6176,10 +6169,10 @@ const TaskCard = ({
6176
6169
  };
6177
6170
  const style2 = {
6178
6171
  flexShrink: 0,
6179
- background: theme2.colors.surface,
6172
+ background: isSelected ? `${theme2.colors.primary}10` : theme2.colors.surface,
6180
6173
  borderRadius: theme2.radii[2],
6181
6174
  padding: "12px",
6182
- border: `1px solid ${theme2.colors.border}`,
6175
+ border: `1px solid ${isSelected ? theme2.colors.primary : theme2.colors.border}`,
6183
6176
  borderLeft: `4px solid ${getPriorityColor(task.priority)}`,
6184
6177
  cursor: isDragOverlay ? "grabbing" : "grab",
6185
6178
  transition: isDragging ? "none" : "all 0.2s ease",
@@ -6189,6 +6182,10 @@ const TaskCard = ({
6189
6182
  // When dragging, the original card stays in place but becomes a placeholder
6190
6183
  // The DragOverlay handles the visual movement
6191
6184
  opacity: isDragging ? 0.4 : 1,
6185
+ // Selected card styling
6186
+ ...isSelected && !isDragOverlay && {
6187
+ boxShadow: `0 0 0 1px ${theme2.colors.primary}`
6188
+ },
6192
6189
  // Overlay card styling
6193
6190
  ...isDragOverlay && {
6194
6191
  boxShadow: `0 8px 16px rgba(0, 0, 0, 0.15)`,
@@ -6328,7 +6325,8 @@ const KanbanColumn = ({
6328
6325
  isLoadingMore = false,
6329
6326
  onLoadMore,
6330
6327
  onTaskClick,
6331
- fullWidth = false
6328
+ fullWidth = false,
6329
+ selectedTaskId
6332
6330
  }) => {
6333
6331
  const { theme: theme2 } = useTheme();
6334
6332
  const { setNodeRef, isOver } = useDroppable({
@@ -6417,7 +6415,8 @@ const KanbanColumn = ({
6417
6415
  TaskCard,
6418
6416
  {
6419
6417
  task,
6420
- onClick: onTaskClick
6418
+ onClick: onTaskClick,
6419
+ isSelected: selectedTaskId === task.id
6421
6420
  },
6422
6421
  task.id
6423
6422
  )),
@@ -6741,6 +6740,7 @@ const TaskModal = ({
6741
6740
  onSave,
6742
6741
  task,
6743
6742
  defaultStatus = "To Do",
6743
+ defaultMilestone = "",
6744
6744
  availableStatuses = ["To Do", "In Progress", "Done"],
6745
6745
  availableMilestones = []
6746
6746
  }) => {
@@ -6773,11 +6773,11 @@ const TaskModal = ({
6773
6773
  setPriority("medium");
6774
6774
  setLabels("");
6775
6775
  setAssignee("");
6776
- setMilestone("");
6776
+ setMilestone(defaultMilestone);
6777
6777
  }
6778
6778
  setError(null);
6779
6779
  }
6780
- }, [isOpen, task, defaultStatus]);
6780
+ }, [isOpen, task, defaultStatus, defaultMilestone]);
6781
6781
  const handleSubmit = async (e) => {
6782
6782
  e.preventDefault();
6783
6783
  if (!title.trim()) {
@@ -7154,7 +7154,7 @@ const TaskModal = ({
7154
7154
  },
7155
7155
  children: [
7156
7156
  /* @__PURE__ */ jsx("option", { value: "", children: "None" }),
7157
- availableMilestones.map((m) => /* @__PURE__ */ jsx("option", { value: m, children: m }, m))
7157
+ availableMilestones.map((m) => /* @__PURE__ */ jsx("option", { value: m.id, children: m.title }, m.id))
7158
7158
  ]
7159
7159
  }
7160
7160
  )
@@ -7315,6 +7315,11 @@ function useMilestoneData(options) {
7315
7315
  try {
7316
7316
  const files = fileTreeSlice.data.allFiles;
7317
7317
  const filePaths = files.map((f) => f.path);
7318
+ const taskPaths = filePaths.filter((p2) => p2.includes("backlog/tasks/"));
7319
+ console.log(`[useMilestoneData] File paths: ${filePaths.length} total, ${taskPaths.length} task files`);
7320
+ if (taskPaths.length > 0) {
7321
+ console.log(`[useMilestoneData] Sample task paths:`, taskPaths.slice(0, 3));
7322
+ }
7318
7323
  const fs = new PanelFileSystemAdapter({
7319
7324
  fetchFile: fetchFileContent,
7320
7325
  filePaths,
@@ -7337,6 +7342,11 @@ function useMilestoneData(options) {
7337
7342
  setCanWrite(fs.canWrite);
7338
7343
  await core2.initializeLazy(filePaths);
7339
7344
  coreRef.current = core2;
7345
+ const taskIndex = core2.taskIndex;
7346
+ if (taskIndex) {
7347
+ const indexedIds = Array.from(taskIndex.keys());
7348
+ console.log(`[useMilestoneData] Core taskIndex has ${indexedIds.length} tasks:`, indexedIds.slice(0, 5));
7349
+ }
7340
7350
  console.log("[useMilestoneData] Core instance:", core2);
7341
7351
  console.log("[useMilestoneData] Core.listMilestones:", typeof core2.listMilestones);
7342
7352
  console.log("[useMilestoneData] Core prototype:", Object.getPrototypeOf(core2));
@@ -7348,12 +7358,32 @@ function useMilestoneData(options) {
7348
7358
  }
7349
7359
  const milestoneList = await core2.listMilestones();
7350
7360
  console.log(`[useMilestoneData] Loaded ${milestoneList.length} milestones`);
7351
- const milestoneStates = milestoneList.map((m) => ({
7352
- milestone: m,
7353
- tasks: [],
7354
- isLoading: false,
7355
- isExpanded: false
7356
- }));
7361
+ const allTaskIds = milestoneList.flatMap((m) => m.tasks);
7362
+ const uniqueTaskIds = [...new Set(allTaskIds)];
7363
+ console.log(`[useMilestoneData] Milestone task IDs to load:`, uniqueTaskIds.slice(0, 5), `(${uniqueTaskIds.length} total)`);
7364
+ let allTasks = [];
7365
+ if (uniqueTaskIds.length > 0) {
7366
+ try {
7367
+ allTasks = await core2.loadTasksByIds(uniqueTaskIds);
7368
+ console.log(`[useMilestoneData] Pre-loaded ${allTasks.length} tasks for progress`);
7369
+ if (allTasks.length > 0) {
7370
+ console.log(`[useMilestoneData] Sample task IDs:`, allTasks.slice(0, 5).map((t) => t.id));
7371
+ }
7372
+ } catch (err) {
7373
+ console.warn("[useMilestoneData] Failed to pre-load tasks:", err);
7374
+ }
7375
+ }
7376
+ const taskMap = new Map(allTasks.map((t) => [t.id, t]));
7377
+ const milestoneStates = milestoneList.map((m) => {
7378
+ const loadedTasks = m.tasks.map((id) => taskMap.get(id)).filter((t) => !!t);
7379
+ console.log(`[useMilestoneData] Milestone ${m.id}: ${m.tasks.length} task IDs, ${loadedTasks.length} loaded`);
7380
+ return {
7381
+ milestone: m,
7382
+ tasks: loadedTasks,
7383
+ isLoading: false,
7384
+ isExpanded: false
7385
+ };
7386
+ });
7357
7387
  fileTreeVersionRef.current = currentVersion;
7358
7388
  setMilestones(milestoneStates);
7359
7389
  } catch (err) {
@@ -7448,356 +7478,6 @@ function useMilestoneData(options) {
7448
7478
  core: coreRef.current
7449
7479
  };
7450
7480
  }
7451
- const MilestoneCard = ({
7452
- milestoneState,
7453
- onToggle,
7454
- onTaskClick
7455
- }) => {
7456
- const { theme: theme2 } = useTheme();
7457
- const { milestone, tasks, isLoading, isExpanded } = milestoneState;
7458
- const totalTasks = milestone.tasks.length;
7459
- const doneTasks = tasks.filter(
7460
- (t) => {
7461
- var _a, _b;
7462
- return ((_a = t.status) == null ? void 0 : _a.toLowerCase().includes("done")) || ((_b = t.status) == null ? void 0 : _b.toLowerCase().includes("complete"));
7463
- }
7464
- ).length;
7465
- const progress = totalTasks > 0 ? Math.round(doneTasks / totalTasks * 100) : 0;
7466
- const showProgress = tasks.length > 0 || totalTasks === 0;
7467
- const getPriorityColor = (priority) => {
7468
- switch (priority) {
7469
- case "high":
7470
- return theme2.colors.error;
7471
- case "medium":
7472
- return theme2.colors.warning;
7473
- case "low":
7474
- return theme2.colors.info;
7475
- default:
7476
- return theme2.colors.border;
7477
- }
7478
- };
7479
- return /* @__PURE__ */ jsxs(
7480
- "div",
7481
- {
7482
- style: {
7483
- flexShrink: 0,
7484
- background: theme2.colors.surface,
7485
- borderRadius: theme2.radii[2],
7486
- border: `1px solid ${theme2.colors.border}`,
7487
- overflow: "hidden"
7488
- },
7489
- children: [
7490
- /* @__PURE__ */ jsxs(
7491
- "div",
7492
- {
7493
- onClick: onToggle,
7494
- style: {
7495
- padding: "16px",
7496
- cursor: "pointer",
7497
- display: "flex",
7498
- flexDirection: "column",
7499
- gap: "12px",
7500
- transition: "background 0.2s ease"
7501
- },
7502
- onMouseEnter: (e) => {
7503
- e.currentTarget.style.background = theme2.colors.backgroundSecondary;
7504
- },
7505
- onMouseLeave: (e) => {
7506
- e.currentTarget.style.background = "transparent";
7507
- },
7508
- children: [
7509
- /* @__PURE__ */ jsxs(
7510
- "div",
7511
- {
7512
- style: {
7513
- display: "flex",
7514
- alignItems: "center",
7515
- justifyContent: "space-between",
7516
- gap: "12px"
7517
- },
7518
- children: [
7519
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
7520
- isLoading ? /* @__PURE__ */ jsx(
7521
- LoaderCircle,
7522
- {
7523
- size: 16,
7524
- color: theme2.colors.primary,
7525
- style: { animation: "spin 1s linear infinite" }
7526
- }
7527
- ) : isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { size: 16, color: theme2.colors.textSecondary }) : /* @__PURE__ */ jsx(ChevronRight, { size: 16, color: theme2.colors.textSecondary }),
7528
- /* @__PURE__ */ jsx(
7529
- "h3",
7530
- {
7531
- style: {
7532
- margin: 0,
7533
- fontSize: theme2.fontSizes[3],
7534
- fontWeight: theme2.fontWeights.semibold,
7535
- color: theme2.colors.text
7536
- },
7537
- children: milestone.title
7538
- }
7539
- )
7540
- ] }),
7541
- /* @__PURE__ */ jsxs(
7542
- "span",
7543
- {
7544
- style: {
7545
- fontSize: theme2.fontSizes[1],
7546
- color: theme2.colors.textSecondary,
7547
- background: theme2.colors.backgroundSecondary,
7548
- padding: "4px 10px",
7549
- borderRadius: theme2.radii[1],
7550
- fontWeight: theme2.fontWeights.medium
7551
- },
7552
- children: [
7553
- totalTasks,
7554
- " task",
7555
- totalTasks !== 1 ? "s" : ""
7556
- ]
7557
- }
7558
- )
7559
- ]
7560
- }
7561
- ),
7562
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [
7563
- /* @__PURE__ */ jsx(
7564
- "div",
7565
- {
7566
- style: {
7567
- flex: 1,
7568
- height: "6px",
7569
- background: theme2.colors.backgroundSecondary,
7570
- borderRadius: theme2.radii[1],
7571
- overflow: "hidden"
7572
- },
7573
- children: /* @__PURE__ */ jsx(
7574
- "div",
7575
- {
7576
- style: {
7577
- height: "100%",
7578
- width: showProgress ? `${progress}%` : "0%",
7579
- background: progress === 100 ? theme2.colors.success : theme2.colors.primary,
7580
- transition: "width 0.3s ease"
7581
- }
7582
- }
7583
- )
7584
- }
7585
- ),
7586
- /* @__PURE__ */ jsx(
7587
- "span",
7588
- {
7589
- style: {
7590
- fontSize: theme2.fontSizes[1],
7591
- color: theme2.colors.textSecondary,
7592
- minWidth: "45px",
7593
- textAlign: "right"
7594
- },
7595
- children: showProgress ? `${progress}%` : "..."
7596
- }
7597
- )
7598
- ] }),
7599
- !isExpanded && milestone.description && /* @__PURE__ */ jsx(
7600
- "p",
7601
- {
7602
- style: {
7603
- margin: 0,
7604
- fontSize: theme2.fontSizes[1],
7605
- color: theme2.colors.textSecondary,
7606
- overflow: "hidden",
7607
- textOverflow: "ellipsis",
7608
- display: "-webkit-box",
7609
- WebkitLineClamp: 2,
7610
- WebkitBoxOrient: "vertical",
7611
- lineHeight: "1.4"
7612
- },
7613
- children: milestone.description
7614
- }
7615
- )
7616
- ]
7617
- }
7618
- ),
7619
- isExpanded && /* @__PURE__ */ jsxs(
7620
- "div",
7621
- {
7622
- style: {
7623
- borderTop: `1px solid ${theme2.colors.border}`,
7624
- padding: "16px",
7625
- display: "flex",
7626
- flexDirection: "column",
7627
- gap: "12px"
7628
- },
7629
- children: [
7630
- milestone.description && /* @__PURE__ */ jsx(
7631
- "p",
7632
- {
7633
- style: {
7634
- margin: 0,
7635
- fontSize: theme2.fontSizes[1],
7636
- color: theme2.colors.textSecondary,
7637
- lineHeight: "1.5"
7638
- },
7639
- children: milestone.description
7640
- }
7641
- ),
7642
- tasks.length > 0 && /* @__PURE__ */ jsxs(
7643
- "div",
7644
- {
7645
- style: {
7646
- display: "flex",
7647
- gap: "12px",
7648
- flexWrap: "wrap",
7649
- fontSize: theme2.fontSizes[1]
7650
- },
7651
- children: [
7652
- /* @__PURE__ */ jsxs("span", { style: { color: theme2.colors.success }, children: [
7653
- doneTasks,
7654
- " done"
7655
- ] }),
7656
- /* @__PURE__ */ jsxs("span", { style: { color: theme2.colors.textSecondary }, children: [
7657
- totalTasks - doneTasks,
7658
- " remaining"
7659
- ] })
7660
- ]
7661
- }
7662
- ),
7663
- isLoading ? /* @__PURE__ */ jsxs(
7664
- "div",
7665
- {
7666
- style: {
7667
- display: "flex",
7668
- alignItems: "center",
7669
- justifyContent: "center",
7670
- padding: "24px",
7671
- color: theme2.colors.textSecondary,
7672
- gap: "8px"
7673
- },
7674
- children: [
7675
- /* @__PURE__ */ jsx(
7676
- LoaderCircle,
7677
- {
7678
- size: 16,
7679
- style: { animation: "spin 1s linear infinite" }
7680
- }
7681
- ),
7682
- "Loading tasks..."
7683
- ]
7684
- }
7685
- ) : tasks.length > 0 ? /* @__PURE__ */ jsx(
7686
- "div",
7687
- {
7688
- style: {
7689
- display: "flex",
7690
- flexDirection: "column",
7691
- gap: "8px",
7692
- maxHeight: "300px",
7693
- overflowY: "auto",
7694
- paddingRight: "4px"
7695
- },
7696
- children: tasks.map((task) => {
7697
- var _a;
7698
- return /* @__PURE__ */ jsxs(
7699
- "div",
7700
- {
7701
- onClick: (e) => {
7702
- e.stopPropagation();
7703
- onTaskClick == null ? void 0 : onTaskClick(task);
7704
- },
7705
- style: {
7706
- background: theme2.colors.background,
7707
- borderRadius: theme2.radii[1],
7708
- padding: "10px 12px",
7709
- border: `1px solid ${theme2.colors.border}`,
7710
- borderLeft: `3px solid ${getPriorityColor(task.priority)}`,
7711
- cursor: onTaskClick ? "pointer" : "default",
7712
- transition: "all 0.2s ease",
7713
- display: "flex",
7714
- alignItems: "center",
7715
- justifyContent: "space-between",
7716
- gap: "12px"
7717
- },
7718
- onMouseEnter: (e) => {
7719
- if (onTaskClick) {
7720
- e.currentTarget.style.background = theme2.colors.backgroundSecondary;
7721
- }
7722
- },
7723
- onMouseLeave: (e) => {
7724
- e.currentTarget.style.background = theme2.colors.background;
7725
- },
7726
- children: [
7727
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", flex: 1, minWidth: 0 }, children: [
7728
- /* @__PURE__ */ jsxs(
7729
- "span",
7730
- {
7731
- style: {
7732
- fontFamily: theme2.fonts.monospace,
7733
- fontSize: theme2.fontSizes[0],
7734
- color: theme2.colors.textMuted,
7735
- flexShrink: 0
7736
- },
7737
- children: [
7738
- "#",
7739
- task.id
7740
- ]
7741
- }
7742
- ),
7743
- /* @__PURE__ */ jsx(
7744
- "span",
7745
- {
7746
- style: {
7747
- fontSize: theme2.fontSizes[1],
7748
- color: theme2.colors.text,
7749
- overflow: "hidden",
7750
- textOverflow: "ellipsis",
7751
- whiteSpace: "nowrap"
7752
- },
7753
- children: task.title
7754
- }
7755
- )
7756
- ] }),
7757
- /* @__PURE__ */ jsx(
7758
- "span",
7759
- {
7760
- style: {
7761
- fontSize: theme2.fontSizes[0],
7762
- color: ((_a = task.status) == null ? void 0 : _a.toLowerCase().includes("done")) ? theme2.colors.success : theme2.colors.textSecondary,
7763
- background: theme2.colors.backgroundSecondary,
7764
- padding: "2px 8px",
7765
- borderRadius: theme2.radii[1],
7766
- flexShrink: 0
7767
- },
7768
- children: task.status
7769
- }
7770
- )
7771
- ]
7772
- },
7773
- task.id
7774
- );
7775
- })
7776
- }
7777
- ) : totalTasks === 0 ? /* @__PURE__ */ jsx(
7778
- "div",
7779
- {
7780
- style: {
7781
- padding: "16px",
7782
- textAlign: "center",
7783
- color: theme2.colors.textMuted,
7784
- fontSize: theme2.fontSizes[1]
7785
- },
7786
- children: "No tasks in this milestone"
7787
- }
7788
- ) : null
7789
- ]
7790
- }
7791
- ),
7792
- /* @__PURE__ */ jsx("style", { children: `
7793
- @keyframes spin {
7794
- to { transform: rotate(360deg); }
7795
- }
7796
- ` })
7797
- ]
7798
- }
7799
- );
7800
- };
7801
7481
  const MilestoneModal = ({
7802
7482
  isOpen,
7803
7483
  onClose,
@@ -8106,7 +7786,7 @@ const KanbanPanel = ({
8106
7786
  }) => {
8107
7787
  var _a, _b;
8108
7788
  const { theme: theme2 } = useTheme();
8109
- const [_selectedTask, setSelectedTask] = useState(null);
7789
+ const [selectedTaskId, setSelectedTaskId] = useState(null);
8110
7790
  const [selectedTab, setSelectedTab] = useState("todo");
8111
7791
  const [isNarrowView, setIsNarrowView] = useState(false);
8112
7792
  const containerRef = useRef(null);
@@ -8117,6 +7797,8 @@ const KanbanPanel = ({
8117
7797
  const [isMilestoneModalOpen, setIsMilestoneModalOpen] = useState(false);
8118
7798
  const [editingMilestone, setEditingMilestone] = useState(void 0);
8119
7799
  const [isRefreshingMilestones, setIsRefreshingMilestones] = useState(false);
7800
+ const [selectedMilestoneId, setSelectedMilestoneId] = useState(null);
7801
+ const [milestoneStatusFilter, setMilestoneStatusFilter] = useState(null);
8120
7802
  const [searchQuery, setSearchQuery] = useState("");
8121
7803
  const sensors = useSensors(
8122
7804
  useSensor(PointerSensor, {
@@ -8142,6 +7824,16 @@ const KanbanPanel = ({
8142
7824
  observer.observe(container);
8143
7825
  return () => observer.disconnect();
8144
7826
  }, []);
7827
+ useEffect(() => {
7828
+ if (!events2) return;
7829
+ const unsubscribe = events2.on("task:selected", (event) => {
7830
+ const payload = event.payload;
7831
+ if (payload == null ? void 0 : payload.taskId) {
7832
+ setSelectedTaskId(payload.taskId);
7833
+ }
7834
+ });
7835
+ return unsubscribe;
7836
+ }, [events2]);
8145
7837
  const {
8146
7838
  statusColumns,
8147
7839
  tasksByStatus,
@@ -8163,7 +7855,6 @@ const KanbanPanel = ({
8163
7855
  milestones,
8164
7856
  isLoading: isMilestonesLoading,
8165
7857
  error: milestonesError,
8166
- toggleMilestone,
8167
7858
  refreshData: refreshMilestones,
8168
7859
  canWrite: canWriteMilestones,
8169
7860
  core: milestoneCore
@@ -8217,7 +7908,7 @@ const KanbanPanel = ({
8217
7908
  }
8218
7909
  }, [getTaskById, moveTaskOptimistic]);
8219
7910
  const handleTaskClick = (task) => {
8220
- setSelectedTask(task);
7911
+ setSelectedTaskId(task.id);
8221
7912
  if (events2) {
8222
7913
  events2.emit({
8223
7914
  type: "task:selected",
@@ -8338,7 +8029,7 @@ const KanbanPanel = ({
8338
8029
  }
8339
8030
  };
8340
8031
  const handleMilestoneTaskClick = (task) => {
8341
- setSelectedTask(task);
8032
+ setSelectedTaskId(task.id);
8342
8033
  if (events2) {
8343
8034
  events2.emit({
8344
8035
  type: "task:selected",
@@ -8569,6 +8260,33 @@ const KanbanPanel = ({
8569
8260
  }
8570
8261
  )
8571
8262
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8263
+ canWrite && /* @__PURE__ */ jsxs(
8264
+ "button",
8265
+ {
8266
+ onClick: handleOpenNewTask,
8267
+ disabled: !selectedMilestoneId,
8268
+ title: selectedMilestoneId ? "Add task to milestone" : "Select a milestone first",
8269
+ style: {
8270
+ display: "flex",
8271
+ alignItems: "center",
8272
+ gap: "6px",
8273
+ background: selectedMilestoneId ? theme2.colors.primary : theme2.colors.backgroundSecondary,
8274
+ color: selectedMilestoneId ? theme2.colors.textOnPrimary : theme2.colors.textMuted,
8275
+ border: selectedMilestoneId ? "none" : `1px solid ${theme2.colors.border}`,
8276
+ borderRadius: theme2.radii[2],
8277
+ padding: "6px 12px",
8278
+ fontSize: theme2.fontSizes[1],
8279
+ fontWeight: theme2.fontWeights.medium,
8280
+ cursor: selectedMilestoneId ? "pointer" : "not-allowed",
8281
+ opacity: selectedMilestoneId ? 1 : 0.6,
8282
+ transition: "all 0.2s ease"
8283
+ },
8284
+ children: [
8285
+ /* @__PURE__ */ jsx(Plus, { size: 14 }),
8286
+ "Add Task"
8287
+ ]
8288
+ }
8289
+ ),
8572
8290
  canWriteMilestones && /* @__PURE__ */ jsxs(
8573
8291
  "button",
8574
8292
  {
@@ -8762,7 +8480,8 @@ const KanbanPanel = ({
8762
8480
  status: STATUS_DISPLAY_LABELS[status],
8763
8481
  tasks: columnTasks,
8764
8482
  onTaskClick: handleTaskClick,
8765
- fullWidth: isNarrowView
8483
+ fullWidth: isNarrowView,
8484
+ selectedTaskId
8766
8485
  },
8767
8486
  status
8768
8487
  );
@@ -8790,14 +8509,14 @@ const KanbanPanel = ({
8790
8509
  ]
8791
8510
  }
8792
8511
  ) : (
8793
- /* Milestones View */
8512
+ /* Milestones View - Two Column Layout */
8794
8513
  /* @__PURE__ */ jsx(
8795
8514
  "div",
8796
8515
  {
8797
8516
  style: {
8798
8517
  flex: 1,
8799
8518
  display: "flex",
8800
- flexDirection: "column",
8519
+ gap: "16px",
8801
8520
  overflow: "hidden"
8802
8521
  },
8803
8522
  children: isMilestonesLoading ? /* @__PURE__ */ jsx(
@@ -8832,30 +8551,352 @@ const KanbanPanel = ({
8832
8551
  ] })
8833
8552
  ]
8834
8553
  }
8835
- ) : /* @__PURE__ */ jsx(
8836
- "div",
8837
- {
8838
- style: {
8839
- flex: 1,
8840
- overflowY: "auto",
8841
- overflowX: "hidden",
8842
- display: "flex",
8843
- flexDirection: "column",
8844
- gap: "12px",
8845
- paddingRight: "4px",
8846
- marginRight: "-4px"
8847
- },
8848
- children: milestones.map((milestoneState) => /* @__PURE__ */ jsx(
8849
- MilestoneCard,
8850
- {
8851
- milestoneState,
8852
- onToggle: () => toggleMilestone(milestoneState.milestone.id),
8853
- onTaskClick: handleMilestoneTaskClick
8554
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
8555
+ /* @__PURE__ */ jsx(
8556
+ "div",
8557
+ {
8558
+ style: {
8559
+ flex: 1,
8560
+ minWidth: 0,
8561
+ display: "flex",
8562
+ flexDirection: "column",
8563
+ overflow: "hidden"
8854
8564
  },
8855
- milestoneState.milestone.id
8856
- ))
8857
- }
8858
- )
8565
+ children: /* @__PURE__ */ jsx(
8566
+ "div",
8567
+ {
8568
+ style: {
8569
+ flex: 1,
8570
+ overflowY: "auto",
8571
+ display: "flex",
8572
+ flexDirection: "column",
8573
+ gap: "8px",
8574
+ paddingRight: "4px"
8575
+ },
8576
+ children: milestones.map((milestoneState) => {
8577
+ const isSelected = selectedMilestoneId === milestoneState.milestone.id;
8578
+ const totalTasks = milestoneState.milestone.tasks.length;
8579
+ const doneTasks = milestoneState.tasks.filter(
8580
+ (t) => {
8581
+ var _a2, _b2;
8582
+ return ((_a2 = t.status) == null ? void 0 : _a2.toLowerCase().includes("done")) || ((_b2 = t.status) == null ? void 0 : _b2.toLowerCase().includes("complete"));
8583
+ }
8584
+ ).length;
8585
+ const progress = totalTasks > 0 ? Math.round(doneTasks / totalTasks * 100) : 0;
8586
+ const showProgress = milestoneState.tasks.length > 0 || totalTasks === 0;
8587
+ return /* @__PURE__ */ jsxs(
8588
+ "div",
8589
+ {
8590
+ onClick: () => {
8591
+ setSelectedMilestoneId(milestoneState.milestone.id);
8592
+ setMilestoneStatusFilter(null);
8593
+ },
8594
+ style: {
8595
+ padding: "12px 16px",
8596
+ background: isSelected ? theme2.colors.primary + "15" : theme2.colors.surface,
8597
+ border: `1px solid ${isSelected ? theme2.colors.primary : theme2.colors.border}`,
8598
+ borderRadius: theme2.radii[2],
8599
+ cursor: "pointer",
8600
+ transition: "all 0.2s ease"
8601
+ },
8602
+ children: [
8603
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "12px" }, children: [
8604
+ /* @__PURE__ */ jsx(
8605
+ "h3",
8606
+ {
8607
+ style: {
8608
+ margin: 0,
8609
+ fontSize: theme2.fontSizes[2],
8610
+ fontWeight: theme2.fontWeights.semibold,
8611
+ color: theme2.colors.text,
8612
+ overflow: "hidden",
8613
+ textOverflow: "ellipsis",
8614
+ whiteSpace: "nowrap"
8615
+ },
8616
+ children: milestoneState.milestone.title
8617
+ }
8618
+ ),
8619
+ /* @__PURE__ */ jsxs(
8620
+ "span",
8621
+ {
8622
+ style: {
8623
+ fontSize: theme2.fontSizes[1],
8624
+ color: theme2.colors.textSecondary,
8625
+ background: theme2.colors.backgroundSecondary,
8626
+ padding: "2px 8px",
8627
+ borderRadius: theme2.radii[1],
8628
+ flexShrink: 0
8629
+ },
8630
+ children: [
8631
+ totalTasks,
8632
+ " task",
8633
+ totalTasks !== 1 ? "s" : "",
8634
+ showProgress && /* @__PURE__ */ jsxs(Fragment, { children: [
8635
+ " · ",
8636
+ /* @__PURE__ */ jsxs("span", { style: { color: progress === 100 ? theme2.colors.success : theme2.colors.text }, children: [
8637
+ progress,
8638
+ "%"
8639
+ ] })
8640
+ ] })
8641
+ ]
8642
+ }
8643
+ )
8644
+ ] }),
8645
+ isSelected && milestoneState.milestone.description && /* @__PURE__ */ jsx(
8646
+ "p",
8647
+ {
8648
+ style: {
8649
+ margin: "8px 0 0 0",
8650
+ fontSize: theme2.fontSizes[1],
8651
+ color: theme2.colors.textSecondary,
8652
+ lineHeight: "1.4"
8653
+ },
8654
+ children: milestoneState.milestone.description
8655
+ }
8656
+ )
8657
+ ]
8658
+ },
8659
+ milestoneState.milestone.id
8660
+ );
8661
+ })
8662
+ }
8663
+ )
8664
+ }
8665
+ ),
8666
+ /* @__PURE__ */ jsx(
8667
+ "div",
8668
+ {
8669
+ style: {
8670
+ flex: 1,
8671
+ minWidth: 0,
8672
+ display: "flex",
8673
+ flexDirection: "column",
8674
+ background: theme2.colors.surface,
8675
+ borderRadius: theme2.radii[2],
8676
+ border: `1px solid ${theme2.colors.border}`,
8677
+ overflow: "hidden"
8678
+ },
8679
+ children: (() => {
8680
+ const selectedMilestone = milestones.find((m) => m.milestone.id === selectedMilestoneId);
8681
+ if (!selectedMilestone) {
8682
+ return /* @__PURE__ */ jsxs(
8683
+ "div",
8684
+ {
8685
+ style: {
8686
+ flex: 1,
8687
+ display: "flex",
8688
+ flexDirection: "column",
8689
+ alignItems: "center",
8690
+ justifyContent: "center",
8691
+ gap: "8px",
8692
+ color: theme2.colors.textMuted,
8693
+ padding: "24px"
8694
+ },
8695
+ children: [
8696
+ /* @__PURE__ */ jsx(Milestone, { size: 32, color: theme2.colors.border }),
8697
+ /* @__PURE__ */ jsx("span", { style: { fontSize: theme2.fontSizes[1] }, children: "Select a milestone to view tasks" })
8698
+ ]
8699
+ }
8700
+ );
8701
+ }
8702
+ const tasks = selectedMilestone.tasks;
8703
+ const getPriorityColor = (priority) => {
8704
+ switch (priority) {
8705
+ case "high":
8706
+ return theme2.colors.error;
8707
+ case "medium":
8708
+ return theme2.colors.warning;
8709
+ case "low":
8710
+ return theme2.colors.info;
8711
+ default:
8712
+ return theme2.colors.border;
8713
+ }
8714
+ };
8715
+ const todoCount = tasks.filter((t) => t.status === "To Do").length;
8716
+ const inProgressCount = tasks.filter((t) => t.status === "In Progress").length;
8717
+ const doneCount = tasks.filter(
8718
+ (t) => {
8719
+ var _a2, _b2;
8720
+ return ((_a2 = t.status) == null ? void 0 : _a2.toLowerCase().includes("done")) || ((_b2 = t.status) == null ? void 0 : _b2.toLowerCase().includes("complete"));
8721
+ }
8722
+ ).length;
8723
+ const filteredTasks = milestoneStatusFilter ? tasks.filter((t) => {
8724
+ var _a2, _b2;
8725
+ if (milestoneStatusFilter === "Done") {
8726
+ return ((_a2 = t.status) == null ? void 0 : _a2.toLowerCase().includes("done")) || ((_b2 = t.status) == null ? void 0 : _b2.toLowerCase().includes("complete"));
8727
+ }
8728
+ return t.status === milestoneStatusFilter;
8729
+ }) : tasks;
8730
+ const getFilterButtonStyle = (status, count, color2) => {
8731
+ const isActive = milestoneStatusFilter === status;
8732
+ return {
8733
+ flex: 1,
8734
+ padding: "8px 12px",
8735
+ border: "none",
8736
+ borderBottom: isActive ? `2px solid ${color2}` : "2px solid transparent",
8737
+ background: isActive ? `${color2}15` : "transparent",
8738
+ color: isActive ? color2 : theme2.colors.textSecondary,
8739
+ fontSize: theme2.fontSizes[1],
8740
+ fontWeight: isActive ? theme2.fontWeights.medium : theme2.fontWeights.body,
8741
+ cursor: count > 0 ? "pointer" : "default",
8742
+ transition: "all 0.2s ease",
8743
+ textAlign: "center",
8744
+ opacity: count === 0 ? 0.5 : 1
8745
+ };
8746
+ };
8747
+ const handleFilterClick = (status, count) => {
8748
+ if (count === 0) return;
8749
+ setMilestoneStatusFilter(milestoneStatusFilter === status ? null : status);
8750
+ };
8751
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
8752
+ /* @__PURE__ */ jsxs(
8753
+ "div",
8754
+ {
8755
+ style: {
8756
+ borderBottom: `1px solid ${theme2.colors.border}`,
8757
+ background: theme2.colors.backgroundSecondary,
8758
+ display: "flex"
8759
+ },
8760
+ children: [
8761
+ /* @__PURE__ */ jsxs(
8762
+ "button",
8763
+ {
8764
+ onClick: () => handleFilterClick("To Do", todoCount),
8765
+ style: getFilterButtonStyle("To Do", todoCount, theme2.colors.textSecondary),
8766
+ children: [
8767
+ todoCount,
8768
+ " To Do"
8769
+ ]
8770
+ }
8771
+ ),
8772
+ /* @__PURE__ */ jsxs(
8773
+ "button",
8774
+ {
8775
+ onClick: () => handleFilterClick("In Progress", inProgressCount),
8776
+ style: getFilterButtonStyle("In Progress", inProgressCount, theme2.colors.warning),
8777
+ children: [
8778
+ inProgressCount,
8779
+ " In Progress"
8780
+ ]
8781
+ }
8782
+ ),
8783
+ /* @__PURE__ */ jsxs(
8784
+ "button",
8785
+ {
8786
+ onClick: () => handleFilterClick("Done", doneCount),
8787
+ style: getFilterButtonStyle("Done", doneCount, theme2.colors.success),
8788
+ children: [
8789
+ doneCount,
8790
+ " Done"
8791
+ ]
8792
+ }
8793
+ )
8794
+ ]
8795
+ }
8796
+ ),
8797
+ /* @__PURE__ */ jsx(
8798
+ "div",
8799
+ {
8800
+ style: {
8801
+ flex: 1,
8802
+ overflowY: "auto",
8803
+ padding: "12px",
8804
+ display: "flex",
8805
+ flexDirection: "column",
8806
+ gap: "8px"
8807
+ },
8808
+ children: filteredTasks.length === 0 ? /* @__PURE__ */ jsx(
8809
+ "div",
8810
+ {
8811
+ style: {
8812
+ flex: 1,
8813
+ display: "flex",
8814
+ alignItems: "center",
8815
+ justifyContent: "center",
8816
+ color: theme2.colors.textMuted,
8817
+ fontSize: theme2.fontSizes[1]
8818
+ },
8819
+ children: milestoneStatusFilter ? `No ${milestoneStatusFilter.toLowerCase()} tasks` : "No tasks in this milestone"
8820
+ }
8821
+ ) : filteredTasks.map((task) => {
8822
+ var _a2;
8823
+ return /* @__PURE__ */ jsxs(
8824
+ "div",
8825
+ {
8826
+ onClick: () => handleMilestoneTaskClick(task),
8827
+ style: {
8828
+ padding: "10px 12px",
8829
+ background: selectedTaskId === task.id ? `${theme2.colors.primary}10` : theme2.colors.background,
8830
+ border: `1px solid ${selectedTaskId === task.id ? theme2.colors.primary : theme2.colors.border}`,
8831
+ borderLeft: `3px solid ${getPriorityColor(task.priority)}`,
8832
+ borderRadius: theme2.radii[1],
8833
+ cursor: "pointer",
8834
+ transition: "all 0.2s ease",
8835
+ display: "flex",
8836
+ alignItems: "center",
8837
+ justifyContent: "space-between",
8838
+ gap: "12px",
8839
+ ...selectedTaskId === task.id && {
8840
+ boxShadow: `0 0 0 1px ${theme2.colors.primary}`
8841
+ }
8842
+ },
8843
+ children: [
8844
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", flex: 1, minWidth: 0 }, children: [
8845
+ /* @__PURE__ */ jsxs(
8846
+ "span",
8847
+ {
8848
+ style: {
8849
+ fontFamily: theme2.fonts.monospace,
8850
+ fontSize: theme2.fontSizes[0],
8851
+ color: theme2.colors.textMuted,
8852
+ flexShrink: 0
8853
+ },
8854
+ children: [
8855
+ "#",
8856
+ task.id
8857
+ ]
8858
+ }
8859
+ ),
8860
+ /* @__PURE__ */ jsx(
8861
+ "span",
8862
+ {
8863
+ style: {
8864
+ fontSize: theme2.fontSizes[1],
8865
+ color: theme2.colors.text,
8866
+ overflow: "hidden",
8867
+ textOverflow: "ellipsis",
8868
+ whiteSpace: "nowrap"
8869
+ },
8870
+ children: task.title
8871
+ }
8872
+ )
8873
+ ] }),
8874
+ /* @__PURE__ */ jsx(
8875
+ "span",
8876
+ {
8877
+ style: {
8878
+ fontSize: theme2.fontSizes[0],
8879
+ color: ((_a2 = task.status) == null ? void 0 : _a2.toLowerCase().includes("done")) ? theme2.colors.success : theme2.colors.textSecondary,
8880
+ background: theme2.colors.backgroundSecondary,
8881
+ padding: "2px 8px",
8882
+ borderRadius: theme2.radii[1],
8883
+ flexShrink: 0
8884
+ },
8885
+ children: task.status
8886
+ }
8887
+ )
8888
+ ]
8889
+ },
8890
+ task.id
8891
+ );
8892
+ })
8893
+ }
8894
+ )
8895
+ ] });
8896
+ })()
8897
+ }
8898
+ )
8899
+ ] })
8859
8900
  }
8860
8901
  )
8861
8902
  ),
@@ -8867,7 +8908,9 @@ const KanbanPanel = ({
8867
8908
  onSave: handleSaveTask,
8868
8909
  task: editingTask,
8869
8910
  defaultStatus: "To Do",
8870
- availableStatuses
8911
+ defaultMilestone: viewMode === "milestones" ? selectedMilestoneId || "" : "",
8912
+ availableStatuses,
8913
+ availableMilestones: milestones.map((m) => ({ id: m.milestone.id, title: m.milestone.title }))
8871
8914
  }
8872
8915
  ),
8873
8916
  /* @__PURE__ */ jsx(