Skip to content

Commit f4f110a

Browse files
authored
Merge pull request #28 from asepindrak/dev
Dev
2 parents c3c8a6a + b2feea4 commit f4f110a

4 files changed

Lines changed: 62 additions & 59 deletions

File tree

.changeset/major-rockets-study.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"commitflow": patch
3+
---
4+
5+
fix: export & import task

frontend/package-lock.json

Lines changed: 1 addition & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/components/ExportImportControls.tsx

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,23 @@
22
import React, { useRef, useState } from "react";
33
import * as XLSX from "xlsx";
44
import { toast } from "react-toastify";
5-
import { Download, Loader2, Save, UploadCloud } from "lucide-react";
5+
import { Download, Loader2, UploadCloud } from "lucide-react";
66
import type { Project, Task, TeamMember } from "../types";
77
import {
88
findDataUrisInHtml,
99
replaceDataUrisInCommentsAndUpload,
1010
replaceDataUrisInHtmlAndUpload,
1111
} from "../utils/dataURItoFile";
12+
import { useStoreWorkspace } from "../utils/store";
1213

1314
/**
1415
* ExportImportControls (per-project)
1516
*
1617
* Props:
17-
* - projects: Project[] (used only to resolve project -> workspaceId if selectedProjectId provided)
18+
* - projects: Project[] (used only to resolve project -> workspaceId if projectId provided)
1819
* - tasks: Task[]
1920
* - team: TeamMember[]
20-
* - selectedProjectId?: string // when provided, export only tasks for this project (and related members)
21+
* - projectId?: string // when provided, export only tasks for this project (and related members)
2122
* - onImport: (payload: { tasks?: Task[]; team?: TeamMember[] }) => void
2223
*
2324
* Exports sheets:
@@ -31,18 +32,18 @@ export default function ExportImportControls({
3132
projects,
3233
tasks,
3334
team,
34-
selectedProjectId,
3535
onImport,
3636
}: {
3737
projects?: Project[];
3838
tasks: Task[];
3939
team: TeamMember[];
40-
selectedProjectId?: string;
4140
onImport: (payload: { tasks?: Task[]; team?: TeamMember[] }) => void;
4241
}) {
4342
const fileRef = useRef<HTMLInputElement | null>(null);
4443
const [isLoading, setIsLoading] = useState<boolean>(false);
4544

45+
const { workspaceId, projectId } = useStoreWorkspace();
46+
4647
const safeString = (v: any) =>
4748
v === null || typeof v === "undefined" ? "" : String(v);
4849
const tryParseJSON = (s: string) => {
@@ -55,7 +56,15 @@ export default function ExportImportControls({
5556

5657
async function exportXlsx() {
5758
try {
59+
if (!projectId) {
60+
61+
toast.dark(
62+
`Warning: Failed export task. Project ID not found!`
63+
);
64+
return
65+
}
5866
setIsLoading(true);
67+
5968
const MAX_EXCEL_CELL = 32767; // Excel limit for a single cell
6069
const truncations: string[] = [];
6170

@@ -71,8 +80,8 @@ export default function ExportImportControls({
7180
};
7281

7382
// Determine tasks to export (per-project if selected)
74-
const filteredTasks = selectedProjectId
75-
? tasks.filter((t) => t.projectId === selectedProjectId)
83+
const filteredTasks = projectId
84+
? tasks.filter((t) => t.projectId === projectId)
7685
: tasks.slice();
7786

7887
// ---------------------------
@@ -101,8 +110,7 @@ export default function ExportImportControls({
101110
err
102111
);
103112
toast.dark(
104-
`Warning: failed uploading embedded files for comments on task ${
105-
t.id ?? ""
113+
`Warning: failed uploading embedded files for comments on task ${t.id ?? ""
106114
}`
107115
);
108116
}
@@ -144,8 +152,7 @@ export default function ExportImportControls({
144152
err
145153
);
146154
toast.dark(
147-
`Warning: failed uploading embedded files for description on task ${
148-
t.id ?? ""
155+
`Warning: failed uploading embedded files for description on task ${t.id ?? ""
149156
}`
150157
);
151158
// keep original description if upload fails (don't block export)
@@ -160,7 +167,7 @@ export default function ExportImportControls({
160167
}
161168

162169
// Try to find project's workspaceId for broader team inclusion (optional)
163-
const project = projects?.find((p) => p.id === selectedProjectId);
170+
const project = projects?.find((p) => p.id === projectId);
164171
const projectWorkspaceId = project?.workspaceId;
165172

166173
// Build a map for quick lookup of member email by id
@@ -174,7 +181,7 @@ export default function ExportImportControls({
174181
if (assigneeIds.size > 0 && assigneeIds.has(m.id)) return true;
175182
if (projectWorkspaceId && m.workspaceId === projectWorkspaceId)
176183
return true;
177-
return !selectedProjectId;
184+
return !projectId;
178185
})
179186
.map((m) => ({
180187
id: truncateForExcel(m.id ?? "", `team.id:${m.id ?? ""}`),
@@ -292,7 +299,7 @@ export default function ExportImportControls({
292299
"team"
293300
);
294301

295-
const projectTag = selectedProjectId ? `_${selectedProjectId}` : "";
302+
const projectTag = projectId ? `_${projectId}` : "";
296303
const filename = `commitflow_export${projectTag}_${new Date()
297304
.toISOString()
298305
.slice(0, 10)}.xlsx`;
@@ -324,6 +331,15 @@ export default function ExportImportControls({
324331
function onFileChange(e: React.ChangeEvent<HTMLInputElement>) {
325332
const f = e.target.files?.[0];
326333
if (!f) return;
334+
335+
if (!projectId) {
336+
337+
toast.dark(
338+
`Warning: Failed import task. Project ID not found!`
339+
);
340+
return
341+
}
342+
327343
setIsLoading(true);
328344
const reader = new FileReader();
329345
reader.onload = async (ev) => {

frontend/src/components/ProjectManagement.tsx

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,14 +1498,14 @@ export default function ProjectManagement({
14981498
(updated as any).startDate == null
14991499
? null
15001500
: (updated as any).startDate instanceof Date
1501-
? (updated as any).startDate.toISOString()
1502-
: String((updated as any).startDate),
1501+
? (updated as any).startDate.toISOString()
1502+
: String((updated as any).startDate),
15031503
dueDate:
15041504
(updated as any).dueDate == null
15051505
? null
15061506
: (updated as any).dueDate instanceof Date
1507-
? (updated as any).dueDate.toISOString()
1508-
: String((updated as any).dueDate),
1507+
? (updated as any).dueDate.toISOString()
1508+
: String((updated as any).dueDate),
15091509
},
15101510
};
15111511

@@ -1545,17 +1545,17 @@ export default function ProjectManagement({
15451545
(updated as any).startDate === null
15461546
? null
15471547
: (updated as any).startDate instanceof Date
1548-
? (updated as any).startDate.toISOString()
1549-
: String((updated as any).startDate);
1548+
? (updated as any).startDate.toISOString()
1549+
: String((updated as any).startDate);
15501550
}
15511551

15521552
if (typeof (updated as any).dueDate !== "undefined") {
15531553
patch.dueDate =
15541554
(updated as any).dueDate === null
15551555
? null
15561556
: (updated as any).dueDate instanceof Date
1557-
? (updated as any).dueDate.toISOString()
1558-
: String((updated as any).dueDate);
1557+
? (updated as any).dueDate.toISOString()
1558+
: String((updated as any).dueDate);
15591559
}
15601560

15611561
// include comments when provided (array|null)
@@ -1624,13 +1624,13 @@ export default function ProjectManagement({
16241624
setSelectedTask((cur) =>
16251625
cur && nid(cur.id) === nid(updated.id)
16261626
? {
1627-
...cur,
1628-
...result,
1629-
comments:
1630-
result && typeof result.comments !== "undefined"
1631-
? result.comments
1632-
: cur.comments,
1633-
}
1627+
...cur,
1628+
...result,
1629+
comments:
1630+
result && typeof result.comments !== "undefined"
1631+
? result.comments
1632+
: cur.comments,
1633+
}
16341634
: cur
16351635
);
16361636
} catch (err) {
@@ -2389,11 +2389,10 @@ export default function ProjectManagement({
23892389
group relative inline-flex items-center gap-2 px-5 py-2.5
23902390
rounded-2xl text-sm font-semibold backdrop-blur-md
23912391
transition-all duration-300
2392-
${
2393-
syncing
2394-
? "bg-emerald-500/20 text-emerald-400 border border-emerald-500/30"
2395-
: "bg-white/10 dark:bg-white/5 hover:bg-white/20 dark:hover:bg-white/10 border border-white/20 dark:border-white/10"
2396-
}
2392+
${syncing
2393+
? "bg-emerald-500/20 text-emerald-400 border border-emerald-500/30"
2394+
: "bg-white/10 dark:bg-white/5 hover:bg-white/20 dark:hover:bg-white/10 border border-white/20 dark:border-white/10"
2395+
}
23972396
shadow-[0_4px_12px_rgba(0,0,0,0.1)]
23982397
hover:shadow-[0_6px_16px_rgba(0,0,0,0.15)]
23992398
active:scale-95
@@ -2402,11 +2401,10 @@ export default function ProjectManagement({
24022401
{/* spinning icon */}
24032402
<RefreshCw
24042403
size={18}
2405-
className={`transition-transform ${
2406-
syncing
2407-
? "animate-spin text-emerald-400"
2408-
: "group-hover:rotate-180 text-gray-700 dark:text-white/80"
2409-
}`}
2404+
className={`transition-transform ${syncing
2405+
? "animate-spin text-emerald-400"
2406+
: "group-hover:rotate-180 text-gray-700 dark:text-white/80"
2407+
}`}
24102408
/>
24112409

24122410
{/* label */}
@@ -2647,9 +2645,9 @@ export default function ProjectManagement({
26472645
const next = prev.map((t) =>
26482646
nid(t.id) === nid(taskId)
26492647
? {
2650-
...t,
2651-
comments: [tmpComment, ...(t.comments || [])],
2652-
}
2648+
...t,
2649+
comments: [tmpComment, ...(t.comments || [])],
2650+
}
26532651
: t
26542652
);
26552653

0 commit comments

Comments
 (0)