187 lines
4.8 KiB
TypeScript
187 lines
4.8 KiB
TypeScript
import * as yaml from 'js-yaml';
|
|
import { Knex } from 'knex';
|
|
import { GroupRepository, TaskRepository, StepRepository, NoteRepository } from './db/repositories';
|
|
import { Group, Task, Step, Note } from '@shared/index';
|
|
|
|
export interface YamlData {
|
|
groups: YamlGroup[];
|
|
}
|
|
|
|
export interface YamlGroup {
|
|
name: string;
|
|
tasks: YamlTask[];
|
|
}
|
|
|
|
export interface YamlTask {
|
|
name: string;
|
|
steps: YamlStep[];
|
|
notes?: YamlNote[];
|
|
}
|
|
|
|
export interface YamlStep {
|
|
name: string;
|
|
instructions: string;
|
|
notes?: YamlNote[];
|
|
}
|
|
|
|
export interface YamlNote {
|
|
content: string;
|
|
}
|
|
|
|
export class YamlService {
|
|
private groupRepo: GroupRepository;
|
|
private taskRepo: TaskRepository;
|
|
private stepRepo: StepRepository;
|
|
private noteRepo: NoteRepository;
|
|
private db: Knex;
|
|
|
|
constructor(db: Knex) {
|
|
this.db = db;
|
|
this.groupRepo = new GroupRepository(db);
|
|
this.taskRepo = new TaskRepository(db);
|
|
this.stepRepo = new StepRepository(db);
|
|
this.noteRepo = new NoteRepository(db);
|
|
}
|
|
|
|
async exportToYaml(): Promise<string> {
|
|
const groups = await this.groupRepo.findRootGroups();
|
|
const yamlData: YamlData = {
|
|
groups: []
|
|
};
|
|
|
|
for (const group of groups) {
|
|
const yamlGroup = await this.convertGroupToYaml(group);
|
|
yamlData.groups.push(yamlGroup);
|
|
}
|
|
|
|
return yaml.dump(yamlData, {
|
|
indent: 2,
|
|
lineWidth: 120,
|
|
noRefs: true
|
|
});
|
|
}
|
|
|
|
async importFromYaml(yamlContent: string): Promise<void> {
|
|
const yamlData = yaml.load(yamlContent) as YamlData;
|
|
|
|
if (!yamlData || !yamlData.groups) {
|
|
throw new Error('Invalid YAML format: missing groups');
|
|
}
|
|
|
|
// Clear existing data (optional - you might want to make this configurable)
|
|
await this.clearExistingData();
|
|
|
|
// Import groups and their nested data
|
|
for (const yamlGroup of yamlData.groups) {
|
|
await this.importGroup(yamlGroup);
|
|
}
|
|
}
|
|
|
|
private async convertGroupToYaml(group: Group): Promise<YamlGroup> {
|
|
const tasks = await this.taskRepo.findByGroupId(group.id);
|
|
const yamlTasks: YamlTask[] = [];
|
|
|
|
for (const task of tasks) {
|
|
const yamlTask = await this.convertTaskToYaml(task);
|
|
yamlTasks.push(yamlTask);
|
|
}
|
|
|
|
return {
|
|
name: group.name,
|
|
tasks: yamlTasks
|
|
};
|
|
}
|
|
|
|
private async convertTaskToYaml(task: Task): Promise<YamlTask> {
|
|
const steps = await this.stepRepo.findByTaskId(task.id);
|
|
const notes = await this.noteRepo.findByTaskId(task.id);
|
|
|
|
const yamlSteps: YamlStep[] = [];
|
|
for (const step of steps) {
|
|
const stepNotes = await this.noteRepo.findByStepId(step.id);
|
|
const yamlStep: YamlStep = {
|
|
name: step.name,
|
|
instructions: step.instructions,
|
|
notes: stepNotes.map(note => ({ content: note.content }))
|
|
};
|
|
yamlSteps.push(yamlStep);
|
|
}
|
|
|
|
const yamlTask: YamlTask = {
|
|
name: task.name,
|
|
steps: yamlSteps,
|
|
notes: notes.map(note => ({ content: note.content }))
|
|
};
|
|
|
|
return yamlTask;
|
|
}
|
|
|
|
private async importGroup(yamlGroup: YamlGroup): Promise<void> {
|
|
// Create the group
|
|
const group = await this.groupRepo.create({
|
|
name: yamlGroup.name,
|
|
parent_id: undefined
|
|
});
|
|
|
|
// Import tasks for this group
|
|
for (const yamlTask of yamlGroup.tasks) {
|
|
await this.importTask(yamlTask, group.id);
|
|
}
|
|
}
|
|
|
|
private async importTask(yamlTask: YamlTask, groupId: number): Promise<void> {
|
|
// Create the task
|
|
const task = await this.taskRepo.create({
|
|
name: yamlTask.name,
|
|
group_id: groupId,
|
|
print_count: 0
|
|
});
|
|
|
|
// Import task-level notes
|
|
if (yamlTask.notes) {
|
|
for (const yamlNote of yamlTask.notes) {
|
|
await this.noteRepo.create({
|
|
content: yamlNote.content,
|
|
task_id: task.id,
|
|
created_by: 1 // Default user ID
|
|
});
|
|
}
|
|
}
|
|
|
|
// Import steps
|
|
for (let i = 0; i < yamlTask.steps.length; i++) {
|
|
const yamlStep = yamlTask.steps[i];
|
|
await this.importStep(yamlStep, task.id, i + 1);
|
|
}
|
|
}
|
|
|
|
private async importStep(yamlStep: YamlStep, taskId: number, order: number): Promise<void> {
|
|
// Create the step
|
|
const step = await this.stepRepo.create({
|
|
name: yamlStep.name,
|
|
instructions: yamlStep.instructions,
|
|
task_id: taskId,
|
|
order: order,
|
|
print_count: 0
|
|
});
|
|
|
|
// Import step-level notes
|
|
if (yamlStep.notes) {
|
|
for (const yamlNote of yamlStep.notes) {
|
|
await this.noteRepo.create({
|
|
content: yamlNote.content,
|
|
step_id: step.id,
|
|
created_by: 1 // Default user ID
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
private async clearExistingData(): Promise<void> {
|
|
// Delete in reverse order to respect foreign key constraints
|
|
await this.db('notes').del();
|
|
await this.db('steps').del();
|
|
await this.db('tasks').del();
|
|
await this.db('groups').del();
|
|
}
|
|
} |