@industry-theme/backlogmd-kanban-panel 1.0.12 → 1.0.15
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/adapters/PanelFileSystemAdapter.d.ts +22 -3
- package/dist/adapters/PanelFileSystemAdapter.d.ts.map +1 -1
- package/dist/panels/KanbanPanel.d.ts.map +1 -1
- package/dist/panels/MilestonePanel.d.ts.map +1 -1
- package/dist/panels/kanban/components/TaskModal.d.ts +17 -0
- package/dist/panels/kanban/components/TaskModal.d.ts.map +1 -0
- package/dist/panels/kanban/hooks/useKanbanData.d.ts +5 -1
- package/dist/panels/kanban/hooks/useKanbanData.d.ts.map +1 -1
- package/dist/panels/milestone/components/MilestoneModal.d.ts +14 -0
- package/dist/panels/milestone/components/MilestoneModal.d.ts.map +1 -0
- package/dist/panels/milestone/hooks/useMilestoneData.d.ts +5 -1
- package/dist/panels/milestone/hooks/useMilestoneData.d.ts.map +1 -1
- package/dist/panels.bundle.js +1487 -355
- package/dist/panels.bundle.js.map +1 -1
- package/package.json +2 -2
package/dist/panels.bundle.js
CHANGED
|
@@ -3740,89 +3740,89 @@ 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$
|
|
3743
|
+
const __iconNode$o = [
|
|
3744
3744
|
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
3745
3745
|
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
3746
3746
|
];
|
|
3747
|
-
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$
|
|
3747
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$o);
|
|
3748
3748
|
/**
|
|
3749
3749
|
* @license lucide-react v0.552.0 - ISC
|
|
3750
3750
|
*
|
|
3751
3751
|
* This source code is licensed under the ISC license.
|
|
3752
3752
|
* See the LICENSE file in the root directory of this source tree.
|
|
3753
3753
|
*/
|
|
3754
|
-
const __iconNode$
|
|
3754
|
+
const __iconNode$n = [
|
|
3755
3755
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
3756
3756
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
3757
3757
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
3758
3758
|
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
3759
3759
|
];
|
|
3760
|
-
const Calendar = createLucideIcon("calendar", __iconNode$
|
|
3760
|
+
const Calendar = createLucideIcon("calendar", __iconNode$n);
|
|
3761
3761
|
/**
|
|
3762
3762
|
* @license lucide-react v0.552.0 - ISC
|
|
3763
3763
|
*
|
|
3764
3764
|
* This source code is licensed under the ISC license.
|
|
3765
3765
|
* See the LICENSE file in the root directory of this source tree.
|
|
3766
3766
|
*/
|
|
3767
|
-
const __iconNode$
|
|
3768
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
3767
|
+
const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
3768
|
+
const Check = createLucideIcon("check", __iconNode$m);
|
|
3769
3769
|
/**
|
|
3770
3770
|
* @license lucide-react v0.552.0 - ISC
|
|
3771
3771
|
*
|
|
3772
3772
|
* This source code is licensed under the ISC license.
|
|
3773
3773
|
* See the LICENSE file in the root directory of this source tree.
|
|
3774
3774
|
*/
|
|
3775
|
-
const __iconNode$
|
|
3776
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
3775
|
+
const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
3776
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
|
|
3777
3777
|
/**
|
|
3778
3778
|
* @license lucide-react v0.552.0 - ISC
|
|
3779
3779
|
*
|
|
3780
3780
|
* This source code is licensed under the ISC license.
|
|
3781
3781
|
* See the LICENSE file in the root directory of this source tree.
|
|
3782
3782
|
*/
|
|
3783
|
-
const __iconNode$
|
|
3784
|
-
const ChevronRight = createLucideIcon("chevron-right", __iconNode$
|
|
3783
|
+
const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
|
|
3784
|
+
const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
|
|
3785
3785
|
/**
|
|
3786
3786
|
* @license lucide-react v0.552.0 - ISC
|
|
3787
3787
|
*
|
|
3788
3788
|
* This source code is licensed under the ISC license.
|
|
3789
3789
|
* See the LICENSE file in the root directory of this source tree.
|
|
3790
3790
|
*/
|
|
3791
|
-
const __iconNode$
|
|
3791
|
+
const __iconNode$j = [
|
|
3792
3792
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3793
3793
|
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
3794
3794
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
3795
3795
|
];
|
|
3796
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$
|
|
3796
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$j);
|
|
3797
3797
|
/**
|
|
3798
3798
|
* @license lucide-react v0.552.0 - ISC
|
|
3799
3799
|
*
|
|
3800
3800
|
* This source code is licensed under the ISC license.
|
|
3801
3801
|
* See the LICENSE file in the root directory of this source tree.
|
|
3802
3802
|
*/
|
|
3803
|
-
const __iconNode$
|
|
3803
|
+
const __iconNode$i = [
|
|
3804
3804
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3805
3805
|
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
3806
3806
|
];
|
|
3807
|
-
const CircleCheck = createLucideIcon("circle-check", __iconNode$
|
|
3807
|
+
const CircleCheck = createLucideIcon("circle-check", __iconNode$i);
|
|
3808
3808
|
/**
|
|
3809
3809
|
* @license lucide-react v0.552.0 - ISC
|
|
3810
3810
|
*
|
|
3811
3811
|
* This source code is licensed under the ISC license.
|
|
3812
3812
|
* See the LICENSE file in the root directory of this source tree.
|
|
3813
3813
|
*/
|
|
3814
|
-
const __iconNode$
|
|
3814
|
+
const __iconNode$h = [
|
|
3815
3815
|
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
3816
3816
|
["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
|
|
3817
3817
|
];
|
|
3818
|
-
const Copy = createLucideIcon("copy", __iconNode$
|
|
3818
|
+
const Copy = createLucideIcon("copy", __iconNode$h);
|
|
3819
3819
|
/**
|
|
3820
3820
|
* @license lucide-react v0.552.0 - ISC
|
|
3821
3821
|
*
|
|
3822
3822
|
* This source code is licensed under the ISC license.
|
|
3823
3823
|
* See the LICENSE file in the root directory of this source tree.
|
|
3824
3824
|
*/
|
|
3825
|
-
const __iconNode$
|
|
3825
|
+
const __iconNode$g = [
|
|
3826
3826
|
["path", { d: "m15 15 6 6", key: "1s409w" }],
|
|
3827
3827
|
["path", { d: "m15 9 6-6", key: "ko1vev" }],
|
|
3828
3828
|
["path", { d: "M21 16v5h-5", key: "1ck2sf" }],
|
|
@@ -3832,26 +3832,26 @@ const __iconNode$e = [
|
|
|
3832
3832
|
["path", { d: "M3 8V3h5", key: "1ln10m" }],
|
|
3833
3833
|
["path", { d: "M9 9 3 3", key: "v551iv" }]
|
|
3834
3834
|
];
|
|
3835
|
-
const Expand = createLucideIcon("expand", __iconNode$
|
|
3835
|
+
const Expand = createLucideIcon("expand", __iconNode$g);
|
|
3836
3836
|
/**
|
|
3837
3837
|
* @license lucide-react v0.552.0 - ISC
|
|
3838
3838
|
*
|
|
3839
3839
|
* This source code is licensed under the ISC license.
|
|
3840
3840
|
* See the LICENSE file in the root directory of this source tree.
|
|
3841
3841
|
*/
|
|
3842
|
-
const __iconNode$
|
|
3842
|
+
const __iconNode$f = [
|
|
3843
3843
|
["path", { d: "M15 3h6v6", key: "1q9fwt" }],
|
|
3844
3844
|
["path", { d: "M10 14 21 3", key: "gplh6r" }],
|
|
3845
3845
|
["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
|
|
3846
3846
|
];
|
|
3847
|
-
const ExternalLink = createLucideIcon("external-link", __iconNode$
|
|
3847
|
+
const ExternalLink = createLucideIcon("external-link", __iconNode$f);
|
|
3848
3848
|
/**
|
|
3849
3849
|
* @license lucide-react v0.552.0 - ISC
|
|
3850
3850
|
*
|
|
3851
3851
|
* This source code is licensed under the ISC license.
|
|
3852
3852
|
* See the LICENSE file in the root directory of this source tree.
|
|
3853
3853
|
*/
|
|
3854
|
-
const __iconNode$
|
|
3854
|
+
const __iconNode$e = [
|
|
3855
3855
|
[
|
|
3856
3856
|
"path",
|
|
3857
3857
|
{
|
|
@@ -3864,14 +3864,14 @@ const __iconNode$c = [
|
|
|
3864
3864
|
["path", { d: "M16 13H8", key: "t4e002" }],
|
|
3865
3865
|
["path", { d: "M16 17H8", key: "z1uh3a" }]
|
|
3866
3866
|
];
|
|
3867
|
-
const FileText = createLucideIcon("file-text", __iconNode$
|
|
3867
|
+
const FileText = createLucideIcon("file-text", __iconNode$e);
|
|
3868
3868
|
/**
|
|
3869
3869
|
* @license lucide-react v0.552.0 - ISC
|
|
3870
3870
|
*
|
|
3871
3871
|
* This source code is licensed under the ISC license.
|
|
3872
3872
|
* See the LICENSE file in the root directory of this source tree.
|
|
3873
3873
|
*/
|
|
3874
|
-
const __iconNode$
|
|
3874
|
+
const __iconNode$d = [
|
|
3875
3875
|
[
|
|
3876
3876
|
"path",
|
|
3877
3877
|
{
|
|
@@ -3880,14 +3880,14 @@ const __iconNode$b = [
|
|
|
3880
3880
|
}
|
|
3881
3881
|
]
|
|
3882
3882
|
];
|
|
3883
|
-
const Flag = createLucideIcon("flag", __iconNode$
|
|
3883
|
+
const Flag = createLucideIcon("flag", __iconNode$d);
|
|
3884
3884
|
/**
|
|
3885
3885
|
* @license lucide-react v0.552.0 - ISC
|
|
3886
3886
|
*
|
|
3887
3887
|
* This source code is licensed under the ISC license.
|
|
3888
3888
|
* See the LICENSE file in the root directory of this source tree.
|
|
3889
3889
|
*/
|
|
3890
|
-
const __iconNode$
|
|
3890
|
+
const __iconNode$c = [
|
|
3891
3891
|
["path", { d: "M12 10v6", key: "1bos4e" }],
|
|
3892
3892
|
["path", { d: "M9 13h6", key: "1uhe8q" }],
|
|
3893
3893
|
[
|
|
@@ -3898,70 +3898,70 @@ const __iconNode$a = [
|
|
|
3898
3898
|
}
|
|
3899
3899
|
]
|
|
3900
3900
|
];
|
|
3901
|
-
const FolderPlus = createLucideIcon("folder-plus", __iconNode$
|
|
3901
|
+
const FolderPlus = createLucideIcon("folder-plus", __iconNode$c);
|
|
3902
3902
|
/**
|
|
3903
3903
|
* @license lucide-react v0.552.0 - ISC
|
|
3904
3904
|
*
|
|
3905
3905
|
* This source code is licensed under the ISC license.
|
|
3906
3906
|
* See the LICENSE file in the root directory of this source tree.
|
|
3907
3907
|
*/
|
|
3908
|
-
const __iconNode$
|
|
3908
|
+
const __iconNode$b = [
|
|
3909
3909
|
["line", { x1: "6", x2: "6", y1: "3", y2: "15", key: "17qcm7" }],
|
|
3910
3910
|
["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
|
|
3911
3911
|
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
3912
3912
|
["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
|
|
3913
3913
|
];
|
|
3914
|
-
const GitBranch = createLucideIcon("git-branch", __iconNode$
|
|
3914
|
+
const GitBranch = createLucideIcon("git-branch", __iconNode$b);
|
|
3915
3915
|
/**
|
|
3916
3916
|
* @license lucide-react v0.552.0 - ISC
|
|
3917
3917
|
*
|
|
3918
3918
|
* This source code is licensed under the ISC license.
|
|
3919
3919
|
* See the LICENSE file in the root directory of this source tree.
|
|
3920
3920
|
*/
|
|
3921
|
-
const __iconNode$
|
|
3921
|
+
const __iconNode$a = [
|
|
3922
3922
|
["path", { d: "M5 3v14", key: "9nsxs2" }],
|
|
3923
3923
|
["path", { d: "M12 3v8", key: "1h2ygw" }],
|
|
3924
3924
|
["path", { d: "M19 3v18", key: "1sk56x" }]
|
|
3925
3925
|
];
|
|
3926
|
-
const Kanban = createLucideIcon("kanban", __iconNode$
|
|
3926
|
+
const Kanban = createLucideIcon("kanban", __iconNode$a);
|
|
3927
3927
|
/**
|
|
3928
3928
|
* @license lucide-react v0.552.0 - ISC
|
|
3929
3929
|
*
|
|
3930
3930
|
* This source code is licensed under the ISC license.
|
|
3931
3931
|
* See the LICENSE file in the root directory of this source tree.
|
|
3932
3932
|
*/
|
|
3933
|
-
const __iconNode$
|
|
3934
|
-
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$
|
|
3933
|
+
const __iconNode$9 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
3934
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$9);
|
|
3935
3935
|
/**
|
|
3936
3936
|
* @license lucide-react v0.552.0 - ISC
|
|
3937
3937
|
*
|
|
3938
3938
|
* This source code is licensed under the ISC license.
|
|
3939
3939
|
* See the LICENSE file in the root directory of this source tree.
|
|
3940
3940
|
*/
|
|
3941
|
-
const __iconNode$
|
|
3941
|
+
const __iconNode$8 = [
|
|
3942
3942
|
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
3943
3943
|
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
3944
3944
|
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
3945
3945
|
];
|
|
3946
|
-
const Monitor = createLucideIcon("monitor", __iconNode$
|
|
3946
|
+
const Monitor = createLucideIcon("monitor", __iconNode$8);
|
|
3947
3947
|
/**
|
|
3948
3948
|
* @license lucide-react v0.552.0 - ISC
|
|
3949
3949
|
*
|
|
3950
3950
|
* This source code is licensed under the ISC license.
|
|
3951
3951
|
* See the LICENSE file in the root directory of this source tree.
|
|
3952
3952
|
*/
|
|
3953
|
-
const __iconNode$
|
|
3953
|
+
const __iconNode$7 = [
|
|
3954
3954
|
["path", { d: "M18 8L22 12L18 16", key: "1r0oui" }],
|
|
3955
3955
|
["path", { d: "M2 12H22", key: "1m8cig" }]
|
|
3956
3956
|
];
|
|
3957
|
-
const MoveRight = createLucideIcon("move-right", __iconNode$
|
|
3957
|
+
const MoveRight = createLucideIcon("move-right", __iconNode$7);
|
|
3958
3958
|
/**
|
|
3959
3959
|
* @license lucide-react v0.552.0 - ISC
|
|
3960
3960
|
*
|
|
3961
3961
|
* This source code is licensed under the ISC license.
|
|
3962
3962
|
* See the LICENSE file in the root directory of this source tree.
|
|
3963
3963
|
*/
|
|
3964
|
-
const __iconNode$
|
|
3964
|
+
const __iconNode$6 = [
|
|
3965
3965
|
[
|
|
3966
3966
|
"path",
|
|
3967
3967
|
{
|
|
@@ -3970,27 +3970,38 @@ const __iconNode$4 = [
|
|
|
3970
3970
|
}
|
|
3971
3971
|
]
|
|
3972
3972
|
];
|
|
3973
|
-
const Play = createLucideIcon("play", __iconNode$
|
|
3973
|
+
const Play = createLucideIcon("play", __iconNode$6);
|
|
3974
3974
|
/**
|
|
3975
3975
|
* @license lucide-react v0.552.0 - ISC
|
|
3976
3976
|
*
|
|
3977
3977
|
* This source code is licensed under the ISC license.
|
|
3978
3978
|
* See the LICENSE file in the root directory of this source tree.
|
|
3979
3979
|
*/
|
|
3980
|
-
const __iconNode$
|
|
3980
|
+
const __iconNode$5 = [
|
|
3981
|
+
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
3982
|
+
["path", { d: "M12 5v14", key: "s699le" }]
|
|
3983
|
+
];
|
|
3984
|
+
const Plus = createLucideIcon("plus", __iconNode$5);
|
|
3985
|
+
/**
|
|
3986
|
+
* @license lucide-react v0.552.0 - ISC
|
|
3987
|
+
*
|
|
3988
|
+
* This source code is licensed under the ISC license.
|
|
3989
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3990
|
+
*/
|
|
3991
|
+
const __iconNode$4 = [
|
|
3981
3992
|
["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
|
|
3982
3993
|
["path", { d: "M21 3v5h-5", key: "1q7to0" }],
|
|
3983
3994
|
["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
|
|
3984
3995
|
["path", { d: "M8 16H3v5", key: "1cv678" }]
|
|
3985
3996
|
];
|
|
3986
|
-
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$
|
|
3997
|
+
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$4);
|
|
3987
3998
|
/**
|
|
3988
3999
|
* @license lucide-react v0.552.0 - ISC
|
|
3989
4000
|
*
|
|
3990
4001
|
* This source code is licensed under the ISC license.
|
|
3991
4002
|
* See the LICENSE file in the root directory of this source tree.
|
|
3992
4003
|
*/
|
|
3993
|
-
const __iconNode$
|
|
4004
|
+
const __iconNode$3 = [
|
|
3994
4005
|
[
|
|
3995
4006
|
"path",
|
|
3996
4007
|
{
|
|
@@ -4000,30 +4011,41 @@ const __iconNode$2 = [
|
|
|
4000
4011
|
],
|
|
4001
4012
|
["circle", { cx: "7.5", cy: "7.5", r: ".5", fill: "currentColor", key: "kqv944" }]
|
|
4002
4013
|
];
|
|
4003
|
-
const Tag = createLucideIcon("tag", __iconNode$
|
|
4014
|
+
const Tag = createLucideIcon("tag", __iconNode$3);
|
|
4004
4015
|
/**
|
|
4005
4016
|
* @license lucide-react v0.552.0 - ISC
|
|
4006
4017
|
*
|
|
4007
4018
|
* This source code is licensed under the ISC license.
|
|
4008
4019
|
* See the LICENSE file in the root directory of this source tree.
|
|
4009
4020
|
*/
|
|
4010
|
-
const __iconNode$
|
|
4021
|
+
const __iconNode$2 = [
|
|
4011
4022
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
4012
4023
|
["circle", { cx: "12", cy: "12", r: "6", key: "1vlfrh" }],
|
|
4013
4024
|
["circle", { cx: "12", cy: "12", r: "2", key: "1c9p78" }]
|
|
4014
4025
|
];
|
|
4015
|
-
const Target = createLucideIcon("target", __iconNode$
|
|
4026
|
+
const Target = createLucideIcon("target", __iconNode$2);
|
|
4016
4027
|
/**
|
|
4017
4028
|
* @license lucide-react v0.552.0 - ISC
|
|
4018
4029
|
*
|
|
4019
4030
|
* This source code is licensed under the ISC license.
|
|
4020
4031
|
* See the LICENSE file in the root directory of this source tree.
|
|
4021
4032
|
*/
|
|
4022
|
-
const __iconNode = [
|
|
4033
|
+
const __iconNode$1 = [
|
|
4023
4034
|
["path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2", key: "975kel" }],
|
|
4024
4035
|
["circle", { cx: "12", cy: "7", r: "4", key: "17ys0d" }]
|
|
4025
4036
|
];
|
|
4026
|
-
const User = createLucideIcon("user", __iconNode);
|
|
4037
|
+
const User = createLucideIcon("user", __iconNode$1);
|
|
4038
|
+
/**
|
|
4039
|
+
* @license lucide-react v0.552.0 - ISC
|
|
4040
|
+
*
|
|
4041
|
+
* This source code is licensed under the ISC license.
|
|
4042
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
4043
|
+
*/
|
|
4044
|
+
const __iconNode = [
|
|
4045
|
+
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
4046
|
+
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
4047
|
+
];
|
|
4048
|
+
const X = createLucideIcon("x", __iconNode);
|
|
4027
4049
|
var terminalTheme$1 = {
|
|
4028
4050
|
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
|
|
4029
4051
|
fonts: {
|
|
@@ -4397,9 +4419,9 @@ function parseArrayValue(value) {
|
|
|
4397
4419
|
function parseAcceptanceCriteria(content2) {
|
|
4398
4420
|
const criteria = [];
|
|
4399
4421
|
const checkboxPattern = /^-\s*\[([ xX])\]\s*(.+)$/gm;
|
|
4400
|
-
|
|
4422
|
+
const matches = content2.matchAll(checkboxPattern);
|
|
4401
4423
|
let index2 = 1;
|
|
4402
|
-
|
|
4424
|
+
for (const match of matches) {
|
|
4403
4425
|
criteria.push({
|
|
4404
4426
|
index: index2++,
|
|
4405
4427
|
checked: match[1].toLowerCase() === "x",
|
|
@@ -4413,9 +4435,9 @@ function extractDescription(content2, title) {
|
|
|
4413
4435
|
if (title) {
|
|
4414
4436
|
body = body.replace(new RegExp(`^#\\s+${escapeRegex(title)}\\s*$`, "m"), "");
|
|
4415
4437
|
}
|
|
4416
|
-
body = body.replace(/^##\s+Acceptance Criteria[\s\S]*?(
|
|
4417
|
-
body = body.replace(/^##\s+Implementation Plan[\s\S]*?(
|
|
4418
|
-
body = body.replace(/^##\s+Implementation Notes[\s\S]*?(
|
|
4438
|
+
body = body.replace(/^##\s+Acceptance Criteria[\s\S]*?(?=^##|$)/m, "");
|
|
4439
|
+
body = body.replace(/^##\s+Implementation Plan[\s\S]*?(?=^##|$)/m, "");
|
|
4440
|
+
body = body.replace(/^##\s+Implementation Notes[\s\S]*?(?=^##|$)/m, "");
|
|
4419
4441
|
return body.trim();
|
|
4420
4442
|
}
|
|
4421
4443
|
function extractIdFromPath(filePath) {
|
|
@@ -4524,155 +4546,123 @@ function extractMilestoneIdFromFilename(filename) {
|
|
|
4524
4546
|
const match = filename.match(/^(m-\d+)/);
|
|
4525
4547
|
return match ? match[1] : null;
|
|
4526
4548
|
}
|
|
4527
|
-
const
|
|
4528
|
-
function
|
|
4529
|
-
|
|
4530
|
-
const lines = content2.split("\n");
|
|
4531
|
-
for (const line of lines) {
|
|
4532
|
-
const trimmed = line.trim();
|
|
4533
|
-
if (!trimmed || trimmed.startsWith("#"))
|
|
4534
|
-
continue;
|
|
4535
|
-
const colonIndex = trimmed.indexOf(":");
|
|
4536
|
-
if (colonIndex === -1)
|
|
4537
|
-
continue;
|
|
4538
|
-
const key2 = trimmed.substring(0, colonIndex).trim();
|
|
4539
|
-
const value = trimmed.substring(colonIndex + 1).trim();
|
|
4540
|
-
switch (key2) {
|
|
4541
|
-
case "project_name":
|
|
4542
|
-
config.projectName = value.replace(/['"]/g, "");
|
|
4543
|
-
break;
|
|
4544
|
-
case "default_assignee":
|
|
4545
|
-
config.defaultAssignee = value.replace(/['"]/g, "");
|
|
4546
|
-
break;
|
|
4547
|
-
case "default_reporter":
|
|
4548
|
-
config.defaultReporter = value.replace(/['"]/g, "");
|
|
4549
|
-
break;
|
|
4550
|
-
case "default_status":
|
|
4551
|
-
config.defaultStatus = value.replace(/['"]/g, "");
|
|
4552
|
-
break;
|
|
4553
|
-
case "statuses":
|
|
4554
|
-
case "labels":
|
|
4555
|
-
case "milestones":
|
|
4556
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
4557
|
-
const arrayContent = value.slice(1, -1);
|
|
4558
|
-
config[key2] = arrayContent.split(",").map((item) => item.trim().replace(/['"]/g, "")).filter(Boolean);
|
|
4559
|
-
}
|
|
4560
|
-
break;
|
|
4561
|
-
case "date_format":
|
|
4562
|
-
config.dateFormat = value.replace(/['"]/g, "");
|
|
4563
|
-
break;
|
|
4564
|
-
case "max_column_width":
|
|
4565
|
-
config.maxColumnWidth = parseInt(value, 10);
|
|
4566
|
-
break;
|
|
4567
|
-
case "task_resolution_strategy":
|
|
4568
|
-
config.taskResolutionStrategy = value.replace(/['"]/g, "");
|
|
4569
|
-
break;
|
|
4570
|
-
case "default_editor":
|
|
4571
|
-
config.defaultEditor = value.replace(/["']/g, "");
|
|
4572
|
-
break;
|
|
4573
|
-
case "auto_open_browser":
|
|
4574
|
-
config.autoOpenBrowser = value.toLowerCase() === "true";
|
|
4575
|
-
break;
|
|
4576
|
-
case "default_port":
|
|
4577
|
-
config.defaultPort = parseInt(value, 10);
|
|
4578
|
-
break;
|
|
4579
|
-
case "remote_operations":
|
|
4580
|
-
config.remoteOperations = value.toLowerCase() === "true";
|
|
4581
|
-
break;
|
|
4582
|
-
case "auto_commit":
|
|
4583
|
-
config.autoCommit = value.toLowerCase() === "true";
|
|
4584
|
-
break;
|
|
4585
|
-
case "zero_padded_ids":
|
|
4586
|
-
config.zeroPaddedIds = parseInt(value, 10);
|
|
4587
|
-
break;
|
|
4588
|
-
case "timezone_preference":
|
|
4589
|
-
config.timezonePreference = value.replace(/['"]/g, "");
|
|
4590
|
-
break;
|
|
4591
|
-
case "include_date_time_in_dates":
|
|
4592
|
-
config.includeDateTimeInDates = value.toLowerCase() === "true";
|
|
4593
|
-
break;
|
|
4594
|
-
case "bypass_git_hooks":
|
|
4595
|
-
config.bypassGitHooks = value.toLowerCase() === "true";
|
|
4596
|
-
break;
|
|
4597
|
-
case "check_active_branches":
|
|
4598
|
-
config.checkActiveBranches = value.toLowerCase() === "true";
|
|
4599
|
-
break;
|
|
4600
|
-
case "active_branch_days":
|
|
4601
|
-
config.activeBranchDays = parseInt(value, 10);
|
|
4602
|
-
break;
|
|
4603
|
-
}
|
|
4604
|
-
}
|
|
4605
|
-
return {
|
|
4606
|
-
projectName: config.projectName || "Backlog",
|
|
4607
|
-
statuses: config.statuses || [...DEFAULT_STATUSES],
|
|
4608
|
-
labels: config.labels || [],
|
|
4609
|
-
milestones: config.milestones || [],
|
|
4610
|
-
defaultStatus: config.defaultStatus || DEFAULT_STATUSES[0],
|
|
4611
|
-
dateFormat: config.dateFormat || "YYYY-MM-DD",
|
|
4612
|
-
defaultAssignee: config.defaultAssignee,
|
|
4613
|
-
defaultReporter: config.defaultReporter,
|
|
4614
|
-
maxColumnWidth: config.maxColumnWidth,
|
|
4615
|
-
taskResolutionStrategy: config.taskResolutionStrategy,
|
|
4616
|
-
defaultEditor: config.defaultEditor,
|
|
4617
|
-
autoOpenBrowser: config.autoOpenBrowser,
|
|
4618
|
-
defaultPort: config.defaultPort,
|
|
4619
|
-
remoteOperations: config.remoteOperations,
|
|
4620
|
-
autoCommit: config.autoCommit,
|
|
4621
|
-
zeroPaddedIds: config.zeroPaddedIds,
|
|
4622
|
-
timezonePreference: config.timezonePreference,
|
|
4623
|
-
includeDateTimeInDates: config.includeDateTimeInDates,
|
|
4624
|
-
bypassGitHooks: config.bypassGitHooks,
|
|
4625
|
-
checkActiveBranches: config.checkActiveBranches,
|
|
4626
|
-
activeBranchDays: config.activeBranchDays
|
|
4627
|
-
};
|
|
4549
|
+
const NO_MILESTONE_KEY = "__none";
|
|
4550
|
+
function normalizeMilestoneName(name2) {
|
|
4551
|
+
return name2.trim();
|
|
4628
4552
|
}
|
|
4629
|
-
function
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
lines.push(`date_format: "${config.dateFormat}"`);
|
|
4640
|
-
}
|
|
4641
|
-
if (config.defaultAssignee) {
|
|
4642
|
-
lines.push(`default_assignee: "${config.defaultAssignee}"`);
|
|
4643
|
-
}
|
|
4644
|
-
if (config.defaultReporter) {
|
|
4645
|
-
lines.push(`default_reporter: "${config.defaultReporter}"`);
|
|
4646
|
-
}
|
|
4647
|
-
if (config.defaultEditor) {
|
|
4648
|
-
lines.push(`default_editor: "${config.defaultEditor}"`);
|
|
4649
|
-
}
|
|
4650
|
-
if (typeof config.autoCommit === "boolean") {
|
|
4651
|
-
lines.push(`auto_commit: ${config.autoCommit}`);
|
|
4652
|
-
}
|
|
4653
|
-
if (typeof config.zeroPaddedIds === "number") {
|
|
4654
|
-
lines.push(`zero_padded_ids: ${config.zeroPaddedIds}`);
|
|
4553
|
+
function milestoneKey(name2) {
|
|
4554
|
+
return normalizeMilestoneName(name2 ?? "").toLowerCase();
|
|
4555
|
+
}
|
|
4556
|
+
function isDoneStatus(status) {
|
|
4557
|
+
const normalized = (status ?? "").toLowerCase();
|
|
4558
|
+
return normalized.includes("done") || normalized.includes("complete");
|
|
4559
|
+
}
|
|
4560
|
+
function getMilestoneLabel(milestoneId, milestoneEntities) {
|
|
4561
|
+
if (!milestoneId) {
|
|
4562
|
+
return "Tasks without milestone";
|
|
4655
4563
|
}
|
|
4656
|
-
|
|
4657
|
-
|
|
4564
|
+
const entity = milestoneEntities.find((m) => milestoneKey(m.id) === milestoneKey(milestoneId));
|
|
4565
|
+
return (entity == null ? void 0 : entity.title) || milestoneId;
|
|
4566
|
+
}
|
|
4567
|
+
function collectMilestoneIds(tasks, milestoneEntities) {
|
|
4568
|
+
const merged = [];
|
|
4569
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4570
|
+
const addMilestone = (value) => {
|
|
4571
|
+
const normalized = normalizeMilestoneName(value);
|
|
4572
|
+
if (!normalized)
|
|
4573
|
+
return;
|
|
4574
|
+
const key2 = milestoneKey(normalized);
|
|
4575
|
+
if (seen.has(key2))
|
|
4576
|
+
return;
|
|
4577
|
+
seen.add(key2);
|
|
4578
|
+
merged.push(normalized);
|
|
4579
|
+
};
|
|
4580
|
+
for (const entity of milestoneEntities) {
|
|
4581
|
+
addMilestone(entity.id);
|
|
4658
4582
|
}
|
|
4659
|
-
|
|
4660
|
-
|
|
4583
|
+
for (const task of tasks) {
|
|
4584
|
+
addMilestone(task.milestone ?? "");
|
|
4661
4585
|
}
|
|
4662
|
-
|
|
4663
|
-
|
|
4586
|
+
return merged;
|
|
4587
|
+
}
|
|
4588
|
+
function collectMilestones(tasks, configMilestones) {
|
|
4589
|
+
const merged = [];
|
|
4590
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4591
|
+
const addMilestone = (value) => {
|
|
4592
|
+
const normalized = normalizeMilestoneName(value);
|
|
4593
|
+
if (!normalized)
|
|
4594
|
+
return;
|
|
4595
|
+
const key2 = milestoneKey(normalized);
|
|
4596
|
+
if (seen.has(key2))
|
|
4597
|
+
return;
|
|
4598
|
+
seen.add(key2);
|
|
4599
|
+
merged.push(normalized);
|
|
4600
|
+
};
|
|
4601
|
+
for (const m of configMilestones) {
|
|
4602
|
+
addMilestone(m);
|
|
4664
4603
|
}
|
|
4665
|
-
|
|
4666
|
-
|
|
4604
|
+
for (const task of tasks) {
|
|
4605
|
+
addMilestone(task.milestone ?? "");
|
|
4667
4606
|
}
|
|
4668
|
-
|
|
4669
|
-
|
|
4607
|
+
return merged;
|
|
4608
|
+
}
|
|
4609
|
+
function createBucket(milestoneId, tasks, statuses, milestoneEntities, isNoMilestone) {
|
|
4610
|
+
const bucketMilestoneKey = milestoneKey(milestoneId);
|
|
4611
|
+
const bucketTasks = tasks.filter((task) => {
|
|
4612
|
+
const taskMilestoneKey = milestoneKey(task.milestone);
|
|
4613
|
+
return bucketMilestoneKey ? taskMilestoneKey === bucketMilestoneKey : !taskMilestoneKey;
|
|
4614
|
+
});
|
|
4615
|
+
const counts = {};
|
|
4616
|
+
for (const status of statuses) {
|
|
4617
|
+
counts[status] = 0;
|
|
4670
4618
|
}
|
|
4671
|
-
|
|
4672
|
-
|
|
4619
|
+
for (const task of bucketTasks) {
|
|
4620
|
+
const status = task.status ?? "";
|
|
4621
|
+
counts[status] = (counts[status] ?? 0) + 1;
|
|
4673
4622
|
}
|
|
4674
|
-
|
|
4675
|
-
|
|
4623
|
+
const doneCount = bucketTasks.filter((t) => isDoneStatus(t.status)).length;
|
|
4624
|
+
const progress = bucketTasks.length > 0 ? Math.round(doneCount / bucketTasks.length * 100) : 0;
|
|
4625
|
+
const key2 = bucketMilestoneKey ? bucketMilestoneKey : NO_MILESTONE_KEY;
|
|
4626
|
+
const label = getMilestoneLabel(milestoneId, milestoneEntities);
|
|
4627
|
+
return {
|
|
4628
|
+
key: key2,
|
|
4629
|
+
label,
|
|
4630
|
+
milestone: milestoneId,
|
|
4631
|
+
isNoMilestone,
|
|
4632
|
+
tasks: bucketTasks,
|
|
4633
|
+
statusCounts: counts,
|
|
4634
|
+
total: bucketTasks.length,
|
|
4635
|
+
doneCount,
|
|
4636
|
+
progress
|
|
4637
|
+
};
|
|
4638
|
+
}
|
|
4639
|
+
function buildMilestoneBuckets(tasks, milestoneEntities, statuses) {
|
|
4640
|
+
const allMilestoneIds = collectMilestoneIds(tasks, milestoneEntities);
|
|
4641
|
+
const buckets = [
|
|
4642
|
+
// "No milestone" bucket first
|
|
4643
|
+
createBucket(void 0, tasks, statuses, milestoneEntities, true),
|
|
4644
|
+
// Then each milestone bucket
|
|
4645
|
+
...allMilestoneIds.map((m) => createBucket(m, tasks, statuses, milestoneEntities, false))
|
|
4646
|
+
];
|
|
4647
|
+
return buckets;
|
|
4648
|
+
}
|
|
4649
|
+
function buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses) {
|
|
4650
|
+
const milestoneEntities = configMilestones.map((id) => ({
|
|
4651
|
+
id,
|
|
4652
|
+
title: id,
|
|
4653
|
+
description: "",
|
|
4654
|
+
rawContent: "",
|
|
4655
|
+
tasks: []
|
|
4656
|
+
}));
|
|
4657
|
+
return buildMilestoneBuckets(tasks, milestoneEntities, statuses);
|
|
4658
|
+
}
|
|
4659
|
+
function groupTasksByMilestone(tasks, configMilestones, statuses) {
|
|
4660
|
+
const milestones = collectMilestones(tasks, configMilestones);
|
|
4661
|
+
const buckets = buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses);
|
|
4662
|
+
return {
|
|
4663
|
+
milestones,
|
|
4664
|
+
buckets
|
|
4665
|
+
};
|
|
4676
4666
|
}
|
|
4677
4667
|
const PRIORITY_ORDER = {
|
|
4678
4668
|
high: 0,
|
|
@@ -4694,11 +4684,10 @@ function sortTasksBy(tasks, sortBy = "title", direction = "asc") {
|
|
|
4694
4684
|
const cmp = a.createdDate.localeCompare(b.createdDate);
|
|
4695
4685
|
return direction === "asc" ? cmp : -cmp;
|
|
4696
4686
|
});
|
|
4697
|
-
|
|
4698
|
-
case "ordinal":
|
|
4699
|
-
default:
|
|
4687
|
+
default: {
|
|
4700
4688
|
const sorted = sortTasks(tasks);
|
|
4701
4689
|
return direction === "desc" ? sorted.reverse() : sorted;
|
|
4690
|
+
}
|
|
4702
4691
|
}
|
|
4703
4692
|
}
|
|
4704
4693
|
function sortTasks(tasks) {
|
|
@@ -4735,123 +4724,155 @@ function groupTasksByStatus(tasks, statuses) {
|
|
|
4735
4724
|
}
|
|
4736
4725
|
return grouped;
|
|
4737
4726
|
}
|
|
4738
|
-
const
|
|
4739
|
-
function
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4727
|
+
const DEFAULT_STATUSES = ["To Do", "In Progress", "Done"];
|
|
4728
|
+
function parseBacklogConfig(content2) {
|
|
4729
|
+
const config = {};
|
|
4730
|
+
const lines = content2.split("\n");
|
|
4731
|
+
for (const line of lines) {
|
|
4732
|
+
const trimmed = line.trim();
|
|
4733
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
4734
|
+
continue;
|
|
4735
|
+
const colonIndex = trimmed.indexOf(":");
|
|
4736
|
+
if (colonIndex === -1)
|
|
4737
|
+
continue;
|
|
4738
|
+
const key2 = trimmed.substring(0, colonIndex).trim();
|
|
4739
|
+
const value = trimmed.substring(colonIndex + 1).trim();
|
|
4740
|
+
switch (key2) {
|
|
4741
|
+
case "project_name":
|
|
4742
|
+
config.projectName = value.replace(/['"]/g, "");
|
|
4743
|
+
break;
|
|
4744
|
+
case "default_assignee":
|
|
4745
|
+
config.defaultAssignee = value.replace(/['"]/g, "");
|
|
4746
|
+
break;
|
|
4747
|
+
case "default_reporter":
|
|
4748
|
+
config.defaultReporter = value.replace(/['"]/g, "");
|
|
4749
|
+
break;
|
|
4750
|
+
case "default_status":
|
|
4751
|
+
config.defaultStatus = value.replace(/['"]/g, "");
|
|
4752
|
+
break;
|
|
4753
|
+
case "statuses":
|
|
4754
|
+
case "labels":
|
|
4755
|
+
case "milestones":
|
|
4756
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
4757
|
+
const arrayContent = value.slice(1, -1);
|
|
4758
|
+
config[key2] = arrayContent.split(",").map((item) => item.trim().replace(/['"]/g, "")).filter(Boolean);
|
|
4759
|
+
}
|
|
4760
|
+
break;
|
|
4761
|
+
case "date_format":
|
|
4762
|
+
config.dateFormat = value.replace(/['"]/g, "");
|
|
4763
|
+
break;
|
|
4764
|
+
case "max_column_width":
|
|
4765
|
+
config.maxColumnWidth = parseInt(value, 10);
|
|
4766
|
+
break;
|
|
4767
|
+
case "task_resolution_strategy":
|
|
4768
|
+
config.taskResolutionStrategy = value.replace(/['"]/g, "");
|
|
4769
|
+
break;
|
|
4770
|
+
case "default_editor":
|
|
4771
|
+
config.defaultEditor = value.replace(/["']/g, "");
|
|
4772
|
+
break;
|
|
4773
|
+
case "auto_open_browser":
|
|
4774
|
+
config.autoOpenBrowser = value.toLowerCase() === "true";
|
|
4775
|
+
break;
|
|
4776
|
+
case "default_port":
|
|
4777
|
+
config.defaultPort = parseInt(value, 10);
|
|
4778
|
+
break;
|
|
4779
|
+
case "remote_operations":
|
|
4780
|
+
config.remoteOperations = value.toLowerCase() === "true";
|
|
4781
|
+
break;
|
|
4782
|
+
case "auto_commit":
|
|
4783
|
+
config.autoCommit = value.toLowerCase() === "true";
|
|
4784
|
+
break;
|
|
4785
|
+
case "zero_padded_ids":
|
|
4786
|
+
config.zeroPaddedIds = parseInt(value, 10);
|
|
4787
|
+
break;
|
|
4788
|
+
case "timezone_preference":
|
|
4789
|
+
config.timezonePreference = value.replace(/['"]/g, "");
|
|
4790
|
+
break;
|
|
4791
|
+
case "include_date_time_in_dates":
|
|
4792
|
+
config.includeDateTimeInDates = value.toLowerCase() === "true";
|
|
4793
|
+
break;
|
|
4794
|
+
case "bypass_git_hooks":
|
|
4795
|
+
config.bypassGitHooks = value.toLowerCase() === "true";
|
|
4796
|
+
break;
|
|
4797
|
+
case "check_active_branches":
|
|
4798
|
+
config.checkActiveBranches = value.toLowerCase() === "true";
|
|
4799
|
+
break;
|
|
4800
|
+
case "active_branch_days":
|
|
4801
|
+
config.activeBranchDays = parseInt(value, 10);
|
|
4802
|
+
break;
|
|
4803
|
+
}
|
|
4752
4804
|
}
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4805
|
+
return {
|
|
4806
|
+
projectName: config.projectName || "Backlog",
|
|
4807
|
+
statuses: config.statuses || [...DEFAULT_STATUSES],
|
|
4808
|
+
labels: config.labels || [],
|
|
4809
|
+
milestones: config.milestones || [],
|
|
4810
|
+
defaultStatus: config.defaultStatus || DEFAULT_STATUSES[0],
|
|
4811
|
+
dateFormat: config.dateFormat || "YYYY-MM-DD",
|
|
4812
|
+
defaultAssignee: config.defaultAssignee,
|
|
4813
|
+
defaultReporter: config.defaultReporter,
|
|
4814
|
+
maxColumnWidth: config.maxColumnWidth,
|
|
4815
|
+
taskResolutionStrategy: config.taskResolutionStrategy,
|
|
4816
|
+
defaultEditor: config.defaultEditor,
|
|
4817
|
+
autoOpenBrowser: config.autoOpenBrowser,
|
|
4818
|
+
defaultPort: config.defaultPort,
|
|
4819
|
+
remoteOperations: config.remoteOperations,
|
|
4820
|
+
autoCommit: config.autoCommit,
|
|
4821
|
+
zeroPaddedIds: config.zeroPaddedIds,
|
|
4822
|
+
timezonePreference: config.timezonePreference,
|
|
4823
|
+
includeDateTimeInDates: config.includeDateTimeInDates,
|
|
4824
|
+
bypassGitHooks: config.bypassGitHooks,
|
|
4825
|
+
checkActiveBranches: config.checkActiveBranches,
|
|
4826
|
+
activeBranchDays: config.activeBranchDays
|
|
4768
4827
|
};
|
|
4769
|
-
|
|
4770
|
-
|
|
4828
|
+
}
|
|
4829
|
+
function serializeBacklogConfig(config) {
|
|
4830
|
+
const lines = [];
|
|
4831
|
+
lines.push(`project_name: "${config.projectName}"`);
|
|
4832
|
+
if (config.defaultStatus) {
|
|
4833
|
+
lines.push(`default_status: "${config.defaultStatus}"`);
|
|
4771
4834
|
}
|
|
4772
|
-
|
|
4773
|
-
|
|
4835
|
+
lines.push(`statuses: [${config.statuses.map((s2) => `"${s2}"`).join(", ")}]`);
|
|
4836
|
+
lines.push(`labels: [${(config.labels || []).map((l) => `"${l}"`).join(", ")}]`);
|
|
4837
|
+
lines.push(`milestones: [${(config.milestones || []).map((m) => `"${m}"`).join(", ")}]`);
|
|
4838
|
+
if (config.dateFormat) {
|
|
4839
|
+
lines.push(`date_format: "${config.dateFormat}"`);
|
|
4774
4840
|
}
|
|
4775
|
-
|
|
4776
|
-
}
|
|
4777
|
-
function collectMilestones(tasks, configMilestones) {
|
|
4778
|
-
const merged = [];
|
|
4779
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4780
|
-
const addMilestone = (value) => {
|
|
4781
|
-
const normalized = normalizeMilestoneName(value);
|
|
4782
|
-
if (!normalized)
|
|
4783
|
-
return;
|
|
4784
|
-
const key2 = milestoneKey(normalized);
|
|
4785
|
-
if (seen.has(key2))
|
|
4786
|
-
return;
|
|
4787
|
-
seen.add(key2);
|
|
4788
|
-
merged.push(normalized);
|
|
4789
|
-
};
|
|
4790
|
-
for (const m of configMilestones) {
|
|
4791
|
-
addMilestone(m);
|
|
4841
|
+
if (config.defaultAssignee) {
|
|
4842
|
+
lines.push(`default_assignee: "${config.defaultAssignee}"`);
|
|
4792
4843
|
}
|
|
4793
|
-
|
|
4794
|
-
|
|
4844
|
+
if (config.defaultReporter) {
|
|
4845
|
+
lines.push(`default_reporter: "${config.defaultReporter}"`);
|
|
4795
4846
|
}
|
|
4796
|
-
|
|
4797
|
-
}
|
|
4798
|
-
function createBucket(milestoneId, tasks, statuses, milestoneEntities, isNoMilestone) {
|
|
4799
|
-
const bucketMilestoneKey = milestoneKey(milestoneId);
|
|
4800
|
-
const bucketTasks = tasks.filter((task) => {
|
|
4801
|
-
const taskMilestoneKey = milestoneKey(task.milestone);
|
|
4802
|
-
return bucketMilestoneKey ? taskMilestoneKey === bucketMilestoneKey : !taskMilestoneKey;
|
|
4803
|
-
});
|
|
4804
|
-
const counts = {};
|
|
4805
|
-
for (const status of statuses) {
|
|
4806
|
-
counts[status] = 0;
|
|
4847
|
+
if (config.defaultEditor) {
|
|
4848
|
+
lines.push(`default_editor: "${config.defaultEditor}"`);
|
|
4807
4849
|
}
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
counts[status] = (counts[status] ?? 0) + 1;
|
|
4850
|
+
if (typeof config.autoCommit === "boolean") {
|
|
4851
|
+
lines.push(`auto_commit: ${config.autoCommit}`);
|
|
4811
4852
|
}
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
}
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
];
|
|
4836
|
-
return buckets;
|
|
4837
|
-
}
|
|
4838
|
-
function buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses) {
|
|
4839
|
-
const milestoneEntities = configMilestones.map((id) => ({
|
|
4840
|
-
id,
|
|
4841
|
-
title: id,
|
|
4842
|
-
description: "",
|
|
4843
|
-
rawContent: "",
|
|
4844
|
-
tasks: []
|
|
4845
|
-
}));
|
|
4846
|
-
return buildMilestoneBuckets(tasks, milestoneEntities, statuses);
|
|
4847
|
-
}
|
|
4848
|
-
function groupTasksByMilestone(tasks, configMilestones, statuses) {
|
|
4849
|
-
const milestones = collectMilestones(tasks, configMilestones);
|
|
4850
|
-
const buckets = buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses);
|
|
4851
|
-
return {
|
|
4852
|
-
milestones,
|
|
4853
|
-
buckets
|
|
4854
|
-
};
|
|
4853
|
+
if (typeof config.zeroPaddedIds === "number") {
|
|
4854
|
+
lines.push(`zero_padded_ids: ${config.zeroPaddedIds}`);
|
|
4855
|
+
}
|
|
4856
|
+
if (typeof config.autoOpenBrowser === "boolean") {
|
|
4857
|
+
lines.push(`auto_open_browser: ${config.autoOpenBrowser}`);
|
|
4858
|
+
}
|
|
4859
|
+
if (typeof config.defaultPort === "number") {
|
|
4860
|
+
lines.push(`default_port: ${config.defaultPort}`);
|
|
4861
|
+
}
|
|
4862
|
+
if (typeof config.remoteOperations === "boolean") {
|
|
4863
|
+
lines.push(`remote_operations: ${config.remoteOperations}`);
|
|
4864
|
+
}
|
|
4865
|
+
if (typeof config.bypassGitHooks === "boolean") {
|
|
4866
|
+
lines.push(`bypass_git_hooks: ${config.bypassGitHooks}`);
|
|
4867
|
+
}
|
|
4868
|
+
if (typeof config.checkActiveBranches === "boolean") {
|
|
4869
|
+
lines.push(`check_active_branches: ${config.checkActiveBranches}`);
|
|
4870
|
+
}
|
|
4871
|
+
if (typeof config.activeBranchDays === "number") {
|
|
4872
|
+
lines.push(`active_branch_days: ${config.activeBranchDays}`);
|
|
4873
|
+
}
|
|
4874
|
+
return `${lines.join("\n")}
|
|
4875
|
+
`;
|
|
4855
4876
|
}
|
|
4856
4877
|
class Core {
|
|
4857
4878
|
constructor(options) {
|
|
@@ -5045,7 +5066,7 @@ class Core {
|
|
|
5045
5066
|
const tasksLimit = (options == null ? void 0 : options.tasksLimit) ?? 10;
|
|
5046
5067
|
const completedLimit = (options == null ? void 0 : options.completedLimit) ?? 10;
|
|
5047
5068
|
const offset = (options == null ? void 0 : options.offset) ?? 0;
|
|
5048
|
-
(options == null ? void 0 : options.tasksSortDirection) ?? "asc";
|
|
5069
|
+
const tasksSortDirection = (options == null ? void 0 : options.tasksSortDirection) ?? "asc";
|
|
5049
5070
|
const completedSortByIdDesc = (options == null ? void 0 : options.completedSortByIdDesc) ?? true;
|
|
5050
5071
|
const sources = ["tasks", "completed"];
|
|
5051
5072
|
const bySource = /* @__PURE__ */ new Map();
|
|
@@ -5055,7 +5076,11 @@ class Core {
|
|
|
5055
5076
|
entries = entries.sort((a, b) => {
|
|
5056
5077
|
const aNum = parseInt(a.id.replace(/\D/g, ""), 10) || 0;
|
|
5057
5078
|
const bNum = parseInt(b.id.replace(/\D/g, ""), 10) || 0;
|
|
5058
|
-
|
|
5079
|
+
if (source2 === "completed") {
|
|
5080
|
+
return completedSortByIdDesc ? bNum - aNum : aNum - bNum;
|
|
5081
|
+
} else {
|
|
5082
|
+
return tasksSortDirection === "desc" ? bNum - aNum : aNum - bNum;
|
|
5083
|
+
}
|
|
5059
5084
|
});
|
|
5060
5085
|
const total = entries.length;
|
|
5061
5086
|
const pageEntries = entries.slice(offset, offset + limit);
|
|
@@ -5086,13 +5111,17 @@ class Core {
|
|
|
5086
5111
|
throw new Error("Core not lazy initialized. Call initializeLazy() first.");
|
|
5087
5112
|
}
|
|
5088
5113
|
const limit = (options == null ? void 0 : options.limit) ?? 10;
|
|
5089
|
-
(options == null ? void 0 : options.sortDirection) ?? "asc";
|
|
5114
|
+
const sortDirection = (options == null ? void 0 : options.sortDirection) ?? "asc";
|
|
5090
5115
|
const completedSortByIdDesc = (options == null ? void 0 : options.completedSortByIdDesc) ?? true;
|
|
5091
5116
|
let entries = Array.from(this.taskIndex.values()).filter((e) => e.source === source2);
|
|
5092
5117
|
entries = entries.sort((a, b) => {
|
|
5093
5118
|
const aNum = parseInt(a.id.replace(/\D/g, ""), 10) || 0;
|
|
5094
5119
|
const bNum = parseInt(b.id.replace(/\D/g, ""), 10) || 0;
|
|
5095
|
-
|
|
5120
|
+
if (source2 === "completed") {
|
|
5121
|
+
return completedSortByIdDesc ? bNum - aNum : aNum - bNum;
|
|
5122
|
+
} else {
|
|
5123
|
+
return sortDirection === "desc" ? bNum - aNum : aNum - bNum;
|
|
5124
|
+
}
|
|
5096
5125
|
});
|
|
5097
5126
|
const total = entries.length;
|
|
5098
5127
|
const pageEntries = entries.slice(currentOffset, currentOffset + limit);
|
|
@@ -5112,7 +5141,7 @@ class Core {
|
|
|
5112
5141
|
*/
|
|
5113
5142
|
getConfig() {
|
|
5114
5143
|
this.ensureInitialized();
|
|
5115
|
-
return this.
|
|
5144
|
+
return this.safeConfig;
|
|
5116
5145
|
}
|
|
5117
5146
|
/**
|
|
5118
5147
|
* List all tasks, optionally filtered
|
|
@@ -5127,7 +5156,8 @@ class Core {
|
|
|
5127
5156
|
tasks = tasks.filter((t) => t.status === filter.status);
|
|
5128
5157
|
}
|
|
5129
5158
|
if (filter == null ? void 0 : filter.assignee) {
|
|
5130
|
-
|
|
5159
|
+
const assignee = filter.assignee;
|
|
5160
|
+
tasks = tasks.filter((t) => t.assignee.includes(assignee));
|
|
5131
5161
|
}
|
|
5132
5162
|
if (filter == null ? void 0 : filter.priority) {
|
|
5133
5163
|
tasks = tasks.filter((t) => t.priority === filter.priority);
|
|
@@ -5137,7 +5167,10 @@ class Core {
|
|
|
5137
5167
|
tasks = tasks.filter((t) => milestoneKey(t.milestone) === filterKey);
|
|
5138
5168
|
}
|
|
5139
5169
|
if ((filter == null ? void 0 : filter.labels) && filter.labels.length > 0) {
|
|
5140
|
-
tasks = tasks.filter((t) =>
|
|
5170
|
+
tasks = tasks.filter((t) => {
|
|
5171
|
+
var _a;
|
|
5172
|
+
return (_a = filter.labels) == null ? void 0 : _a.some((label) => t.labels.includes(label));
|
|
5173
|
+
});
|
|
5141
5174
|
}
|
|
5142
5175
|
if (filter == null ? void 0 : filter.parentTaskId) {
|
|
5143
5176
|
tasks = tasks.filter((t) => t.parentTaskId === filter.parentTaskId);
|
|
@@ -5154,7 +5187,7 @@ class Core {
|
|
|
5154
5187
|
getTasksByStatus() {
|
|
5155
5188
|
this.ensureInitialized();
|
|
5156
5189
|
const tasks = Array.from(this.tasks.values());
|
|
5157
|
-
return groupTasksByStatus(tasks, this.
|
|
5190
|
+
return groupTasksByStatus(tasks, this.safeConfig.statuses);
|
|
5158
5191
|
}
|
|
5159
5192
|
/**
|
|
5160
5193
|
* Get tasks grouped by milestone
|
|
@@ -5178,7 +5211,7 @@ class Core {
|
|
|
5178
5211
|
getTasksByMilestone() {
|
|
5179
5212
|
this.ensureInitialized();
|
|
5180
5213
|
const tasks = Array.from(this.tasks.values());
|
|
5181
|
-
return groupTasksByMilestone(tasks, this.
|
|
5214
|
+
return groupTasksByMilestone(tasks, this.safeConfig.milestones, this.safeConfig.statuses);
|
|
5182
5215
|
}
|
|
5183
5216
|
// =========================================================================
|
|
5184
5217
|
// Milestone CRUD Operations
|
|
@@ -5404,7 +5437,7 @@ class Core {
|
|
|
5404
5437
|
const sortDirection = (pagination == null ? void 0 : pagination.sortDirection) ?? "asc";
|
|
5405
5438
|
const byStatus = /* @__PURE__ */ new Map();
|
|
5406
5439
|
const allGrouped = /* @__PURE__ */ new Map();
|
|
5407
|
-
for (const status of this.
|
|
5440
|
+
for (const status of this.safeConfig.statuses) {
|
|
5408
5441
|
allGrouped.set(status, []);
|
|
5409
5442
|
}
|
|
5410
5443
|
for (const task of this.tasks.values()) {
|
|
@@ -5415,7 +5448,7 @@ class Core {
|
|
|
5415
5448
|
allGrouped.set(task.status, [task]);
|
|
5416
5449
|
}
|
|
5417
5450
|
}
|
|
5418
|
-
for (const status of this.
|
|
5451
|
+
for (const status of this.safeConfig.statuses) {
|
|
5419
5452
|
let tasks = allGrouped.get(status) ?? [];
|
|
5420
5453
|
tasks = sortTasksBy(tasks, sortBy, sortDirection);
|
|
5421
5454
|
const total = tasks.length;
|
|
@@ -5430,7 +5463,7 @@ class Core {
|
|
|
5430
5463
|
}
|
|
5431
5464
|
return {
|
|
5432
5465
|
byStatus,
|
|
5433
|
-
statuses: this.
|
|
5466
|
+
statuses: this.safeConfig.statuses
|
|
5434
5467
|
};
|
|
5435
5468
|
}
|
|
5436
5469
|
/**
|
|
@@ -5470,10 +5503,16 @@ class Core {
|
|
|
5470
5503
|
}
|
|
5471
5504
|
// --- Private methods ---
|
|
5472
5505
|
ensureInitialized() {
|
|
5473
|
-
if (!this.initialized) {
|
|
5474
|
-
throw new Error("Core not initialized. Call initialize() first.");
|
|
5506
|
+
if (!this.initialized && !this.lazyInitialized || !this.config) {
|
|
5507
|
+
throw new Error("Core not initialized. Call initialize() or initializeLazy() first.");
|
|
5475
5508
|
}
|
|
5476
5509
|
}
|
|
5510
|
+
/**
|
|
5511
|
+
* Get config with type safety (use after ensureInitialized)
|
|
5512
|
+
*/
|
|
5513
|
+
get safeConfig() {
|
|
5514
|
+
return this.config;
|
|
5515
|
+
}
|
|
5477
5516
|
applyFilters(tasks, filter) {
|
|
5478
5517
|
if (!filter)
|
|
5479
5518
|
return tasks;
|
|
@@ -5482,7 +5521,8 @@ class Core {
|
|
|
5482
5521
|
result = result.filter((t) => t.status === filter.status);
|
|
5483
5522
|
}
|
|
5484
5523
|
if (filter.assignee) {
|
|
5485
|
-
|
|
5524
|
+
const assignee = filter.assignee;
|
|
5525
|
+
result = result.filter((t) => t.assignee.includes(assignee));
|
|
5486
5526
|
}
|
|
5487
5527
|
if (filter.priority) {
|
|
5488
5528
|
result = result.filter((t) => t.priority === filter.priority);
|
|
@@ -5492,7 +5532,10 @@ class Core {
|
|
|
5492
5532
|
result = result.filter((t) => milestoneKey(t.milestone) === filterKey);
|
|
5493
5533
|
}
|
|
5494
5534
|
if (filter.labels && filter.labels.length > 0) {
|
|
5495
|
-
result = result.filter((t) =>
|
|
5535
|
+
result = result.filter((t) => {
|
|
5536
|
+
var _a;
|
|
5537
|
+
return (_a = filter.labels) == null ? void 0 : _a.some((label) => t.labels.includes(label));
|
|
5538
|
+
});
|
|
5496
5539
|
}
|
|
5497
5540
|
if (filter.parentTaskId) {
|
|
5498
5541
|
result = result.filter((t) => t.parentTaskId === filter.parentTaskId);
|
|
@@ -5589,6 +5632,12 @@ class Core {
|
|
|
5589
5632
|
getTasksDir() {
|
|
5590
5633
|
return this.fs.join(this.projectRoot, "backlog", "tasks");
|
|
5591
5634
|
}
|
|
5635
|
+
/**
|
|
5636
|
+
* Get the completed directory path
|
|
5637
|
+
*/
|
|
5638
|
+
getCompletedDir() {
|
|
5639
|
+
return this.fs.join(this.projectRoot, "backlog", "completed");
|
|
5640
|
+
}
|
|
5592
5641
|
// =========================================================================
|
|
5593
5642
|
// Task CRUD Operations
|
|
5594
5643
|
// =========================================================================
|
|
@@ -5599,18 +5648,18 @@ class Core {
|
|
|
5599
5648
|
* @returns Created task
|
|
5600
5649
|
*/
|
|
5601
5650
|
async createTask(input) {
|
|
5602
|
-
var _a;
|
|
5651
|
+
var _a, _b;
|
|
5603
5652
|
this.ensureInitialized();
|
|
5604
5653
|
const tasksDir = this.getTasksDir();
|
|
5605
5654
|
await this.fs.createDir(tasksDir, { recursive: true });
|
|
5606
|
-
const existingIds = Array.from(this.tasks.keys()).map((id) => parseInt(id.replace(/\D/g, ""), 10)).filter((n) => !isNaN(n));
|
|
5655
|
+
const existingIds = Array.from(this.tasks.keys()).map((id) => parseInt(id.replace(/\D/g, ""), 10)).filter((n) => !Number.isNaN(n));
|
|
5607
5656
|
const nextId = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 1;
|
|
5608
5657
|
const taskId = String(nextId);
|
|
5609
5658
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
5610
5659
|
const task = {
|
|
5611
5660
|
id: taskId,
|
|
5612
5661
|
title: input.title,
|
|
5613
|
-
status: input.status || this.config.defaultStatus || "To Do",
|
|
5662
|
+
status: input.status || ((_a = this.config) == null ? void 0 : _a.defaultStatus) || "To Do",
|
|
5614
5663
|
priority: input.priority,
|
|
5615
5664
|
assignee: input.assignee || [],
|
|
5616
5665
|
createdDate: now,
|
|
@@ -5621,7 +5670,7 @@ class Core {
|
|
|
5621
5670
|
description: input.description,
|
|
5622
5671
|
implementationPlan: input.implementationPlan,
|
|
5623
5672
|
implementationNotes: input.implementationNotes,
|
|
5624
|
-
acceptanceCriteriaItems: (
|
|
5673
|
+
acceptanceCriteriaItems: (_b = input.acceptanceCriteria) == null ? void 0 : _b.map((ac, i) => ({
|
|
5625
5674
|
index: i + 1,
|
|
5626
5675
|
text: ac.text,
|
|
5627
5676
|
checked: ac.checked || false
|
|
@@ -5677,19 +5726,23 @@ class Core {
|
|
|
5677
5726
|
updated.labels = [.../* @__PURE__ */ new Set([...updated.labels, ...input.addLabels])];
|
|
5678
5727
|
}
|
|
5679
5728
|
if (input.removeLabels) {
|
|
5680
|
-
updated.labels = updated.labels.filter((l) =>
|
|
5729
|
+
updated.labels = updated.labels.filter((l) => {
|
|
5730
|
+
var _a;
|
|
5731
|
+
return !((_a = input.removeLabels) == null ? void 0 : _a.includes(l));
|
|
5732
|
+
});
|
|
5681
5733
|
}
|
|
5682
5734
|
}
|
|
5683
5735
|
if (input.assignee) {
|
|
5684
5736
|
updated.assignee = input.assignee;
|
|
5685
5737
|
}
|
|
5686
5738
|
if (input.addDependencies) {
|
|
5687
|
-
updated.dependencies = [
|
|
5688
|
-
.../* @__PURE__ */ new Set([...updated.dependencies, ...input.addDependencies])
|
|
5689
|
-
];
|
|
5739
|
+
updated.dependencies = [.../* @__PURE__ */ new Set([...updated.dependencies, ...input.addDependencies])];
|
|
5690
5740
|
}
|
|
5691
5741
|
if (input.removeDependencies) {
|
|
5692
|
-
updated.dependencies = updated.dependencies.filter((d) =>
|
|
5742
|
+
updated.dependencies = updated.dependencies.filter((d) => {
|
|
5743
|
+
var _a;
|
|
5744
|
+
return !((_a = input.removeDependencies) == null ? void 0 : _a.includes(d));
|
|
5745
|
+
});
|
|
5693
5746
|
}
|
|
5694
5747
|
if (input.acceptanceCriteria) {
|
|
5695
5748
|
updated.acceptanceCriteriaItems = input.acceptanceCriteria.map((ac, i) => ({
|
|
@@ -5745,6 +5798,92 @@ class Core {
|
|
|
5745
5798
|
this.tasks.delete(id);
|
|
5746
5799
|
return true;
|
|
5747
5800
|
}
|
|
5801
|
+
/**
|
|
5802
|
+
* Archive a task (move from tasks/ to completed/)
|
|
5803
|
+
*
|
|
5804
|
+
* @param id - Task ID to archive
|
|
5805
|
+
* @returns Archived task or null if not found or already archived
|
|
5806
|
+
*/
|
|
5807
|
+
async archiveTask(id) {
|
|
5808
|
+
this.ensureInitialized();
|
|
5809
|
+
const task = this.tasks.get(id);
|
|
5810
|
+
if (!task) {
|
|
5811
|
+
return null;
|
|
5812
|
+
}
|
|
5813
|
+
if (task.source === "completed") {
|
|
5814
|
+
return null;
|
|
5815
|
+
}
|
|
5816
|
+
const completedDir = this.getCompletedDir();
|
|
5817
|
+
await this.fs.createDir(completedDir, { recursive: true });
|
|
5818
|
+
const safeTitle = task.title.replace(/[<>:"/\\|?*]/g, "").replace(/\s+/g, " ").slice(0, 50);
|
|
5819
|
+
const filename = `${id} - ${safeTitle}.md`;
|
|
5820
|
+
const newFilepath = this.fs.join(completedDir, filename);
|
|
5821
|
+
if (task.filePath) {
|
|
5822
|
+
try {
|
|
5823
|
+
await this.fs.deleteFile(task.filePath);
|
|
5824
|
+
} catch {
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5827
|
+
const archived = {
|
|
5828
|
+
...task,
|
|
5829
|
+
source: "completed",
|
|
5830
|
+
filePath: newFilepath
|
|
5831
|
+
};
|
|
5832
|
+
const content2 = serializeTaskMarkdown(archived);
|
|
5833
|
+
await this.fs.writeFile(newFilepath, content2);
|
|
5834
|
+
this.tasks.set(id, archived);
|
|
5835
|
+
if (this.lazyInitialized) {
|
|
5836
|
+
const entry = this.taskIndex.get(id);
|
|
5837
|
+
if (entry) {
|
|
5838
|
+
entry.source = "completed";
|
|
5839
|
+
entry.filePath = newFilepath;
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
5842
|
+
return archived;
|
|
5843
|
+
}
|
|
5844
|
+
/**
|
|
5845
|
+
* Restore a task (move from completed/ to tasks/)
|
|
5846
|
+
*
|
|
5847
|
+
* @param id - Task ID to restore
|
|
5848
|
+
* @returns Restored task or null if not found or not archived
|
|
5849
|
+
*/
|
|
5850
|
+
async restoreTask(id) {
|
|
5851
|
+
this.ensureInitialized();
|
|
5852
|
+
const task = this.tasks.get(id);
|
|
5853
|
+
if (!task) {
|
|
5854
|
+
return null;
|
|
5855
|
+
}
|
|
5856
|
+
if (task.source !== "completed") {
|
|
5857
|
+
return null;
|
|
5858
|
+
}
|
|
5859
|
+
const tasksDir = this.getTasksDir();
|
|
5860
|
+
await this.fs.createDir(tasksDir, { recursive: true });
|
|
5861
|
+
const safeTitle = task.title.replace(/[<>:"/\\|?*]/g, "").replace(/\s+/g, " ").slice(0, 50);
|
|
5862
|
+
const filename = `${id} - ${safeTitle}.md`;
|
|
5863
|
+
const newFilepath = this.fs.join(tasksDir, filename);
|
|
5864
|
+
if (task.filePath) {
|
|
5865
|
+
try {
|
|
5866
|
+
await this.fs.deleteFile(task.filePath);
|
|
5867
|
+
} catch {
|
|
5868
|
+
}
|
|
5869
|
+
}
|
|
5870
|
+
const restored = {
|
|
5871
|
+
...task,
|
|
5872
|
+
source: "local",
|
|
5873
|
+
filePath: newFilepath
|
|
5874
|
+
};
|
|
5875
|
+
const content2 = serializeTaskMarkdown(restored);
|
|
5876
|
+
await this.fs.writeFile(newFilepath, content2);
|
|
5877
|
+
this.tasks.set(id, restored);
|
|
5878
|
+
if (this.lazyInitialized) {
|
|
5879
|
+
const entry = this.taskIndex.get(id);
|
|
5880
|
+
if (entry) {
|
|
5881
|
+
entry.source = "tasks";
|
|
5882
|
+
entry.filePath = newFilepath;
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
return restored;
|
|
5886
|
+
}
|
|
5748
5887
|
/**
|
|
5749
5888
|
* Load specific tasks by their IDs (for lazy loading milestone tasks)
|
|
5750
5889
|
*
|
|
@@ -5765,6 +5904,7 @@ class PanelFileSystemAdapter {
|
|
|
5765
5904
|
constructor(access) {
|
|
5766
5905
|
this.fetchFile = access.fetchFile;
|
|
5767
5906
|
this.filePaths = new Set(access.filePaths);
|
|
5907
|
+
this.hostFileSystem = access.hostFileSystem;
|
|
5768
5908
|
this.directories = /* @__PURE__ */ new Set();
|
|
5769
5909
|
for (const filePath of access.filePaths) {
|
|
5770
5910
|
const parts = filePath.split("/");
|
|
@@ -5774,6 +5914,13 @@ class PanelFileSystemAdapter {
|
|
|
5774
5914
|
}
|
|
5775
5915
|
this.directories.add("");
|
|
5776
5916
|
}
|
|
5917
|
+
/**
|
|
5918
|
+
* Check if write operations are available
|
|
5919
|
+
*/
|
|
5920
|
+
get canWrite() {
|
|
5921
|
+
var _a, _b;
|
|
5922
|
+
return !!(((_a = this.hostFileSystem) == null ? void 0 : _a.writeFile) && ((_b = this.hostFileSystem) == null ? void 0 : _b.createDir));
|
|
5923
|
+
}
|
|
5777
5924
|
async exists(path2) {
|
|
5778
5925
|
const normalized = this.normalizePath(path2);
|
|
5779
5926
|
return this.filePaths.has(normalized) || this.directories.has(normalized);
|
|
@@ -5785,14 +5932,36 @@ class PanelFileSystemAdapter {
|
|
|
5785
5932
|
}
|
|
5786
5933
|
return this.fetchFile(normalized);
|
|
5787
5934
|
}
|
|
5788
|
-
async writeFile(
|
|
5789
|
-
|
|
5935
|
+
async writeFile(path2, content2) {
|
|
5936
|
+
var _a;
|
|
5937
|
+
if (!((_a = this.hostFileSystem) == null ? void 0 : _a.writeFile)) {
|
|
5938
|
+
throw new Error("Write operations not available - host adapter not configured");
|
|
5939
|
+
}
|
|
5940
|
+
const normalized = this.normalizePath(path2);
|
|
5941
|
+
await this.hostFileSystem.writeFile(normalized, content2);
|
|
5942
|
+
this.filePaths.add(normalized);
|
|
5943
|
+
const parts = normalized.split("/");
|
|
5944
|
+
for (let i = 1; i < parts.length; i++) {
|
|
5945
|
+
this.directories.add(parts.slice(0, i).join("/"));
|
|
5946
|
+
}
|
|
5790
5947
|
}
|
|
5791
|
-
async deleteFile(
|
|
5792
|
-
|
|
5948
|
+
async deleteFile(path2) {
|
|
5949
|
+
var _a;
|
|
5950
|
+
if (!((_a = this.hostFileSystem) == null ? void 0 : _a.deleteFile)) {
|
|
5951
|
+
throw new Error("Delete operations not available - host adapter not configured");
|
|
5952
|
+
}
|
|
5953
|
+
const normalized = this.normalizePath(path2);
|
|
5954
|
+
await this.hostFileSystem.deleteFile(normalized);
|
|
5955
|
+
this.filePaths.delete(normalized);
|
|
5793
5956
|
}
|
|
5794
|
-
async createDir(
|
|
5795
|
-
|
|
5957
|
+
async createDir(path2, _options) {
|
|
5958
|
+
var _a;
|
|
5959
|
+
if (!((_a = this.hostFileSystem) == null ? void 0 : _a.createDir)) {
|
|
5960
|
+
throw new Error("Directory creation not available - host adapter not configured");
|
|
5961
|
+
}
|
|
5962
|
+
const normalized = this.normalizePath(path2);
|
|
5963
|
+
await this.hostFileSystem.createDir(normalized);
|
|
5964
|
+
this.directories.add(normalized);
|
|
5796
5965
|
}
|
|
5797
5966
|
async readDir(path2) {
|
|
5798
5967
|
const normalized = this.normalizePath(path2);
|
|
@@ -5905,6 +6074,7 @@ function useKanbanData(options) {
|
|
|
5905
6074
|
const [isLoading, setIsLoading] = useState(true);
|
|
5906
6075
|
const [error, setError] = useState(null);
|
|
5907
6076
|
const [isBacklogProject, setIsBacklogProject] = useState(false);
|
|
6077
|
+
const [canWrite, setCanWrite] = useState(false);
|
|
5908
6078
|
const [tasksBySource, setTasksBySource] = useState(
|
|
5909
6079
|
/* @__PURE__ */ new Map()
|
|
5910
6080
|
);
|
|
@@ -5950,7 +6120,7 @@ function useKanbanData(options) {
|
|
|
5950
6120
|
}, []);
|
|
5951
6121
|
const fileTreeVersionRef = useRef(null);
|
|
5952
6122
|
const loadBacklogData = useCallback(async () => {
|
|
5953
|
-
var _a, _b;
|
|
6123
|
+
var _a, _b, _c;
|
|
5954
6124
|
if (!context || !actions) {
|
|
5955
6125
|
console.log("[useKanbanData] No context provided");
|
|
5956
6126
|
setIsBacklogProject(false);
|
|
@@ -5986,7 +6156,8 @@ function useKanbanData(options) {
|
|
|
5986
6156
|
const filePaths = files.map((f) => f.path);
|
|
5987
6157
|
const fs = new PanelFileSystemAdapter({
|
|
5988
6158
|
fetchFile: fetchFileContent,
|
|
5989
|
-
filePaths
|
|
6159
|
+
filePaths,
|
|
6160
|
+
hostFileSystem: (_c = context.adapters) == null ? void 0 : _c.fileSystem
|
|
5990
6161
|
});
|
|
5991
6162
|
const core2 = new Core({
|
|
5992
6163
|
projectRoot: "",
|
|
@@ -6004,6 +6175,7 @@ function useKanbanData(options) {
|
|
|
6004
6175
|
}
|
|
6005
6176
|
console.log("[useKanbanData] Loading Backlog.md data with lazy loading...");
|
|
6006
6177
|
setIsBacklogProject(true);
|
|
6178
|
+
setCanWrite(fs.canWrite);
|
|
6007
6179
|
await core2.initializeLazy(filePaths);
|
|
6008
6180
|
coreRef.current = core2;
|
|
6009
6181
|
const paginatedResult = await core2.getTasksBySourcePaginated({
|
|
@@ -6138,14 +6310,28 @@ function useKanbanData(options) {
|
|
|
6138
6310
|
await loadBacklogData();
|
|
6139
6311
|
}, [loadBacklogData]);
|
|
6140
6312
|
const updateTaskStatus = useCallback(
|
|
6141
|
-
async (
|
|
6313
|
+
async (taskId, newStatus) => {
|
|
6314
|
+
const core2 = coreRef.current;
|
|
6315
|
+
if (!core2) {
|
|
6316
|
+
console.warn("[useKanbanData] Core not available for updateTaskStatus");
|
|
6317
|
+
setError("Cannot update task - backlog not loaded");
|
|
6318
|
+
return;
|
|
6319
|
+
}
|
|
6142
6320
|
setError(null);
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6321
|
+
try {
|
|
6322
|
+
console.log(`[useKanbanData] Updating task ${taskId} status to "${newStatus}"`);
|
|
6323
|
+
const updatedTask = await core2.updateTask(taskId, { status: newStatus });
|
|
6324
|
+
if (!updatedTask) {
|
|
6325
|
+
throw new Error(`Task ${taskId} not found`);
|
|
6326
|
+
}
|
|
6327
|
+
console.log(`[useKanbanData] Task ${taskId} updated successfully`);
|
|
6328
|
+
await loadBacklogData();
|
|
6329
|
+
} catch (err) {
|
|
6330
|
+
console.error("[useKanbanData] Failed to update task status:", err);
|
|
6331
|
+
setError(err instanceof Error ? err.message : "Failed to update task");
|
|
6332
|
+
}
|
|
6147
6333
|
},
|
|
6148
|
-
[]
|
|
6334
|
+
[loadBacklogData]
|
|
6149
6335
|
);
|
|
6150
6336
|
const moveTaskOptimistic = useCallback(
|
|
6151
6337
|
(taskId, toColumn) => {
|
|
@@ -6237,7 +6423,10 @@ function useKanbanData(options) {
|
|
|
6237
6423
|
loadMoreActive,
|
|
6238
6424
|
// Drag-and-drop support
|
|
6239
6425
|
moveTaskOptimistic,
|
|
6240
|
-
getTaskById
|
|
6426
|
+
getTaskById,
|
|
6427
|
+
// Write support
|
|
6428
|
+
canWrite,
|
|
6429
|
+
core: coreRef.current
|
|
6241
6430
|
};
|
|
6242
6431
|
}
|
|
6243
6432
|
const TaskCard = ({
|
|
@@ -6830,6 +7019,519 @@ const EmptyState = ({
|
|
|
6830
7019
|
)
|
|
6831
7020
|
] });
|
|
6832
7021
|
};
|
|
7022
|
+
const TaskModal = ({
|
|
7023
|
+
isOpen,
|
|
7024
|
+
onClose,
|
|
7025
|
+
onSave,
|
|
7026
|
+
task,
|
|
7027
|
+
defaultStatus = "To Do",
|
|
7028
|
+
availableStatuses = ["To Do", "In Progress", "Done"],
|
|
7029
|
+
availableMilestones = []
|
|
7030
|
+
}) => {
|
|
7031
|
+
const { theme: theme2 } = useTheme();
|
|
7032
|
+
const isEditing = !!task;
|
|
7033
|
+
const [title, setTitle] = useState("");
|
|
7034
|
+
const [description, setDescription] = useState("");
|
|
7035
|
+
const [status, setStatus] = useState(defaultStatus);
|
|
7036
|
+
const [priority, setPriority] = useState("medium");
|
|
7037
|
+
const [labels, setLabels] = useState("");
|
|
7038
|
+
const [assignee, setAssignee] = useState("");
|
|
7039
|
+
const [milestone, setMilestone] = useState("");
|
|
7040
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
7041
|
+
const [error, setError] = useState(null);
|
|
7042
|
+
useEffect(() => {
|
|
7043
|
+
var _a, _b;
|
|
7044
|
+
if (isOpen) {
|
|
7045
|
+
if (task) {
|
|
7046
|
+
setTitle(task.title || "");
|
|
7047
|
+
setDescription(task.description || "");
|
|
7048
|
+
setStatus(task.status || defaultStatus);
|
|
7049
|
+
setPriority(task.priority || "medium");
|
|
7050
|
+
setLabels(((_a = task.labels) == null ? void 0 : _a.join(", ")) || "");
|
|
7051
|
+
setAssignee(((_b = task.assignee) == null ? void 0 : _b.join(", ")) || "");
|
|
7052
|
+
setMilestone(task.milestone || "");
|
|
7053
|
+
} else {
|
|
7054
|
+
setTitle("");
|
|
7055
|
+
setDescription("");
|
|
7056
|
+
setStatus(defaultStatus);
|
|
7057
|
+
setPriority("medium");
|
|
7058
|
+
setLabels("");
|
|
7059
|
+
setAssignee("");
|
|
7060
|
+
setMilestone("");
|
|
7061
|
+
}
|
|
7062
|
+
setError(null);
|
|
7063
|
+
}
|
|
7064
|
+
}, [isOpen, task, defaultStatus]);
|
|
7065
|
+
const handleSubmit = async (e) => {
|
|
7066
|
+
e.preventDefault();
|
|
7067
|
+
if (!title.trim()) {
|
|
7068
|
+
setError("Title is required");
|
|
7069
|
+
return;
|
|
7070
|
+
}
|
|
7071
|
+
setIsSaving(true);
|
|
7072
|
+
setError(null);
|
|
7073
|
+
try {
|
|
7074
|
+
const labelsArray = labels.split(",").map((l) => l.trim()).filter(Boolean);
|
|
7075
|
+
const assigneeArray = assignee.split(",").map((a) => a.trim()).filter(Boolean);
|
|
7076
|
+
if (isEditing) {
|
|
7077
|
+
const input = {
|
|
7078
|
+
title: title.trim(),
|
|
7079
|
+
description: description.trim() || void 0,
|
|
7080
|
+
status,
|
|
7081
|
+
priority,
|
|
7082
|
+
labels: labelsArray.length > 0 ? labelsArray : void 0,
|
|
7083
|
+
assignee: assigneeArray.length > 0 ? assigneeArray : void 0,
|
|
7084
|
+
milestone: milestone || void 0
|
|
7085
|
+
};
|
|
7086
|
+
await onSave(input);
|
|
7087
|
+
} else {
|
|
7088
|
+
const input = {
|
|
7089
|
+
title: title.trim(),
|
|
7090
|
+
description: description.trim() || void 0,
|
|
7091
|
+
status,
|
|
7092
|
+
priority,
|
|
7093
|
+
labels: labelsArray.length > 0 ? labelsArray : void 0,
|
|
7094
|
+
assignee: assigneeArray.length > 0 ? assigneeArray : void 0,
|
|
7095
|
+
milestone: milestone || void 0
|
|
7096
|
+
};
|
|
7097
|
+
await onSave(input);
|
|
7098
|
+
}
|
|
7099
|
+
onClose();
|
|
7100
|
+
} catch (err) {
|
|
7101
|
+
setError(err instanceof Error ? err.message : "Failed to save task");
|
|
7102
|
+
} finally {
|
|
7103
|
+
setIsSaving(false);
|
|
7104
|
+
}
|
|
7105
|
+
};
|
|
7106
|
+
if (!isOpen) return null;
|
|
7107
|
+
const modalContent = /* @__PURE__ */ jsxs(
|
|
7108
|
+
"div",
|
|
7109
|
+
{
|
|
7110
|
+
style: {
|
|
7111
|
+
position: "fixed",
|
|
7112
|
+
inset: 0,
|
|
7113
|
+
zIndex: 9999,
|
|
7114
|
+
display: "flex",
|
|
7115
|
+
alignItems: "center",
|
|
7116
|
+
justifyContent: "center",
|
|
7117
|
+
padding: "16px"
|
|
7118
|
+
},
|
|
7119
|
+
children: [
|
|
7120
|
+
/* @__PURE__ */ jsx(
|
|
7121
|
+
"div",
|
|
7122
|
+
{
|
|
7123
|
+
onClick: onClose,
|
|
7124
|
+
style: {
|
|
7125
|
+
position: "absolute",
|
|
7126
|
+
inset: 0,
|
|
7127
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)"
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
),
|
|
7131
|
+
/* @__PURE__ */ jsxs(
|
|
7132
|
+
"div",
|
|
7133
|
+
{
|
|
7134
|
+
style: {
|
|
7135
|
+
position: "relative",
|
|
7136
|
+
width: "100%",
|
|
7137
|
+
maxWidth: "500px",
|
|
7138
|
+
maxHeight: "90vh",
|
|
7139
|
+
overflow: "auto",
|
|
7140
|
+
backgroundColor: theme2.colors.background,
|
|
7141
|
+
borderRadius: theme2.radii[3],
|
|
7142
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
|
7143
|
+
border: `1px solid ${theme2.colors.border}`
|
|
7144
|
+
},
|
|
7145
|
+
children: [
|
|
7146
|
+
/* @__PURE__ */ jsxs(
|
|
7147
|
+
"div",
|
|
7148
|
+
{
|
|
7149
|
+
style: {
|
|
7150
|
+
display: "flex",
|
|
7151
|
+
alignItems: "center",
|
|
7152
|
+
justifyContent: "space-between",
|
|
7153
|
+
padding: "16px 20px",
|
|
7154
|
+
borderBottom: `1px solid ${theme2.colors.border}`
|
|
7155
|
+
},
|
|
7156
|
+
children: [
|
|
7157
|
+
/* @__PURE__ */ jsx(
|
|
7158
|
+
"h2",
|
|
7159
|
+
{
|
|
7160
|
+
style: {
|
|
7161
|
+
margin: 0,
|
|
7162
|
+
fontSize: theme2.fontSizes[4],
|
|
7163
|
+
fontWeight: 600,
|
|
7164
|
+
color: theme2.colors.text
|
|
7165
|
+
},
|
|
7166
|
+
children: isEditing ? "Edit Task" : "New Task"
|
|
7167
|
+
}
|
|
7168
|
+
),
|
|
7169
|
+
/* @__PURE__ */ jsx(
|
|
7170
|
+
"button",
|
|
7171
|
+
{
|
|
7172
|
+
onClick: onClose,
|
|
7173
|
+
style: {
|
|
7174
|
+
background: "none",
|
|
7175
|
+
border: "none",
|
|
7176
|
+
cursor: "pointer",
|
|
7177
|
+
padding: "4px",
|
|
7178
|
+
display: "flex",
|
|
7179
|
+
alignItems: "center",
|
|
7180
|
+
justifyContent: "center",
|
|
7181
|
+
borderRadius: theme2.radii[1],
|
|
7182
|
+
color: theme2.colors.textMuted
|
|
7183
|
+
},
|
|
7184
|
+
children: /* @__PURE__ */ jsx(X, { size: 20 })
|
|
7185
|
+
}
|
|
7186
|
+
)
|
|
7187
|
+
]
|
|
7188
|
+
}
|
|
7189
|
+
),
|
|
7190
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
|
|
7191
|
+
/* @__PURE__ */ jsxs("div", { style: { padding: "20px", display: "flex", flexDirection: "column", gap: "16px" }, children: [
|
|
7192
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
7193
|
+
/* @__PURE__ */ jsx(
|
|
7194
|
+
"label",
|
|
7195
|
+
{
|
|
7196
|
+
style: {
|
|
7197
|
+
display: "block",
|
|
7198
|
+
marginBottom: "6px",
|
|
7199
|
+
fontSize: theme2.fontSizes[1],
|
|
7200
|
+
fontWeight: 500,
|
|
7201
|
+
color: theme2.colors.text
|
|
7202
|
+
},
|
|
7203
|
+
children: "Title *"
|
|
7204
|
+
}
|
|
7205
|
+
),
|
|
7206
|
+
/* @__PURE__ */ jsx(
|
|
7207
|
+
"input",
|
|
7208
|
+
{
|
|
7209
|
+
type: "text",
|
|
7210
|
+
value: title,
|
|
7211
|
+
onChange: (e) => setTitle(e.target.value),
|
|
7212
|
+
placeholder: "Enter task title",
|
|
7213
|
+
autoFocus: true,
|
|
7214
|
+
style: {
|
|
7215
|
+
width: "100%",
|
|
7216
|
+
padding: "10px 12px",
|
|
7217
|
+
fontSize: theme2.fontSizes[2],
|
|
7218
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7219
|
+
borderRadius: theme2.radii[2],
|
|
7220
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7221
|
+
color: theme2.colors.text,
|
|
7222
|
+
outline: "none",
|
|
7223
|
+
boxSizing: "border-box"
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
)
|
|
7227
|
+
] }),
|
|
7228
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
7229
|
+
/* @__PURE__ */ jsx(
|
|
7230
|
+
"label",
|
|
7231
|
+
{
|
|
7232
|
+
style: {
|
|
7233
|
+
display: "block",
|
|
7234
|
+
marginBottom: "6px",
|
|
7235
|
+
fontSize: theme2.fontSizes[1],
|
|
7236
|
+
fontWeight: 500,
|
|
7237
|
+
color: theme2.colors.text
|
|
7238
|
+
},
|
|
7239
|
+
children: "Description"
|
|
7240
|
+
}
|
|
7241
|
+
),
|
|
7242
|
+
/* @__PURE__ */ jsx(
|
|
7243
|
+
"textarea",
|
|
7244
|
+
{
|
|
7245
|
+
value: description,
|
|
7246
|
+
onChange: (e) => setDescription(e.target.value),
|
|
7247
|
+
placeholder: "Enter task description (markdown supported)",
|
|
7248
|
+
rows: 4,
|
|
7249
|
+
style: {
|
|
7250
|
+
width: "100%",
|
|
7251
|
+
padding: "10px 12px",
|
|
7252
|
+
fontSize: theme2.fontSizes[2],
|
|
7253
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7254
|
+
borderRadius: theme2.radii[2],
|
|
7255
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7256
|
+
color: theme2.colors.text,
|
|
7257
|
+
outline: "none",
|
|
7258
|
+
resize: "vertical",
|
|
7259
|
+
fontFamily: theme2.fonts.body,
|
|
7260
|
+
boxSizing: "border-box"
|
|
7261
|
+
}
|
|
7262
|
+
}
|
|
7263
|
+
)
|
|
7264
|
+
] }),
|
|
7265
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px" }, children: [
|
|
7266
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
7267
|
+
/* @__PURE__ */ jsx(
|
|
7268
|
+
"label",
|
|
7269
|
+
{
|
|
7270
|
+
style: {
|
|
7271
|
+
display: "block",
|
|
7272
|
+
marginBottom: "6px",
|
|
7273
|
+
fontSize: theme2.fontSizes[1],
|
|
7274
|
+
fontWeight: 500,
|
|
7275
|
+
color: theme2.colors.text
|
|
7276
|
+
},
|
|
7277
|
+
children: "Status"
|
|
7278
|
+
}
|
|
7279
|
+
),
|
|
7280
|
+
/* @__PURE__ */ jsx(
|
|
7281
|
+
"select",
|
|
7282
|
+
{
|
|
7283
|
+
value: status,
|
|
7284
|
+
onChange: (e) => setStatus(e.target.value),
|
|
7285
|
+
style: {
|
|
7286
|
+
width: "100%",
|
|
7287
|
+
padding: "10px 12px",
|
|
7288
|
+
fontSize: theme2.fontSizes[2],
|
|
7289
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7290
|
+
borderRadius: theme2.radii[2],
|
|
7291
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7292
|
+
color: theme2.colors.text,
|
|
7293
|
+
outline: "none",
|
|
7294
|
+
cursor: "pointer"
|
|
7295
|
+
},
|
|
7296
|
+
children: availableStatuses.map((s2) => /* @__PURE__ */ jsx("option", { value: s2, children: s2 }, s2))
|
|
7297
|
+
}
|
|
7298
|
+
)
|
|
7299
|
+
] }),
|
|
7300
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
7301
|
+
/* @__PURE__ */ jsx(
|
|
7302
|
+
"label",
|
|
7303
|
+
{
|
|
7304
|
+
style: {
|
|
7305
|
+
display: "block",
|
|
7306
|
+
marginBottom: "6px",
|
|
7307
|
+
fontSize: theme2.fontSizes[1],
|
|
7308
|
+
fontWeight: 500,
|
|
7309
|
+
color: theme2.colors.text
|
|
7310
|
+
},
|
|
7311
|
+
children: "Priority"
|
|
7312
|
+
}
|
|
7313
|
+
),
|
|
7314
|
+
/* @__PURE__ */ jsxs(
|
|
7315
|
+
"select",
|
|
7316
|
+
{
|
|
7317
|
+
value: priority,
|
|
7318
|
+
onChange: (e) => setPriority(e.target.value),
|
|
7319
|
+
style: {
|
|
7320
|
+
width: "100%",
|
|
7321
|
+
padding: "10px 12px",
|
|
7322
|
+
fontSize: theme2.fontSizes[2],
|
|
7323
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7324
|
+
borderRadius: theme2.radii[2],
|
|
7325
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7326
|
+
color: theme2.colors.text,
|
|
7327
|
+
outline: "none",
|
|
7328
|
+
cursor: "pointer"
|
|
7329
|
+
},
|
|
7330
|
+
children: [
|
|
7331
|
+
/* @__PURE__ */ jsx("option", { value: "low", children: "Low" }),
|
|
7332
|
+
/* @__PURE__ */ jsx("option", { value: "medium", children: "Medium" }),
|
|
7333
|
+
/* @__PURE__ */ jsx("option", { value: "high", children: "High" })
|
|
7334
|
+
]
|
|
7335
|
+
}
|
|
7336
|
+
)
|
|
7337
|
+
] })
|
|
7338
|
+
] }),
|
|
7339
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
7340
|
+
/* @__PURE__ */ jsx(
|
|
7341
|
+
"label",
|
|
7342
|
+
{
|
|
7343
|
+
style: {
|
|
7344
|
+
display: "block",
|
|
7345
|
+
marginBottom: "6px",
|
|
7346
|
+
fontSize: theme2.fontSizes[1],
|
|
7347
|
+
fontWeight: 500,
|
|
7348
|
+
color: theme2.colors.text
|
|
7349
|
+
},
|
|
7350
|
+
children: "Labels"
|
|
7351
|
+
}
|
|
7352
|
+
),
|
|
7353
|
+
/* @__PURE__ */ jsx(
|
|
7354
|
+
"input",
|
|
7355
|
+
{
|
|
7356
|
+
type: "text",
|
|
7357
|
+
value: labels,
|
|
7358
|
+
onChange: (e) => setLabels(e.target.value),
|
|
7359
|
+
placeholder: "bug, feature, enhancement (comma-separated)",
|
|
7360
|
+
style: {
|
|
7361
|
+
width: "100%",
|
|
7362
|
+
padding: "10px 12px",
|
|
7363
|
+
fontSize: theme2.fontSizes[2],
|
|
7364
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7365
|
+
borderRadius: theme2.radii[2],
|
|
7366
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7367
|
+
color: theme2.colors.text,
|
|
7368
|
+
outline: "none",
|
|
7369
|
+
boxSizing: "border-box"
|
|
7370
|
+
}
|
|
7371
|
+
}
|
|
7372
|
+
)
|
|
7373
|
+
] }),
|
|
7374
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
7375
|
+
/* @__PURE__ */ jsx(
|
|
7376
|
+
"label",
|
|
7377
|
+
{
|
|
7378
|
+
style: {
|
|
7379
|
+
display: "block",
|
|
7380
|
+
marginBottom: "6px",
|
|
7381
|
+
fontSize: theme2.fontSizes[1],
|
|
7382
|
+
fontWeight: 500,
|
|
7383
|
+
color: theme2.colors.text
|
|
7384
|
+
},
|
|
7385
|
+
children: "Assignee"
|
|
7386
|
+
}
|
|
7387
|
+
),
|
|
7388
|
+
/* @__PURE__ */ jsx(
|
|
7389
|
+
"input",
|
|
7390
|
+
{
|
|
7391
|
+
type: "text",
|
|
7392
|
+
value: assignee,
|
|
7393
|
+
onChange: (e) => setAssignee(e.target.value),
|
|
7394
|
+
placeholder: "user@example.com (comma-separated)",
|
|
7395
|
+
style: {
|
|
7396
|
+
width: "100%",
|
|
7397
|
+
padding: "10px 12px",
|
|
7398
|
+
fontSize: theme2.fontSizes[2],
|
|
7399
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7400
|
+
borderRadius: theme2.radii[2],
|
|
7401
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7402
|
+
color: theme2.colors.text,
|
|
7403
|
+
outline: "none",
|
|
7404
|
+
boxSizing: "border-box"
|
|
7405
|
+
}
|
|
7406
|
+
}
|
|
7407
|
+
)
|
|
7408
|
+
] }),
|
|
7409
|
+
availableMilestones.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
7410
|
+
/* @__PURE__ */ jsx(
|
|
7411
|
+
"label",
|
|
7412
|
+
{
|
|
7413
|
+
style: {
|
|
7414
|
+
display: "block",
|
|
7415
|
+
marginBottom: "6px",
|
|
7416
|
+
fontSize: theme2.fontSizes[1],
|
|
7417
|
+
fontWeight: 500,
|
|
7418
|
+
color: theme2.colors.text
|
|
7419
|
+
},
|
|
7420
|
+
children: "Milestone"
|
|
7421
|
+
}
|
|
7422
|
+
),
|
|
7423
|
+
/* @__PURE__ */ jsxs(
|
|
7424
|
+
"select",
|
|
7425
|
+
{
|
|
7426
|
+
value: milestone,
|
|
7427
|
+
onChange: (e) => setMilestone(e.target.value),
|
|
7428
|
+
style: {
|
|
7429
|
+
width: "100%",
|
|
7430
|
+
padding: "10px 12px",
|
|
7431
|
+
fontSize: theme2.fontSizes[2],
|
|
7432
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7433
|
+
borderRadius: theme2.radii[2],
|
|
7434
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
7435
|
+
color: theme2.colors.text,
|
|
7436
|
+
outline: "none",
|
|
7437
|
+
cursor: "pointer"
|
|
7438
|
+
},
|
|
7439
|
+
children: [
|
|
7440
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "None" }),
|
|
7441
|
+
availableMilestones.map((m) => /* @__PURE__ */ jsx("option", { value: m, children: m }, m))
|
|
7442
|
+
]
|
|
7443
|
+
}
|
|
7444
|
+
)
|
|
7445
|
+
] }),
|
|
7446
|
+
error && /* @__PURE__ */ jsx(
|
|
7447
|
+
"div",
|
|
7448
|
+
{
|
|
7449
|
+
style: {
|
|
7450
|
+
padding: "10px 12px",
|
|
7451
|
+
backgroundColor: `${theme2.colors.error}15`,
|
|
7452
|
+
border: `1px solid ${theme2.colors.error}`,
|
|
7453
|
+
borderRadius: theme2.radii[2],
|
|
7454
|
+
color: theme2.colors.error,
|
|
7455
|
+
fontSize: theme2.fontSizes[1]
|
|
7456
|
+
},
|
|
7457
|
+
children: error
|
|
7458
|
+
}
|
|
7459
|
+
)
|
|
7460
|
+
] }),
|
|
7461
|
+
/* @__PURE__ */ jsxs(
|
|
7462
|
+
"div",
|
|
7463
|
+
{
|
|
7464
|
+
style: {
|
|
7465
|
+
display: "flex",
|
|
7466
|
+
justifyContent: "flex-end",
|
|
7467
|
+
gap: "12px",
|
|
7468
|
+
padding: "16px 20px",
|
|
7469
|
+
borderTop: `1px solid ${theme2.colors.border}`
|
|
7470
|
+
},
|
|
7471
|
+
children: [
|
|
7472
|
+
/* @__PURE__ */ jsx(
|
|
7473
|
+
"button",
|
|
7474
|
+
{
|
|
7475
|
+
type: "button",
|
|
7476
|
+
onClick: onClose,
|
|
7477
|
+
disabled: isSaving,
|
|
7478
|
+
style: {
|
|
7479
|
+
padding: "10px 20px",
|
|
7480
|
+
fontSize: theme2.fontSizes[2],
|
|
7481
|
+
fontWeight: 500,
|
|
7482
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7483
|
+
borderRadius: theme2.radii[2],
|
|
7484
|
+
backgroundColor: "transparent",
|
|
7485
|
+
color: theme2.colors.text,
|
|
7486
|
+
cursor: "pointer"
|
|
7487
|
+
},
|
|
7488
|
+
children: "Cancel"
|
|
7489
|
+
}
|
|
7490
|
+
),
|
|
7491
|
+
/* @__PURE__ */ jsxs(
|
|
7492
|
+
"button",
|
|
7493
|
+
{
|
|
7494
|
+
type: "submit",
|
|
7495
|
+
disabled: isSaving,
|
|
7496
|
+
style: {
|
|
7497
|
+
display: "flex",
|
|
7498
|
+
alignItems: "center",
|
|
7499
|
+
gap: "8px",
|
|
7500
|
+
padding: "10px 20px",
|
|
7501
|
+
fontSize: theme2.fontSizes[2],
|
|
7502
|
+
fontWeight: 500,
|
|
7503
|
+
border: "none",
|
|
7504
|
+
borderRadius: theme2.radii[2],
|
|
7505
|
+
backgroundColor: theme2.colors.primary,
|
|
7506
|
+
color: "#fff",
|
|
7507
|
+
cursor: isSaving ? "wait" : "pointer",
|
|
7508
|
+
opacity: isSaving ? 0.7 : 1
|
|
7509
|
+
},
|
|
7510
|
+
children: [
|
|
7511
|
+
isSaving && /* @__PURE__ */ jsx(LoaderCircle, { size: 16, style: { animation: "spin 1s linear infinite" } }),
|
|
7512
|
+
isEditing ? "Save Changes" : "Create Task"
|
|
7513
|
+
]
|
|
7514
|
+
}
|
|
7515
|
+
)
|
|
7516
|
+
]
|
|
7517
|
+
}
|
|
7518
|
+
)
|
|
7519
|
+
] })
|
|
7520
|
+
]
|
|
7521
|
+
}
|
|
7522
|
+
),
|
|
7523
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
7524
|
+
@keyframes spin {
|
|
7525
|
+
from { transform: rotate(0deg); }
|
|
7526
|
+
to { transform: rotate(360deg); }
|
|
7527
|
+
}
|
|
7528
|
+
` })
|
|
7529
|
+
]
|
|
7530
|
+
}
|
|
7531
|
+
);
|
|
7532
|
+
if (typeof document === "undefined") return null;
|
|
7533
|
+
return createPortal(modalContent, document.body);
|
|
7534
|
+
};
|
|
6833
7535
|
const KanbanPanelContent = ({
|
|
6834
7536
|
context,
|
|
6835
7537
|
actions,
|
|
@@ -6842,6 +7544,8 @@ const KanbanPanelContent = ({
|
|
|
6842
7544
|
const [isNarrowView, setIsNarrowView] = useState(false);
|
|
6843
7545
|
const containerRef = useRef(null);
|
|
6844
7546
|
const [activeTask, setActiveTask] = useState(null);
|
|
7547
|
+
const [isTaskModalOpen, setIsTaskModalOpen] = useState(false);
|
|
7548
|
+
const [editingTask, setEditingTask] = useState(void 0);
|
|
6845
7549
|
const sensors = useSensors(
|
|
6846
7550
|
useSensor(PointerSensor, {
|
|
6847
7551
|
activationConstraint: {
|
|
@@ -6877,7 +7581,9 @@ const KanbanPanelContent = ({
|
|
|
6877
7581
|
isBacklogProject,
|
|
6878
7582
|
refreshData,
|
|
6879
7583
|
moveTaskOptimistic,
|
|
6880
|
-
getTaskById
|
|
7584
|
+
getTaskById,
|
|
7585
|
+
canWrite,
|
|
7586
|
+
core: core2
|
|
6881
7587
|
} = useKanbanData({
|
|
6882
7588
|
context,
|
|
6883
7589
|
actions,
|
|
@@ -6972,14 +7678,38 @@ const KanbanPanelContent = ({
|
|
|
6972
7678
|
normalize: (path2) => path2.replace(/\/+/g, "/"),
|
|
6973
7679
|
homedir: () => "/"
|
|
6974
7680
|
};
|
|
6975
|
-
const
|
|
7681
|
+
const core22 = new Core({
|
|
6976
7682
|
projectRoot: repoPath,
|
|
6977
7683
|
adapters: { fs: fsAdapter }
|
|
6978
7684
|
});
|
|
6979
7685
|
const projectName = ((_b2 = context.currentScope.repository) == null ? void 0 : _b2.name) || "Backlog";
|
|
6980
|
-
await
|
|
7686
|
+
await core22.initProject({ projectName });
|
|
6981
7687
|
await refreshData();
|
|
6982
7688
|
}, [fileSystem, context.currentScope.repository, refreshData]);
|
|
7689
|
+
const handleOpenNewTask = useCallback(() => {
|
|
7690
|
+
setEditingTask(void 0);
|
|
7691
|
+
setIsTaskModalOpen(true);
|
|
7692
|
+
}, []);
|
|
7693
|
+
useCallback((task) => {
|
|
7694
|
+
setEditingTask(task);
|
|
7695
|
+
setIsTaskModalOpen(true);
|
|
7696
|
+
}, []);
|
|
7697
|
+
const handleCloseTaskModal = useCallback(() => {
|
|
7698
|
+
setIsTaskModalOpen(false);
|
|
7699
|
+
setEditingTask(void 0);
|
|
7700
|
+
}, []);
|
|
7701
|
+
const handleSaveTask = useCallback(async (input) => {
|
|
7702
|
+
if (!core2) {
|
|
7703
|
+
throw new Error("Backlog not loaded");
|
|
7704
|
+
}
|
|
7705
|
+
if (editingTask) {
|
|
7706
|
+
await core2.updateTask(editingTask.id, input);
|
|
7707
|
+
} else {
|
|
7708
|
+
await core2.createTask(input);
|
|
7709
|
+
}
|
|
7710
|
+
await refreshData();
|
|
7711
|
+
}, [core2, editingTask, refreshData]);
|
|
7712
|
+
const availableStatuses = ["To Do", "In Progress", "Done"];
|
|
6983
7713
|
return /* @__PURE__ */ jsxs(
|
|
6984
7714
|
"div",
|
|
6985
7715
|
{
|
|
@@ -7053,12 +7783,14 @@ const KanbanPanelContent = ({
|
|
|
7053
7783
|
status
|
|
7054
7784
|
);
|
|
7055
7785
|
}) }),
|
|
7056
|
-
|
|
7786
|
+
canWrite && /* @__PURE__ */ jsxs(
|
|
7057
7787
|
"button",
|
|
7058
7788
|
{
|
|
7059
|
-
onClick:
|
|
7060
|
-
disabled: activeTasksState.isLoadingMore,
|
|
7789
|
+
onClick: handleOpenNewTask,
|
|
7061
7790
|
style: {
|
|
7791
|
+
display: "flex",
|
|
7792
|
+
alignItems: "center",
|
|
7793
|
+
gap: "6px",
|
|
7062
7794
|
background: theme2.colors.primary,
|
|
7063
7795
|
color: theme2.colors.background,
|
|
7064
7796
|
border: "none",
|
|
@@ -7066,6 +7798,28 @@ const KanbanPanelContent = ({
|
|
|
7066
7798
|
padding: "6px 12px",
|
|
7067
7799
|
fontSize: theme2.fontSizes[1],
|
|
7068
7800
|
fontWeight: theme2.fontWeights.medium,
|
|
7801
|
+
cursor: "pointer",
|
|
7802
|
+
transition: "opacity 0.2s ease"
|
|
7803
|
+
},
|
|
7804
|
+
children: [
|
|
7805
|
+
/* @__PURE__ */ jsx(Plus, { size: 14 }),
|
|
7806
|
+
"Add Task"
|
|
7807
|
+
]
|
|
7808
|
+
}
|
|
7809
|
+
),
|
|
7810
|
+
activeTasksState.hasMore && /* @__PURE__ */ jsx(
|
|
7811
|
+
"button",
|
|
7812
|
+
{
|
|
7813
|
+
onClick: loadMoreActive,
|
|
7814
|
+
disabled: activeTasksState.isLoadingMore,
|
|
7815
|
+
style: {
|
|
7816
|
+
background: theme2.colors.backgroundSecondary,
|
|
7817
|
+
color: theme2.colors.text,
|
|
7818
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
7819
|
+
borderRadius: theme2.radii[2],
|
|
7820
|
+
padding: "6px 12px",
|
|
7821
|
+
fontSize: theme2.fontSizes[1],
|
|
7822
|
+
fontWeight: theme2.fontWeights.medium,
|
|
7069
7823
|
cursor: activeTasksState.isLoadingMore ? "wait" : "pointer",
|
|
7070
7824
|
opacity: activeTasksState.isLoadingMore ? 0.7 : 1,
|
|
7071
7825
|
transition: "opacity 0.2s ease"
|
|
@@ -7247,6 +8001,17 @@ const KanbanPanelContent = ({
|
|
|
7247
8001
|
)
|
|
7248
8002
|
]
|
|
7249
8003
|
}
|
|
8004
|
+
),
|
|
8005
|
+
/* @__PURE__ */ jsx(
|
|
8006
|
+
TaskModal,
|
|
8007
|
+
{
|
|
8008
|
+
isOpen: isTaskModalOpen,
|
|
8009
|
+
onClose: handleCloseTaskModal,
|
|
8010
|
+
onSave: handleSaveTask,
|
|
8011
|
+
task: editingTask,
|
|
8012
|
+
defaultStatus: "To Do",
|
|
8013
|
+
availableStatuses
|
|
8014
|
+
}
|
|
7250
8015
|
)
|
|
7251
8016
|
]
|
|
7252
8017
|
}
|
|
@@ -51590,6 +52355,7 @@ function useMilestoneData(options) {
|
|
|
51590
52355
|
const [isLoading, setIsLoading] = useState(true);
|
|
51591
52356
|
const [error, setError] = useState(null);
|
|
51592
52357
|
const [isBacklogProject, setIsBacklogProject] = useState(false);
|
|
52358
|
+
const [canWrite, setCanWrite] = useState(false);
|
|
51593
52359
|
const coreRef = useRef(null);
|
|
51594
52360
|
const activeFilePathRef = useRef(null);
|
|
51595
52361
|
const contextRef = useRef(context);
|
|
@@ -51629,7 +52395,7 @@ function useMilestoneData(options) {
|
|
|
51629
52395
|
}, []);
|
|
51630
52396
|
const fileTreeVersionRef = useRef(null);
|
|
51631
52397
|
const loadMilestoneData = useCallback(async () => {
|
|
51632
|
-
var _a, _b;
|
|
52398
|
+
var _a, _b, _c;
|
|
51633
52399
|
if (!context || !actions) {
|
|
51634
52400
|
console.log("[useMilestoneData] No context provided");
|
|
51635
52401
|
setIsBacklogProject(false);
|
|
@@ -51661,7 +52427,8 @@ function useMilestoneData(options) {
|
|
|
51661
52427
|
const filePaths = files.map((f) => f.path);
|
|
51662
52428
|
const fs = new PanelFileSystemAdapter({
|
|
51663
52429
|
fetchFile: fetchFileContent,
|
|
51664
|
-
filePaths
|
|
52430
|
+
filePaths,
|
|
52431
|
+
hostFileSystem: (_c = context.adapters) == null ? void 0 : _c.fileSystem
|
|
51665
52432
|
});
|
|
51666
52433
|
const core2 = new Core({
|
|
51667
52434
|
projectRoot: "",
|
|
@@ -51677,6 +52444,7 @@ function useMilestoneData(options) {
|
|
|
51677
52444
|
}
|
|
51678
52445
|
console.log("[useMilestoneData] Loading milestone data...");
|
|
51679
52446
|
setIsBacklogProject(true);
|
|
52447
|
+
setCanWrite(fs.canWrite);
|
|
51680
52448
|
await core2.initializeLazy(filePaths);
|
|
51681
52449
|
coreRef.current = core2;
|
|
51682
52450
|
console.log("[useMilestoneData] Core instance:", core2);
|
|
@@ -51784,7 +52552,10 @@ function useMilestoneData(options) {
|
|
|
51784
52552
|
expandMilestone,
|
|
51785
52553
|
collapseMilestone,
|
|
51786
52554
|
toggleMilestone,
|
|
51787
|
-
refreshData
|
|
52555
|
+
refreshData,
|
|
52556
|
+
// Write support
|
|
52557
|
+
canWrite,
|
|
52558
|
+
core: coreRef.current
|
|
51788
52559
|
};
|
|
51789
52560
|
}
|
|
51790
52561
|
const MilestoneCard = ({
|
|
@@ -52137,6 +52908,307 @@ const MilestoneCard = ({
|
|
|
52137
52908
|
}
|
|
52138
52909
|
);
|
|
52139
52910
|
};
|
|
52911
|
+
const MilestoneModal = ({
|
|
52912
|
+
isOpen,
|
|
52913
|
+
onClose,
|
|
52914
|
+
onSave,
|
|
52915
|
+
milestone
|
|
52916
|
+
}) => {
|
|
52917
|
+
const { theme: theme2 } = useTheme();
|
|
52918
|
+
const isEditing = !!milestone;
|
|
52919
|
+
const [title, setTitle] = useState("");
|
|
52920
|
+
const [description, setDescription] = useState("");
|
|
52921
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
52922
|
+
const [error, setError] = useState(null);
|
|
52923
|
+
useEffect(() => {
|
|
52924
|
+
if (isOpen) {
|
|
52925
|
+
if (milestone) {
|
|
52926
|
+
setTitle(milestone.title || "");
|
|
52927
|
+
setDescription(milestone.description || "");
|
|
52928
|
+
} else {
|
|
52929
|
+
setTitle("");
|
|
52930
|
+
setDescription("");
|
|
52931
|
+
}
|
|
52932
|
+
setError(null);
|
|
52933
|
+
}
|
|
52934
|
+
}, [isOpen, milestone]);
|
|
52935
|
+
const handleSubmit = async (e) => {
|
|
52936
|
+
e.preventDefault();
|
|
52937
|
+
if (!title.trim()) {
|
|
52938
|
+
setError("Title is required");
|
|
52939
|
+
return;
|
|
52940
|
+
}
|
|
52941
|
+
setIsSaving(true);
|
|
52942
|
+
setError(null);
|
|
52943
|
+
try {
|
|
52944
|
+
if (isEditing) {
|
|
52945
|
+
const input = {
|
|
52946
|
+
title: title.trim(),
|
|
52947
|
+
description: description.trim() || void 0
|
|
52948
|
+
};
|
|
52949
|
+
await onSave(input);
|
|
52950
|
+
} else {
|
|
52951
|
+
const input = {
|
|
52952
|
+
title: title.trim(),
|
|
52953
|
+
description: description.trim() || void 0
|
|
52954
|
+
};
|
|
52955
|
+
await onSave(input);
|
|
52956
|
+
}
|
|
52957
|
+
onClose();
|
|
52958
|
+
} catch (err) {
|
|
52959
|
+
setError(err instanceof Error ? err.message : "Failed to save milestone");
|
|
52960
|
+
} finally {
|
|
52961
|
+
setIsSaving(false);
|
|
52962
|
+
}
|
|
52963
|
+
};
|
|
52964
|
+
if (!isOpen) return null;
|
|
52965
|
+
const modalContent = /* @__PURE__ */ jsxs(
|
|
52966
|
+
"div",
|
|
52967
|
+
{
|
|
52968
|
+
style: {
|
|
52969
|
+
position: "fixed",
|
|
52970
|
+
inset: 0,
|
|
52971
|
+
zIndex: 9999,
|
|
52972
|
+
display: "flex",
|
|
52973
|
+
alignItems: "center",
|
|
52974
|
+
justifyContent: "center",
|
|
52975
|
+
padding: "16px"
|
|
52976
|
+
},
|
|
52977
|
+
children: [
|
|
52978
|
+
/* @__PURE__ */ jsx(
|
|
52979
|
+
"div",
|
|
52980
|
+
{
|
|
52981
|
+
onClick: onClose,
|
|
52982
|
+
style: {
|
|
52983
|
+
position: "absolute",
|
|
52984
|
+
inset: 0,
|
|
52985
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)"
|
|
52986
|
+
}
|
|
52987
|
+
}
|
|
52988
|
+
),
|
|
52989
|
+
/* @__PURE__ */ jsxs(
|
|
52990
|
+
"div",
|
|
52991
|
+
{
|
|
52992
|
+
style: {
|
|
52993
|
+
position: "relative",
|
|
52994
|
+
width: "100%",
|
|
52995
|
+
maxWidth: "500px",
|
|
52996
|
+
maxHeight: "90vh",
|
|
52997
|
+
overflow: "auto",
|
|
52998
|
+
backgroundColor: theme2.colors.background,
|
|
52999
|
+
borderRadius: theme2.radii[3],
|
|
53000
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
|
53001
|
+
border: `1px solid ${theme2.colors.border}`
|
|
53002
|
+
},
|
|
53003
|
+
children: [
|
|
53004
|
+
/* @__PURE__ */ jsxs(
|
|
53005
|
+
"div",
|
|
53006
|
+
{
|
|
53007
|
+
style: {
|
|
53008
|
+
display: "flex",
|
|
53009
|
+
alignItems: "center",
|
|
53010
|
+
justifyContent: "space-between",
|
|
53011
|
+
padding: "16px 20px",
|
|
53012
|
+
borderBottom: `1px solid ${theme2.colors.border}`
|
|
53013
|
+
},
|
|
53014
|
+
children: [
|
|
53015
|
+
/* @__PURE__ */ jsx(
|
|
53016
|
+
"h2",
|
|
53017
|
+
{
|
|
53018
|
+
style: {
|
|
53019
|
+
margin: 0,
|
|
53020
|
+
fontSize: theme2.fontSizes[4],
|
|
53021
|
+
fontWeight: 600,
|
|
53022
|
+
color: theme2.colors.text
|
|
53023
|
+
},
|
|
53024
|
+
children: isEditing ? "Edit Milestone" : "New Milestone"
|
|
53025
|
+
}
|
|
53026
|
+
),
|
|
53027
|
+
/* @__PURE__ */ jsx(
|
|
53028
|
+
"button",
|
|
53029
|
+
{
|
|
53030
|
+
onClick: onClose,
|
|
53031
|
+
style: {
|
|
53032
|
+
background: "none",
|
|
53033
|
+
border: "none",
|
|
53034
|
+
cursor: "pointer",
|
|
53035
|
+
padding: "4px",
|
|
53036
|
+
display: "flex",
|
|
53037
|
+
alignItems: "center",
|
|
53038
|
+
justifyContent: "center",
|
|
53039
|
+
borderRadius: theme2.radii[1],
|
|
53040
|
+
color: theme2.colors.textMuted
|
|
53041
|
+
},
|
|
53042
|
+
children: /* @__PURE__ */ jsx(X, { size: 20 })
|
|
53043
|
+
}
|
|
53044
|
+
)
|
|
53045
|
+
]
|
|
53046
|
+
}
|
|
53047
|
+
),
|
|
53048
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
|
|
53049
|
+
/* @__PURE__ */ jsxs("div", { style: { padding: "20px", display: "flex", flexDirection: "column", gap: "16px" }, children: [
|
|
53050
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
53051
|
+
/* @__PURE__ */ jsx(
|
|
53052
|
+
"label",
|
|
53053
|
+
{
|
|
53054
|
+
style: {
|
|
53055
|
+
display: "block",
|
|
53056
|
+
marginBottom: "6px",
|
|
53057
|
+
fontSize: theme2.fontSizes[1],
|
|
53058
|
+
fontWeight: 500,
|
|
53059
|
+
color: theme2.colors.text
|
|
53060
|
+
},
|
|
53061
|
+
children: "Title *"
|
|
53062
|
+
}
|
|
53063
|
+
),
|
|
53064
|
+
/* @__PURE__ */ jsx(
|
|
53065
|
+
"input",
|
|
53066
|
+
{
|
|
53067
|
+
type: "text",
|
|
53068
|
+
value: title,
|
|
53069
|
+
onChange: (e) => setTitle(e.target.value),
|
|
53070
|
+
placeholder: "Enter milestone title",
|
|
53071
|
+
autoFocus: true,
|
|
53072
|
+
style: {
|
|
53073
|
+
width: "100%",
|
|
53074
|
+
padding: "10px 12px",
|
|
53075
|
+
fontSize: theme2.fontSizes[2],
|
|
53076
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
53077
|
+
borderRadius: theme2.radii[2],
|
|
53078
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
53079
|
+
color: theme2.colors.text,
|
|
53080
|
+
outline: "none",
|
|
53081
|
+
boxSizing: "border-box"
|
|
53082
|
+
}
|
|
53083
|
+
}
|
|
53084
|
+
)
|
|
53085
|
+
] }),
|
|
53086
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
53087
|
+
/* @__PURE__ */ jsx(
|
|
53088
|
+
"label",
|
|
53089
|
+
{
|
|
53090
|
+
style: {
|
|
53091
|
+
display: "block",
|
|
53092
|
+
marginBottom: "6px",
|
|
53093
|
+
fontSize: theme2.fontSizes[1],
|
|
53094
|
+
fontWeight: 500,
|
|
53095
|
+
color: theme2.colors.text
|
|
53096
|
+
},
|
|
53097
|
+
children: "Description"
|
|
53098
|
+
}
|
|
53099
|
+
),
|
|
53100
|
+
/* @__PURE__ */ jsx(
|
|
53101
|
+
"textarea",
|
|
53102
|
+
{
|
|
53103
|
+
value: description,
|
|
53104
|
+
onChange: (e) => setDescription(e.target.value),
|
|
53105
|
+
placeholder: "Enter milestone description (markdown supported)",
|
|
53106
|
+
rows: 4,
|
|
53107
|
+
style: {
|
|
53108
|
+
width: "100%",
|
|
53109
|
+
padding: "10px 12px",
|
|
53110
|
+
fontSize: theme2.fontSizes[2],
|
|
53111
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
53112
|
+
borderRadius: theme2.radii[2],
|
|
53113
|
+
backgroundColor: theme2.colors.backgroundSecondary,
|
|
53114
|
+
color: theme2.colors.text,
|
|
53115
|
+
outline: "none",
|
|
53116
|
+
resize: "vertical",
|
|
53117
|
+
fontFamily: theme2.fonts.body,
|
|
53118
|
+
boxSizing: "border-box"
|
|
53119
|
+
}
|
|
53120
|
+
}
|
|
53121
|
+
)
|
|
53122
|
+
] }),
|
|
53123
|
+
error && /* @__PURE__ */ jsx(
|
|
53124
|
+
"div",
|
|
53125
|
+
{
|
|
53126
|
+
style: {
|
|
53127
|
+
padding: "10px 12px",
|
|
53128
|
+
backgroundColor: `${theme2.colors.error}15`,
|
|
53129
|
+
border: `1px solid ${theme2.colors.error}`,
|
|
53130
|
+
borderRadius: theme2.radii[2],
|
|
53131
|
+
color: theme2.colors.error,
|
|
53132
|
+
fontSize: theme2.fontSizes[1]
|
|
53133
|
+
},
|
|
53134
|
+
children: error
|
|
53135
|
+
}
|
|
53136
|
+
)
|
|
53137
|
+
] }),
|
|
53138
|
+
/* @__PURE__ */ jsxs(
|
|
53139
|
+
"div",
|
|
53140
|
+
{
|
|
53141
|
+
style: {
|
|
53142
|
+
display: "flex",
|
|
53143
|
+
justifyContent: "flex-end",
|
|
53144
|
+
gap: "12px",
|
|
53145
|
+
padding: "16px 20px",
|
|
53146
|
+
borderTop: `1px solid ${theme2.colors.border}`
|
|
53147
|
+
},
|
|
53148
|
+
children: [
|
|
53149
|
+
/* @__PURE__ */ jsx(
|
|
53150
|
+
"button",
|
|
53151
|
+
{
|
|
53152
|
+
type: "button",
|
|
53153
|
+
onClick: onClose,
|
|
53154
|
+
disabled: isSaving,
|
|
53155
|
+
style: {
|
|
53156
|
+
padding: "10px 20px",
|
|
53157
|
+
fontSize: theme2.fontSizes[2],
|
|
53158
|
+
fontWeight: 500,
|
|
53159
|
+
border: `1px solid ${theme2.colors.border}`,
|
|
53160
|
+
borderRadius: theme2.radii[2],
|
|
53161
|
+
backgroundColor: "transparent",
|
|
53162
|
+
color: theme2.colors.text,
|
|
53163
|
+
cursor: "pointer"
|
|
53164
|
+
},
|
|
53165
|
+
children: "Cancel"
|
|
53166
|
+
}
|
|
53167
|
+
),
|
|
53168
|
+
/* @__PURE__ */ jsxs(
|
|
53169
|
+
"button",
|
|
53170
|
+
{
|
|
53171
|
+
type: "submit",
|
|
53172
|
+
disabled: isSaving,
|
|
53173
|
+
style: {
|
|
53174
|
+
display: "flex",
|
|
53175
|
+
alignItems: "center",
|
|
53176
|
+
gap: "8px",
|
|
53177
|
+
padding: "10px 20px",
|
|
53178
|
+
fontSize: theme2.fontSizes[2],
|
|
53179
|
+
fontWeight: 500,
|
|
53180
|
+
border: "none",
|
|
53181
|
+
borderRadius: theme2.radii[2],
|
|
53182
|
+
backgroundColor: theme2.colors.primary,
|
|
53183
|
+
color: "#fff",
|
|
53184
|
+
cursor: isSaving ? "wait" : "pointer",
|
|
53185
|
+
opacity: isSaving ? 0.7 : 1
|
|
53186
|
+
},
|
|
53187
|
+
children: [
|
|
53188
|
+
isSaving && /* @__PURE__ */ jsx(LoaderCircle, { size: 16, style: { animation: "spin 1s linear infinite" } }),
|
|
53189
|
+
isEditing ? "Save Changes" : "Create Milestone"
|
|
53190
|
+
]
|
|
53191
|
+
}
|
|
53192
|
+
)
|
|
53193
|
+
]
|
|
53194
|
+
}
|
|
53195
|
+
)
|
|
53196
|
+
] })
|
|
53197
|
+
]
|
|
53198
|
+
}
|
|
53199
|
+
),
|
|
53200
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
53201
|
+
@keyframes spin {
|
|
53202
|
+
from { transform: rotate(0deg); }
|
|
53203
|
+
to { transform: rotate(360deg); }
|
|
53204
|
+
}
|
|
53205
|
+
` })
|
|
53206
|
+
]
|
|
53207
|
+
}
|
|
53208
|
+
);
|
|
53209
|
+
if (typeof document === "undefined") return null;
|
|
53210
|
+
return createPortal(modalContent, document.body);
|
|
53211
|
+
};
|
|
52140
53212
|
const MilestonePanelContent = ({
|
|
52141
53213
|
context,
|
|
52142
53214
|
actions,
|
|
@@ -52144,13 +53216,17 @@ const MilestonePanelContent = ({
|
|
|
52144
53216
|
}) => {
|
|
52145
53217
|
const { theme: theme2 } = useTheme();
|
|
52146
53218
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
53219
|
+
const [isMilestoneModalOpen, setIsMilestoneModalOpen] = useState(false);
|
|
53220
|
+
const [editingMilestone, setEditingMilestone] = useState(void 0);
|
|
52147
53221
|
const {
|
|
52148
53222
|
milestones,
|
|
52149
53223
|
isLoading,
|
|
52150
53224
|
error,
|
|
52151
53225
|
isBacklogProject,
|
|
52152
53226
|
toggleMilestone,
|
|
52153
|
-
refreshData
|
|
53227
|
+
refreshData,
|
|
53228
|
+
canWrite,
|
|
53229
|
+
core: core2
|
|
52154
53230
|
} = useMilestoneData({
|
|
52155
53231
|
context,
|
|
52156
53232
|
actions
|
|
@@ -52173,6 +53249,29 @@ const MilestonePanelContent = ({
|
|
|
52173
53249
|
setIsRefreshing(false);
|
|
52174
53250
|
}
|
|
52175
53251
|
};
|
|
53252
|
+
const handleOpenNewMilestone = useCallback(() => {
|
|
53253
|
+
setEditingMilestone(void 0);
|
|
53254
|
+
setIsMilestoneModalOpen(true);
|
|
53255
|
+
}, []);
|
|
53256
|
+
useCallback((milestone) => {
|
|
53257
|
+
setEditingMilestone(milestone);
|
|
53258
|
+
setIsMilestoneModalOpen(true);
|
|
53259
|
+
}, []);
|
|
53260
|
+
const handleCloseMilestoneModal = useCallback(() => {
|
|
53261
|
+
setIsMilestoneModalOpen(false);
|
|
53262
|
+
setEditingMilestone(void 0);
|
|
53263
|
+
}, []);
|
|
53264
|
+
const handleSaveMilestone = useCallback(async (input) => {
|
|
53265
|
+
if (!core2) {
|
|
53266
|
+
throw new Error("Backlog not loaded");
|
|
53267
|
+
}
|
|
53268
|
+
if (editingMilestone) {
|
|
53269
|
+
await core2.updateMilestone(editingMilestone.id, input);
|
|
53270
|
+
} else {
|
|
53271
|
+
await core2.createMilestone(input);
|
|
53272
|
+
}
|
|
53273
|
+
await refreshData();
|
|
53274
|
+
}, [core2, editingMilestone, refreshData]);
|
|
52176
53275
|
const totalMilestones = milestones.length;
|
|
52177
53276
|
const totalTasks = milestones.reduce((sum, m) => sum + m.milestone.tasks.length, 0);
|
|
52178
53277
|
return /* @__PURE__ */ jsxs(
|
|
@@ -52239,6 +53338,30 @@ const MilestonePanelContent = ({
|
|
|
52239
53338
|
]
|
|
52240
53339
|
}
|
|
52241
53340
|
),
|
|
53341
|
+
canWrite && /* @__PURE__ */ jsxs(
|
|
53342
|
+
"button",
|
|
53343
|
+
{
|
|
53344
|
+
onClick: handleOpenNewMilestone,
|
|
53345
|
+
style: {
|
|
53346
|
+
display: "flex",
|
|
53347
|
+
alignItems: "center",
|
|
53348
|
+
gap: "6px",
|
|
53349
|
+
background: theme2.colors.primary,
|
|
53350
|
+
color: theme2.colors.background,
|
|
53351
|
+
border: "none",
|
|
53352
|
+
borderRadius: theme2.radii[2],
|
|
53353
|
+
padding: "6px 12px",
|
|
53354
|
+
fontSize: theme2.fontSizes[1],
|
|
53355
|
+
fontWeight: theme2.fontWeights.medium,
|
|
53356
|
+
cursor: "pointer",
|
|
53357
|
+
transition: "opacity 0.2s ease"
|
|
53358
|
+
},
|
|
53359
|
+
children: [
|
|
53360
|
+
/* @__PURE__ */ jsx(Plus, { size: 14 }),
|
|
53361
|
+
"Add Milestone"
|
|
53362
|
+
]
|
|
53363
|
+
}
|
|
53364
|
+
),
|
|
52242
53365
|
/* @__PURE__ */ jsx(
|
|
52243
53366
|
"button",
|
|
52244
53367
|
{
|
|
@@ -52373,7 +53496,16 @@ const MilestonePanelContent = ({
|
|
|
52373
53496
|
@keyframes spin {
|
|
52374
53497
|
to { transform: rotate(360deg); }
|
|
52375
53498
|
}
|
|
52376
|
-
` })
|
|
53499
|
+
` }),
|
|
53500
|
+
/* @__PURE__ */ jsx(
|
|
53501
|
+
MilestoneModal,
|
|
53502
|
+
{
|
|
53503
|
+
isOpen: isMilestoneModalOpen,
|
|
53504
|
+
onClose: handleCloseMilestoneModal,
|
|
53505
|
+
onSave: handleSaveMilestone,
|
|
53506
|
+
milestone: editingMilestone
|
|
53507
|
+
}
|
|
53508
|
+
)
|
|
52377
53509
|
]
|
|
52378
53510
|
}
|
|
52379
53511
|
);
|