From 377610e2748602f61463a5df781893c66cea79dc Mon Sep 17 00:00:00 2001 From: Adrian Kunz Date: Tue, 10 Dec 2024 01:00:23 +0100 Subject: [PATCH 1/3] fix(frontend): Correctly convert tasks to markdown Closes: https://github.com/fujaba/fulib.org/issues/441 --- .../task-markdown.service.spec.ts | 37 +++++++++++++++++++ .../edit-assignment/task-markdown.service.ts | 21 ++++++++--- 2 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts diff --git a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts new file mode 100644 index 000000000..911831112 --- /dev/null +++ b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts @@ -0,0 +1,37 @@ +import {TestBed} from '@angular/core/testing'; +import {TaskMarkdownService} from './task-markdown.service'; +import Task from '../../model/task'; +import {TaskService} from '../../services/task.service'; + +describe(TaskMarkdownService.name, () => { + let md: TaskMarkdownService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [TaskService, TaskMarkdownService], + }); + md = TestBed.inject(TaskMarkdownService); + }); + + it('should render markdown', () => { + const tasks: Task[] = [ + { + _id: 'A', description: 'A', points: 1, children: [ + {_id: 'A.1', description: 'A.1', points: 2, children: []}, + ], + }, + // See https://github.com/fujaba/fulib.org/issues/441. + // This must output as a ## headline. + {_id: 'B', description: 'B', points: -1, children: []}, + // And to avoid C becoming a child of B, it must also output as a ## headline. + {_id: 'C', description: 'C', points: 3, children: []}, + ]; + const markdown = md.renderTasks(tasks); + expect(markdown).toBe(`\ +## A (1P) +- A.1 (2P) +## B (-1P) +## C (3P) +`); + }); +}); diff --git a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts index 083159af2..0197e199b 100644 --- a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts +++ b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts @@ -11,8 +11,8 @@ export class TaskMarkdownService { } parseTasks(markdown: string): Task[] { - // # Assignment 1 (xP/100P) - // ## Task 1 (xP/30P) + // # Assignment 1 (100P) + // ## Task 1 (30P) // - Something wrong (-1P) const taskStack: Task[][] = [[]]; for (const line of markdown.split('\n')) { @@ -47,20 +47,29 @@ export class TaskMarkdownService { } renderTasks(tasks: Task[], depth = 0) { - return tasks.map(t => this.renderTask(t, depth)).join(''); + let result = ''; + let lastTaskWasHeadline = false; + for (const task of tasks) { + const line = this.renderTask(task, depth, lastTaskWasHeadline); + result += line; + lastTaskWasHeadline = line.startsWith('#'); + } + return result; } - private renderTask(task: Task, depth: number) { + private renderTask(task: Task, depth: number, asHeadline: boolean) { const {children, deleted, description, points, ...rest} = task; if (deleted) { return ''; } const extra = JSON.stringify(rest); - if (points < 0 || !children || children.length === 0) { + // If the previous task had children, we need to write this as a new headline. + // Otherwise, it would end up as a subtask of the previous task without a way to distinguish it. + if (!asHeadline && (points < 0 || !children || children.length === 0)) { return `- ${description} (${points}P)\n`; } const childrenMd = this.renderTasks(children, depth + 1); const headlinePrefix = '#'.repeat(depth + 2); - return `${headlinePrefix} ${description} (x/${points}P)\n${childrenMd}`; + return `${headlinePrefix} ${description} (${points}P)\n${childrenMd}`; } } From 547a41873abee896a5e830f3c421995b5290b397 Mon Sep 17 00:00:00 2001 From: Adrian Kunz Date: Tue, 10 Dec 2024 01:05:35 +0100 Subject: [PATCH 2/3] fix(frontend): Don't collapse tasks by default --- .../assignment/modules/edit-assignment/task-markdown.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts index 0197e199b..a787614f2 100644 --- a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts +++ b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.ts @@ -28,7 +28,6 @@ export class TaskMarkdownService { _id: _id || this.taskService.generateID(), points: +points, children: [], - collapsed: true, }; switch (prefix) { case '-': From 5f778dd87f13cec94a743f3101bbc78d3d1cee55 Mon Sep 17 00:00:00 2001 From: Adrian Kunz Date: Tue, 10 Dec 2024 01:05:51 +0100 Subject: [PATCH 3/3] test(frontend): Add test for parsing task lists --- .../task-markdown.service.spec.ts | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts index 911831112..13fabc020 100644 --- a/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts +++ b/frontend/src/app/assignment/modules/edit-assignment/task-markdown.service.spec.ts @@ -13,25 +13,32 @@ describe(TaskMarkdownService.name, () => { md = TestBed.inject(TaskMarkdownService); }); - it('should render markdown', () => { - const tasks: Task[] = [ - { - _id: 'A', description: 'A', points: 1, children: [ - {_id: 'A.1', description: 'A.1', points: 2, children: []}, - ], - }, - // See https://github.com/fujaba/fulib.org/issues/441. - // This must output as a ## headline. - {_id: 'B', description: 'B', points: -1, children: []}, - // And to avoid C becoming a child of B, it must also output as a ## headline. - {_id: 'C', description: 'C', points: 3, children: []}, - ]; - const markdown = md.renderTasks(tasks); - expect(markdown).toBe(`\ + const tasks: Task[] = [ + { + _id: 'A', description: 'A', points: 1, children: [ + {_id: 'A.1', description: 'A.1', points: 2, children: []}, + ], + }, + // See https://github.com/fujaba/fulib.org/issues/441. + // This must output as a ## headline. + {_id: 'B', description: 'B', points: -1, children: []}, + // And to avoid C becoming a child of B, it must also output as a ## headline. + {_id: 'C', description: 'C', points: 3, children: []}, + ]; + const markdown = `\ ## A (1P) - A.1 (2P) ## B (-1P) ## C (3P) -`); +`; + + it('should render markdown', () => { + const actual = md.renderTasks(tasks); + expect(actual).toBe(markdown); + }); + + it('should parse markdown', () => { + const actual = md.parseTasks(markdown); + expect(actual).toEqual(tasks); }); });