task_receipts/server/src/yaml-service.ts

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();
}
}