clean up formatting

This commit is contained in:
Sean Sube 2025-06-14 20:49:56 -05:00
parent b949d4a6c6
commit 66d89adfd0
No known key found for this signature in database
GPG Key ID: 3EED7B957D362AF1
7 changed files with 124 additions and 24 deletions

View File

@ -3,6 +3,7 @@ import { Knex } from 'knex';
export abstract class BaseRepository<T extends { created_at?: Date; updated_at?: Date }> {
protected tableName: string;
protected db: Knex;
protected items: T[] = [];
constructor(db: Knex, tableName: string) {
this.db = db;

View File

@ -1,9 +1,9 @@
import { PrintHistory, Step } from '@shared/index';
import { PrintHistory, Step, Task } from '@shared/index';
import { Knex } from 'knex';
import { BaseRepository } from './base-repository';
export class InMemoryRepository<T extends { id: number; created_at?: Date; updated_at?: Date }> extends BaseRepository<T> {
private items: T[] = [];
protected items: T[] = [];
private nextId = 1;
constructor(db: Knex, tableName: string) {
@ -76,4 +76,15 @@ export class InMemoryStepRepository extends InMemoryRepository<Step> {
last_printed_at: new Date(),
});
}
async findTaskById(stepId: number): Promise<Task | undefined> {
const step = this.items.find(s => s.id === stepId);
return step ? { id: step.task_id, name: 'Test Task', group_id: 1, print_count: 0, created_at: new Date(), updated_at: new Date() } : undefined;
}
async findStepNumber(stepId: number): Promise<number> {
const step = this.items.find(s => s.id === stepId);
if (!step) return 0;
return this.items.filter(s => s.task_id === step.task_id).findIndex(s => s.id === stepId) + 1;
}
}

View File

@ -1,6 +1,6 @@
import { Knex } from 'knex';
import { BaseRepository } from './base-repository';
import { Step } from '@shared/index';
import { Step, Task } from '@shared/index';
export class StepRepository extends BaseRepository<Step> {
constructor(db: Knex) {
@ -23,4 +23,35 @@ export class StepRepository extends BaseRepository<Step> {
last_printed_at: new Date()
});
}
async findTaskById(stepId: number): Promise<Task | undefined> {
const step = await this.db('steps')
.where({ id: stepId })
.first();
if (!step) {
return undefined;
}
return await this.db('tasks')
.where({ id: step.task_id })
.first();
}
async findStepNumber(stepId: number): Promise<number> {
const step = await this.db('steps')
.where({ id: stepId })
.first();
if (!step) {
return 0;
}
const steps = await this.db('steps')
.where({ task_id: step.task_id })
.orderBy('order', 'asc')
.select('id');
return steps.findIndex(s => s.id === stepId) + 1;
}
}

View File

@ -83,9 +83,7 @@ describe('formatUtils', () => {
expect(section).toEqual([
'[ ] Header',
'='.repeat(40),
'',
'Content',
''
]);
});
@ -94,9 +92,7 @@ describe('formatUtils', () => {
expect(section).toEqual([
'[ ] Header',
'-'.repeat(40),
'',
'Content',
''
]);
});
@ -106,8 +102,6 @@ describe('formatUtils', () => {
'[ ] Header',
'='.repeat(40),
'',
'',
''
]);
});
@ -116,10 +110,35 @@ describe('formatUtils', () => {
expect(section).toEqual([
'[ ] ',
'='.repeat(40),
'',
'Content',
''
]);
});
});
describe('formatStepHeader', () => {
it('should format step header with just step name and number', () => {
const header = formatUtils.formatStepHeader('Test Step', 1);
expect(header).toBe('Step 1: Test Step');
});
it('should format step header with step number and task name in single step view', () => {
const header = formatUtils.formatStepHeader('Test Step', 1, 'Test Task');
expect(header).toBe('Step 1 of Test Task: Test Step');
});
it('should format step header with step number but no task name in task view', () => {
const header = formatUtils.formatStepHeader('Test Step', 1, 'Test Task', true);
expect(header).toBe('Step 1: Test Step');
});
it('should handle empty step name', () => {
const header = formatUtils.formatStepHeader('', 1);
expect(header).toBe('Step 1: ');
});
it('should handle zero step number', () => {
const header = formatUtils.formatStepHeader('Test Step', 0);
expect(header).toBe('Step 0: Test Step');
});
});
});

View File

@ -31,6 +31,28 @@ export const formatUtils = {
});
},
/**
* Formats a step header with task context
* @param stepName Name of the step
* @param stepNumber Step number (1-based)
* @param taskName Name of the parent task (only used in single step view)
* @param isTaskView Whether this is being used in a task view
* @returns Formatted step header
*/
formatStepHeader(stepName: string, stepNumber: number, taskName?: string, isTaskView: boolean = false): string {
const parts = ['Step'];
if (stepNumber !== undefined) {
parts.push(' ');
parts.push(stepNumber.toString());
}
if (!isTaskView && taskName) {
parts.push(` of ${taskName}`);
}
parts.push(': ');
parts.push(stepName);
return parts.join('');
},
/**
* Formats a section with a header and content
* @param header Section header
@ -42,9 +64,7 @@ export const formatUtils = {
return [
this.formatCheckbox(header),
this.createBanner(bannerChar),
'',
content,
'',
];
}
};

View File

@ -72,7 +72,11 @@ export class SerialPrinter implements PrinterInterface {
// Print steps
for (let i = 0; i < taskSteps.length; i++) {
const step = taskSteps[i];
const stepSection = formatUtils.formatSection(`Step ${i + 1}: ${step.name}`, step.instructions, '-');
const stepSection = formatUtils.formatSection(
formatUtils.formatStepHeader(step.name, i + 1, task.name, true),
step.instructions,
'-'
);
await this.printer
.size(1, 1) // Normal size for step header
@ -89,9 +93,7 @@ export class SerialPrinter implements PrinterInterface {
}
await this.printer
.text('')
.text('')
.cut()
.cut(true, 2)
.close();
logger.info(`Printed task ${task.id}`);
@ -107,13 +109,20 @@ export class SerialPrinter implements PrinterInterface {
}
}
async printStep(step: Step, _db: Knex): Promise<void> {
async printStep(step: Step, db: Knex): Promise<void> {
if (!this.printer || !this.device) {
throw new Error('Printer not initialized');
}
try {
const stepSection = formatUtils.formatSection(`Step: ${step.name}`, step.instructions);
// Get the task name for context
const task = await this.stepRepository.findTaskById(step.id);
const stepNumber = await this.stepRepository.findStepNumber(step.id);
const stepSection = formatUtils.formatSection(
formatUtils.formatStepHeader(step.name, stepNumber, task?.name),
step.instructions
);
await this.printer
.font('a')
@ -132,9 +141,7 @@ export class SerialPrinter implements PrinterInterface {
// Print step ID as barcode
await this.printer
.barcode(step.id.toString(), 'CODE128', { width: 2, height: 50 })
.text('')
.text('')
.cut()
.cut(true, 2)
.close();
logger.info(`Printed step ${step.id}`);

View File

@ -38,7 +38,11 @@ export class TestPrinter implements Printer {
const content = [
...formatUtils.formatSection(`Task: ${task.name}`, ''),
...taskSteps.map((step, index) =>
formatUtils.formatSection(`Step ${index + 1}: ${step.name}`, step.instructions, '-')
formatUtils.formatSection(
formatUtils.formatStepHeader(step.name, index + 1, task.name, true),
step.instructions,
'-'
)
).flat(),
].join('\n');
@ -57,7 +61,14 @@ export class TestPrinter implements Printer {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = path.join(this.outputDir, `step-${step.id}-${timestamp}.txt`);
const content = formatUtils.formatSection(`Step: ${step.name}`, step.instructions).join('\n');
// Get the task name for context
const task = await this.stepRepository.findTaskById(step.id);
const stepNumber = await this.stepRepository.findStepNumber(step.id);
const content = formatUtils.formatSection(
formatUtils.formatStepHeader(step.name, stepNumber, task?.name),
step.instructions
).join('\n');
await fs.writeFile(filename, content);
logger.info(`Printed step ${step.id} to ${filename}`);