Skip to content

Commit 2d14142

Browse files
authored
Merge pull request #8 from LonoxX/feature/custom-folder
feat: add custom folder settings for issues and pull requests #6
2 parents 075723d + 40a547a commit 2d14142

5 files changed

Lines changed: 388 additions & 119 deletions

File tree

src/file-manager.ts

Lines changed: 104 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ export class FileManager {
175175

176176
const repoCleaned = repoName.replace(/\//g, "-");
177177
const ownerCleaned = owner.replace(/\//g, "-");
178-
const issueFolder = `${repo.issueFolder}/${ownerCleaned}/${repoCleaned}`;
179-
const pullRequestFolder = `${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}`;
178+
const issueFolder = this.getIssueFolderPath(repo, ownerCleaned, repoCleaned);
179+
const pullRequestFolder = this.getPullRequestFolderPath(repo, ownerCleaned, repoCleaned);
180180

181181
await this.cleanupEmptyIssueFolder(
182182
repo,
@@ -196,24 +196,41 @@ export class FileManager {
196196

197197
// ----- Private helper methods -----
198198

199+
/**
200+
* Get the issue folder path for a repository
201+
*/
202+
private getIssueFolderPath(repo: RepositoryTracking, ownerCleaned: string, repoCleaned: string): string {
203+
if (repo.useCustomIssueFolder && repo.customIssueFolder && repo.customIssueFolder.trim()) {
204+
return repo.customIssueFolder.trim();
205+
}
206+
return `${repo.issueFolder}/${ownerCleaned}/${repoCleaned}`;
207+
}
208+
209+
/**
210+
* Get the pull request folder path for a repository
211+
*/
212+
private getPullRequestFolderPath(repo: RepositoryTracking, ownerCleaned: string, repoCleaned: string): string {
213+
if (repo.useCustomPullRequestFolder && repo.customPullRequestFolder && repo.customPullRequestFolder.trim()) {
214+
return repo.customPullRequestFolder.trim();
215+
}
216+
return `${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}`;
217+
}
218+
199219
private async cleanupDeletedIssues(
200220
repo: RepositoryTracking,
201221
ownerCleaned: string,
202222
repoCleaned: string,
203223
allIssuesIncludingRecentlyClosed: any[],
204224
): Promise<void> {
205-
const repoFolder = this.app.vault.getAbstractFileByPath(
206-
`${repo.issueFolder}/${ownerCleaned}/${repoCleaned}`,
207-
);
225+
const issueFolderPath = this.getIssueFolderPath(repo, ownerCleaned, repoCleaned);
226+
const repoFolder = this.app.vault.getAbstractFileByPath(issueFolderPath);
208227

209228
if (repoFolder) {
210229
const files = this.app.vault
211230
.getFiles()
212231
.filter(
213232
(file) =>
214-
file.path.startsWith(
215-
`${repo.issueFolder}/${ownerCleaned}/${repoCleaned}/`,
216-
) && file.extension === "md",
233+
file.path.startsWith(`${issueFolderPath}/`) && file.extension === "md",
217234
);
218235

219236
for (const file of files) {
@@ -263,18 +280,15 @@ export class FileManager {
263280
repoCleaned: string,
264281
allPullRequestsIncludingRecentlyClosed: any[],
265282
): Promise<void> {
266-
const repoFolder = this.app.vault.getAbstractFileByPath(
267-
`${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}`,
268-
);
283+
const pullRequestFolderPath = this.getPullRequestFolderPath(repo, ownerCleaned, repoCleaned);
284+
const repoFolder = this.app.vault.getAbstractFileByPath(pullRequestFolderPath);
269285

270286
if (repoFolder) {
271287
const files = this.app.vault
272288
.getFiles()
273289
.filter(
274290
(file) =>
275-
file.path.startsWith(
276-
`${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}/`,
277-
) && file.extension === "md",
291+
file.path.startsWith(`${pullRequestFolderPath}/`) && file.extension === "md",
278292
);
279293

280294
for (const file of files) {
@@ -323,15 +337,20 @@ export class FileManager {
323337
issue: any,
324338
): Promise<void> {
325339
const fileName = `Issue - ${issue.number}.md`;
326-
await this.ensureFolderExists(repo.issueFolder);
327-
await this.ensureFolderExists(`${repo.issueFolder}/${ownerCleaned}`);
328-
await this.ensureFolderExists(
329-
`${repo.issueFolder}/${ownerCleaned}/${repoCleaned}`,
330-
);
340+
const issueFolderPath = this.getIssueFolderPath(repo, ownerCleaned, repoCleaned);
331341

332-
const file = this.app.vault.getAbstractFileByPath(
333-
`${repo.issueFolder}/${ownerCleaned}/${repoCleaned}/${fileName}`,
334-
);
342+
// Ensure folder structure exists
343+
if (repo.useCustomIssueFolder && repo.customIssueFolder && repo.customIssueFolder.trim()) {
344+
// For custom folders, just ensure the custom path exists
345+
await this.ensureFolderExists(repo.customIssueFolder.trim());
346+
} else {
347+
// For default structure, ensure nested path exists
348+
await this.ensureFolderExists(repo.issueFolder);
349+
await this.ensureFolderExists(`${repo.issueFolder}/${ownerCleaned}`);
350+
await this.ensureFolderExists(`${repo.issueFolder}/${ownerCleaned}/${repoCleaned}`);
351+
}
352+
353+
const file = this.app.vault.getAbstractFileByPath(`${issueFolderPath}/${fileName}`);
335354

336355
const [owner, repoName] = repo.repository.split("/");
337356

@@ -407,10 +426,7 @@ export class FileManager {
407426
}
408427
}
409428
} else {
410-
await this.app.vault.create(
411-
`${repo.issueFolder}/${ownerCleaned}/${repoCleaned}/${fileName}`,
412-
content,
413-
);
429+
await this.app.vault.create(`${issueFolderPath}/${fileName}`, content);
414430
this.noticeManager.debug(`Created issue file for ${issue.number}`);
415431
}
416432
}
@@ -422,18 +438,20 @@ export class FileManager {
422438
pr: any,
423439
): Promise<void> {
424440
const fileName = `Pull Request - ${pr.number}.md`;
441+
const pullRequestFolderPath = this.getPullRequestFolderPath(repo, ownerCleaned, repoCleaned);
425442

426-
await this.ensureFolderExists(repo.pullRequestFolder);
427-
await this.ensureFolderExists(
428-
`${repo.pullRequestFolder}/${ownerCleaned}`,
429-
);
430-
await this.ensureFolderExists(
431-
`${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}`,
432-
);
443+
// Ensure folder structure exists
444+
if (repo.useCustomPullRequestFolder && repo.customPullRequestFolder && repo.customPullRequestFolder.trim()) {
445+
// For custom folders, just ensure the custom path exists
446+
await this.ensureFolderExists(repo.customPullRequestFolder.trim());
447+
} else {
448+
// For default structure, ensure nested path exists
449+
await this.ensureFolderExists(repo.pullRequestFolder);
450+
await this.ensureFolderExists(`${repo.pullRequestFolder}/${ownerCleaned}`);
451+
await this.ensureFolderExists(`${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}`);
452+
}
433453

434-
const file = this.app.vault.getAbstractFileByPath(
435-
`${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}/${fileName}`,
436-
);
454+
const file = this.app.vault.getAbstractFileByPath(`${pullRequestFolderPath}/${fileName}`);
437455

438456
const [owner, repoName] = repo.repository.split("/");
439457

@@ -509,10 +527,7 @@ export class FileManager {
509527
}
510528
}
511529
} else {
512-
await this.app.vault.create(
513-
`${repo.pullRequestFolder}/${ownerCleaned}/${repoCleaned}/${fileName}`,
514-
content,
515-
);
530+
await this.app.vault.create(`${pullRequestFolderPath}/${fileName}`, content);
516531
this.noticeManager.debug(`Created PR file for ${pr.number}`);
517532
}
518533
}
@@ -643,28 +658,31 @@ ${this.formatComments(comments, this.settings.escapeMode)}
643658
}
644659
}
645660

646-
if (files.length === 0) {
647-
this.noticeManager.info(
648-
`Deleting empty folder: ${issueFolder}`,
649-
);
650-
const folder =
651-
this.app.vault.getAbstractFileByPath(issueFolder);
652-
if (folder instanceof TFolder && folder.children.length === 0) {
653-
await this.app.fileManager.trashFile(folder);
654-
}
655-
}
656-
657-
const issueOwnerFolder = this.app.vault.getAbstractFileByPath(
658-
`${repo.issueFolder}/${ownerCleaned}`,
659-
);
660-
661-
if (issueOwnerFolder instanceof TFolder) {
662-
const files = issueOwnerFolder.children;
661+
// Only cleanup nested folder structure if not using custom folder
662+
if (!repo.useCustomIssueFolder || !repo.customIssueFolder || !repo.customIssueFolder.trim()) {
663663
if (files.length === 0) {
664664
this.noticeManager.info(
665-
`Deleting empty folder: ${issueOwnerFolder.path}`,
665+
`Deleting empty folder: ${issueFolder}`,
666666
);
667-
await this.app.fileManager.trashFile(issueOwnerFolder);
667+
const folder =
668+
this.app.vault.getAbstractFileByPath(issueFolder);
669+
if (folder instanceof TFolder && folder.children.length === 0) {
670+
await this.app.fileManager.trashFile(folder);
671+
}
672+
}
673+
674+
const issueOwnerFolder = this.app.vault.getAbstractFileByPath(
675+
`${repo.issueFolder}/${ownerCleaned}`,
676+
);
677+
678+
if (issueOwnerFolder instanceof TFolder) {
679+
const files = issueOwnerFolder.children;
680+
if (files.length === 0) {
681+
this.noticeManager.info(
682+
`Deleting empty folder: ${issueOwnerFolder.path}`,
683+
);
684+
await this.app.fileManager.trashFile(issueOwnerFolder);
685+
}
668686
}
669687
}
670688
}
@@ -703,38 +721,40 @@ ${this.formatComments(comments, this.settings.escapeMode)}
703721
}
704722
}
705723

706-
if (files.length === 0) {
707-
this.noticeManager.info(
708-
`Deleting empty folder: ${pullRequestFolder}`,
709-
);
710-
const folder =
711-
this.app.vault.getAbstractFileByPath(pullRequestFolder);
712-
if (folder instanceof TFolder && folder.children.length === 0) {
713-
await this.app.fileManager.trashFile(folder);
714-
}
715-
}
716-
717-
const pullRequestOwnerFolder = this.app.vault.getAbstractFileByPath(
718-
`${repo.pullRequestFolder}/${ownerCleaned}`,
719-
);
720-
721-
if (pullRequestOwnerFolder instanceof TFolder) {
722-
const files = pullRequestOwnerFolder.children;
724+
// Only cleanup nested folder structure if not using custom folder
725+
if (!repo.useCustomPullRequestFolder || !repo.customPullRequestFolder || !repo.customPullRequestFolder.trim()) {
723726
if (files.length === 0) {
724727
this.noticeManager.info(
725-
`Deleting empty folder: ${pullRequestOwnerFolder.path}`,
726-
);
727-
await this.app.fileManager.trashFile(
728-
pullRequestOwnerFolder,
728+
`Deleting empty folder: ${pullRequestFolder}`,
729729
);
730+
const folder =
731+
this.app.vault.getAbstractFileByPath(pullRequestFolder);
732+
if (folder instanceof TFolder && folder.children.length === 0) {
733+
await this.app.fileManager.trashFile(folder);
734+
}
735+
}
736+
737+
const pullRequestOwnerFolder = this.app.vault.getAbstractFileByPath(
738+
`${repo.pullRequestFolder}/${ownerCleaned}`,
739+
);
740+
741+
if (pullRequestOwnerFolder instanceof TFolder) {
742+
const files = pullRequestOwnerFolder.children;
743+
if (files.length === 0) {
744+
this.noticeManager.info(
745+
`Deleting empty folder: ${pullRequestOwnerFolder.path}`,
746+
);
747+
await this.app.fileManager.trashFile(
748+
pullRequestOwnerFolder,
749+
);
750+
}
730751
}
731752
}
732753
}
733754
}
734755

735-
/**
736-
* Format comments section for issues and pull requests
737-
*/
756+
// Format comments section for issues and pull requests
757+
738758
private formatComments(
739759
comments: any[],
740760
escapeMode: "disabled" | "normal" | "strict" | "veryStrict",
@@ -744,9 +764,7 @@ ${this.formatComments(comments, this.settings.escapeMode)}
744764
}
745765

746766
comments.sort(
747-
(a, b) =>
748-
new Date(a.created_at).getTime() -
749-
new Date(b.created_at).getTime(),
767+
(a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime(),
750768
);
751769

752770
let commentSection = "\n## Comments\n\n";

src/main.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,10 @@ export default class GitHubTrackerPlugin extends Plugin {
255255
const loadedData = await this.loadData();
256256
this.settings = Object.assign({}, DEFAULT_SETTINGS, loadedData);
257257

258-
// Migrate existing repositories to include new label filter properties
259-
this.settings.repositories = this.settings.repositories.map(repo =>
260-
Object.assign({}, DEFAULT_REPOSITORY_TRACKING, repo)
261-
);
258+
// Migrate existing repositories to include new custom folder properties
259+
this.settings.repositories = this.settings.repositories.map(repo => {
260+
return Object.assign({}, DEFAULT_REPOSITORY_TRACKING, repo);
261+
});
262262
}
263263

264264
async saveSettings() {

0 commit comments

Comments
 (0)