feat: part of project rules, models and basic rendering

This commit is contained in:
Al0cam 2025-10-27 06:59:03 +01:00
parent a97fa797b4
commit ff721f4811
5 changed files with 128 additions and 0 deletions

31
Models/ProjectRule.ts Normal file
View file

@ -0,0 +1,31 @@
import { MovingRule } from "./MovingRule";
/**
* Project rules for defining how files should be moved inside project folders
*/
export class ProjectRule {
/**
* The name of the project this rule belongs to
* e.g. "Project A"
* e.g. "Book collection"
* e.g. "Music albums 2025"
*/
public projectName: string;
/**
* Project destination folder
* e.g. "Projects/Project A"
* e.g. "Projects/Project B/
*/
public folder: string;
/**
* Rules for moving files inside the project folder
*/
public rules: Array<MovingRule>;
public collapsed: boolean;
constructor(projectName?: string, folder?: string, rules?: Array<MovingRule>, collapsed?: boolean) {
this.projectName = projectName || "";
this.folder = folder || "";
this.rules = rules || [];
this.collapsed = collapsed || false;
}
}

View file

@ -206,3 +206,9 @@ Thank you!
- [ ] Add undo button to the notification popup for the moved files
- [x] Add collapse/expand all rules button
- [x] Add Project moving rules
- [x] Project name and destination path
- [x] Subfield that contain the moving rules for the project
- [ ] Add project rules UI
- [ ] Project rules business logic

View file

@ -0,0 +1,84 @@
import { MovingRule } from "Models/MovingRule";
import * as obsidian from "obsidian";
import type AutoMoverPlugin from "main";
import { ProjectRule } from "Models/ProjectRule";
export function projectSection(containerEl: HTMLElement, plugin: AutoMoverPlugin, display: () => void) {
/**
* Header for excluded folders
*/
const projectRuleContainer = containerEl.createDiv({
cls: "moving_rules_container",
});
// Class used from obdsidian's css for consistency
const projectRuleDetails = projectRuleContainer.createEl("details", {});
projectRuleDetails.createEl("summary", { text: "Project rules", cls: ["setting-item-heading"] });
projectRuleDetails.open = !plugin.settings.collapseSections.projectRules;
projectRuleDetails.addEventListener("toggle", async () => {
plugin.settings.collapseSections.projectRules = !projectRuleDetails.open;
await plugin.saveData(plugin.settings);
});
const projectList = projectRuleDetails.createDiv({
cls: "rule_list",
});
const projectHeader = projectList.createDiv({
cls: "rule margig_right",
});
projectHeader.createEl("p", {
text: "Project search criteria (string or regex)",
cls: "rule_title",
});
const addProjectButton = projectHeader.createEl("button", {
text: "+",
cls: "rule_button",
});
addProjectButton.addEventListener("click", () => {
plugin.settings.projectRules.push(new ProjectRule());
display();
});
/**
* List of project rules
*/
for (const project of plugin.settings.projectRules) {
const child = projectList.createDiv({ cls: "rule" });
child.createEl("input", {
value: project.projectName,
cls: "rule_input",
}).onchange = (e) => {
project.projectName = (e.target as HTMLInputElement).value;
plugin.settings.projectRules.map((r) => (r === project ? project : r));
plugin.saveData(plugin.settings);
};
child.createEl("input", {
value: project.folder,
cls: "rule_input",
}).onchange = (e) => {
project.folder = (e.target as HTMLInputElement).value;
plugin.settings.projectRules.map((r) => (r === project ? project : r));
plugin.saveData(plugin.settings);
};
const duplicateRuleButton = child.createEl("button", {
text: "⿻",
cls: "rule_button rule_button_duplicate",
});
duplicateRuleButton.addEventListener("click", () => {
plugin.settings.projectRules.push(new ProjectRule(project.projectName, project.folder));
display();
});
const deleteRuleButton = child.createEl("button", {
text: "x",
cls: "rule_button rule_button_remove",
});
deleteRuleButton.addEventListener("click", () => {
plugin.settings.projectRules = plugin.settings.projectRules.filter((r) => r !== project);
display();
});
}
}

View file

@ -1,6 +1,7 @@
import type AutoMoverPlugin from "main";
import type { ExclusionRule } from "Models/ExclusionRule";
import type { MovingRule } from "Models/MovingRule";
import { ProjectRule } from "Models/ProjectRule";
export interface AutoMoverSettings {
moveOnOpen: boolean;
@ -8,6 +9,7 @@ export interface AutoMoverSettings {
movingRules: MovingRule[];
exclusionRules: ExclusionRule[];
tagRules: MovingRule[];
projectRules: ProjectRule[];
automaticMoving: boolean;
timer: number | null; // in miliseconds
collapseSections: {
@ -15,6 +17,7 @@ export interface AutoMoverSettings {
movingRules: boolean;
exclusionRules: boolean;
tagRules: boolean;
projectRules: boolean;
};
}
@ -24,6 +27,7 @@ export const DEFAULT_SETTINGS: Partial<AutoMoverSettings> = {
movingRules: [],
exclusionRules: [],
tagRules: [],
projectRules: [],
automaticMoving: false,
timer: null,
collapseSections: {
@ -31,6 +35,7 @@ export const DEFAULT_SETTINGS: Partial<AutoMoverSettings> = {
movingRules: false,
exclusionRules: false,
tagRules: false,
projectRules: false,
},
};

View file

@ -6,6 +6,7 @@ import { exclusionSection } from "./ExclusionSection";
import movingRuleSection from "./MovingRuleSection";
import { tagSection } from "./TagSection";
import { groupCollapsed } from "console";
import { projectSection } from "./ProjectSection";
export class SettingsTab extends PluginSettingTab {
plugin: AutoMoverPlugin;
@ -159,5 +160,6 @@ export class SettingsTab extends PluginSettingTab {
movingRuleSection(containerEl, this.plugin, this.display);
tagSection(containerEl, this.plugin, this.display);
exclusionSection(containerEl, this.plugin, this.display);
projectSection(containerEl, this.plugin, this.display);
};
}