Skip to content

Commit c80643f

Browse files
committed
feat(xLevelSubTasks): add very basic sub sub task mode
1 parent ef2a5f2 commit c80643f

File tree

6 files changed

+56
-3
lines changed

6 files changed

+56
-3
lines changed

src/app/features/markdown-checklist/is-markdown-checklist.spec.ts

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ describe('isMarkdownChecklist()', () => {
1818
[
1919
// --
2020
'- [ ] task',
21+
' - [ ] task',
2122
'- [x] task another yeah',
2223
'\n- [ ] task\n\n',
2324
].forEach((text, i) => {
@@ -30,6 +31,8 @@ describe('isMarkdownChecklist()', () => {
3031
// --
3132
'some what - [ ] task',
3233
'- [x] task another yeah\nSomewhat',
34+
'',
35+
'\n\n',
3336
'Some what yeah\n- [ ] task\n\n',
3437
].forEach((text, i) => {
3538
it(`should return false for a non valid checklist #${i}`, () => {

src/app/features/markdown-checklist/is-markdown-checklist.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@ Some text yeah
1414

1515
export const isMarkdownChecklist = (text: string): boolean => {
1616
try {
17-
const lines = text.split('\n');
18-
return lines.every(
19-
(it) => it.trim() === '' || it.startsWith('- [x] ') || it.startsWith('- [ ] '),
17+
const lines = text.split('\n').filter((it) => it.trim() !== '');
18+
19+
if (lines.length === 0) {
20+
return false;
21+
}
22+
23+
const items = lines.filter(
24+
(it) => it.trim().startsWith('- [x] ') || it.trim().startsWith('- [ ] '),
2025
);
26+
return items.length === lines.length || items.length >= 3;
2127
} catch (e) {
2228
console.error('Checklist parsing failed');
2329
console.error(e);

src/app/features/tasks/task-detail-panel/task-detail-panel.component.html

+7
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,15 @@
179179
[type]="'panel'"
180180
>
181181
<ng-container panel-header>
182+
@if(isMarkdownChecklist){
183+
<mat-icon>checklist</mat-icon>
184+
Checklist
185+
<!-- -->
186+
} @else {
182187
<mat-icon *ngIf="task.notes">chat</mat-icon>
183188
<mat-icon *ngIf="!task.notes">chat_bubble_outline</mat-icon>
184189
<span>{{T.F.TASK.ADDITIONAL_INFO.NOTES|translate}}</span>
190+
}
185191
</ng-container>
186192

187193
<ng-container panel-content>
@@ -192,6 +198,7 @@
192198
(keyboardUnToggle)="focusItem(noteWrapperElRef)"
193199
[isFocus]="isFocusNotes"
194200
[isShowControls]="true"
201+
[isShowChecklistToggle]="true"
195202
[model]="task.notes|| defaultTaskNotes"
196203
></inline-markdown>
197204
</ng-container>

src/app/features/tasks/task-detail-panel/task-detail-panel.component.ts

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import { PlannerService } from '../../planner/planner.service';
7171
import { DialogScheduleTaskComponent } from '../../planner/dialog-schedule-task/dialog-schedule-task.component';
7272
import { Store } from '@ngrx/store';
7373
import { selectIssueProviderById } from '../../issue/store/issue-provider.selectors';
74+
import { isMarkdownChecklist } from '../../markdown-checklist/is-markdown-checklist';
7475

7576
interface IssueAndType {
7677
id: string | number | null;
@@ -105,6 +106,7 @@ export class TaskDetailPanelComponent implements AfterViewInit, OnDestroy {
105106
selectedItemIndex: number = 0;
106107
isFocusNotes: boolean = false;
107108
isDragOver: boolean = false;
109+
isMarkdownChecklist: boolean = false;
108110

109111
T: typeof T = T;
110112
issueAttachments: TaskAttachment[] = [];
@@ -333,6 +335,7 @@ export class TaskDetailPanelComponent implements AfterViewInit, OnDestroy {
333335
this.isExpandedIssuePanel = !IS_MOBILE && !!this.issueData;
334336
this.isExpandedNotesPanel =
335337
!IS_MOBILE && (!!newVal.notes || (!newVal.issueId && !newVal.attachments?.length));
338+
this.isMarkdownChecklist = isMarkdownChecklist(newVal.notes || '');
336339
}
337340

338341
get progress(): number {

src/app/ui/inline-markdown/inline-markdown.component.html

+12
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,19 @@
3434
*ngIf="isShowControls"
3535
class="controls"
3636
>
37+
@if(isShowChecklistToggle){
38+
<!-- -->
3739
<button
40+
[matTooltip]="'Toggle checklist mode'"
41+
(click)="toggleChecklistMode($event)"
42+
mat-icon-button
43+
>
44+
<mat-icon>checklist</mat-icon>
45+
</button>
46+
}
47+
48+
<button
49+
[matTooltip]="'Open in fullscreen'"
3850
(click)="openFullScreen()"
3951
mat-icon-button
4052
>

src/app/ui/inline-markdown/inline-markdown.component.ts

+22
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { map, startWith } from 'rxjs/operators';
1919
import { GlobalConfigService } from '../../features/config/global-config.service';
2020
import { MatDialog } from '@angular/material/dialog';
2121
import { DialogFullscreenMarkdownComponent } from '../dialog-fullscreen-markdown/dialog-fullscreen-markdown.component';
22+
import { isMarkdownChecklist } from '../../features/markdown-checklist/is-markdown-checklist';
2223

2324
const HIDE_OVERFLOW_TIMEOUT_DURATION = 300;
2425

@@ -32,6 +33,7 @@ const HIDE_OVERFLOW_TIMEOUT_DURATION = 300;
3233
export class InlineMarkdownComponent implements OnInit, OnDestroy {
3334
@Input() isLock: boolean = false;
3435
@Input() isShowControls: boolean = false;
36+
@Input() isShowChecklistToggle: boolean = false;
3537

3638
@Output() changed: EventEmitter<string> = new EventEmitter();
3739
@Output() focused: EventEmitter<Event> = new EventEmitter();
@@ -42,6 +44,7 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
4244
@ViewChild('previewEl') previewEl: MarkdownComponent | undefined;
4345

4446
isHideOverflow: boolean = false;
47+
isChecklistMode: boolean = false;
4548
isShowEdit: boolean = false;
4649
modelCopy: string | undefined;
4750

@@ -78,6 +81,9 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
7881
this.resizeParsedToFit();
7982
});
8083
}
84+
85+
this.isChecklistMode =
86+
this.isChecklistMode && this.isShowChecklistToggle && !!v && isMarkdownChecklist(v);
8187
}
8288

8389
@Input() set isFocus(val: boolean) {
@@ -103,6 +109,10 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
103109
}
104110
}
105111

112+
checklistToggle(): void {
113+
this.isChecklistMode = !this.isChecklistMode;
114+
}
115+
106116
keypressHandler(ev: KeyboardEvent): void {
107117
this.resizeTextareaToFit();
108118

@@ -207,6 +217,18 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
207217
this.blurred.emit(ev);
208218
}
209219

220+
toggleChecklistMode(ev: Event): void {
221+
ev.preventDefault();
222+
ev.stopPropagation();
223+
this.isChecklistMode = true;
224+
this._toggleShowEdit();
225+
if (this.modelCopy && isMarkdownChecklist(this.modelCopy)) {
226+
this.modelCopy += '\n- [ ] ';
227+
} else {
228+
this.modelCopy = '- [ ] ';
229+
}
230+
}
231+
210232
private _toggleShowEdit(): void {
211233
this.isShowEdit = true;
212234
this.modelCopy = this.model || '';

0 commit comments

Comments
 (0)