Skip to content

Commit 2fbf18a

Browse files
committed
Merge remote-tracking branch 'origin/main'
# Conflicts: # vs-code-extension/src/extension.ts
2 parents cd58cb1 + 1a22c2b commit 2fbf18a

13 files changed

Lines changed: 176 additions & 25 deletions

File tree

.vscode/launch.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
"preLaunchTask": "${defaultBuildTask}",
1616
"env": {
1717
"AS_NOTES_DEBUG": "1",
18-
"AS_NOTES_LICENCE_SERVER_URL": "http://localhost:5173"
18+
// Uncomment to use test licence server
19+
// "AS_NOTES_LICENCE_SERVER_URL": "http://localhost:5173"
20+
// Uncomment to simulate licence type
21+
"AS_NOTES_LICENCE_OVERRIDE": "pro_editor"
22+
// "AS_NOTES_LICENCE_OVERRIDE": "pro_ai_sync"
1923
}
2024
}
2125
]

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ The following commands only appear in the slash menu when the cursor is on a tas
165165
| **Task: Waiting** | Toggles `#W` at the start of the task text (inserts if absent, removes if present) |
166166
| **Task: Due Date** | Opens a date input pre-filled with today (YYYY-MM-DD). Confirms and inserts `#D-YYYY-MM-DD` at the start of the task text. Replaces any existing due date tag |
167167
| **Task: Completion Date** | Opens a date input pre-filled with today (YYYY-MM-DD). Confirms and inserts `#C-YYYY-MM-DD` at the start of the task text. Replaces any existing completion date tag |
168+
| **Convert to Kanban Card** *(Pro)* | Marks the task as done, creates a Kanban card in the **TODO** lane with the task title (stripped of tags), matching priority and due date, and the **Waiting** flag set. Only available on unchecked tasks |
168169

169170
Priority and waiting tags toggle: issuing the same tag again removes it. Issuing a different priority replaces the existing one. Due date and completion date tags replace any existing tag of the same type.
170171

@@ -585,7 +586,7 @@ Cards are the primary unit of work. Each card is stored as a **Markdown file** w
585586
- **Delete card** — click the trash icon in the card editor.
586587
- **Open card file** — click the **Open File** button in the card editor to open the Markdown file directly.
587588

588-
**Priority levels:** critical · high · medium · low · none
589+
**Priority levels:** P1 · P2 · P3 · P4 · P5 · none
589590

590591
#### Entries (comments)
591592

@@ -617,7 +618,7 @@ A typical card file looks like:
617618
---
618619
title: Implement search
619620
lane: doing
620-
priority: high
621+
priority: p2
621622
assignee: gareth
622623
labels:
623624
- backend
@@ -647,6 +648,7 @@ Front-matter holds the structured fields; the Markdown body is the card descript
647648
| **AS Notes: Create Kanban Board** | Create a new board |
648649
| **AS Notes: Rename Kanban Board** | Rename the current board |
649650
| **AS Notes: Delete Kanban Board** | Delete the current board and all its data |
651+
| **AS Notes: Convert Task to Kanban Card** | Mark the current task done and create a Kanban card from it *(Pro)* |
650652

651653
## Settings
652654

docs-src/pages/Slash Commands.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ These commands only appear in the slash menu when the cursor is on a task line (
6666
| **Task: Waiting** | Inserts `#W` at the task text start |
6767
| **Task: Due Date** | Opens a date input pre-filled with today (YYYY-MM-DD format). On confirm, inserts `#D-YYYY-MM-DD` at the task text start |
6868
| **Task: Completion Date** | Opens a date input pre-filled with today (YYYY-MM-DD format). On confirm, inserts `#C-YYYY-MM-DD` at the task text start |
69+
| **Convert to Kanban Card** *(Pro)* | Marks the task as done, creates a Kanban card in the **TODO** lane with the task title (stripped of tags), matching priority and due date, and the **Waiting** flag set. Only available on unchecked tasks |
6970

7071
## Pro Licence
7172

vs-code-extension/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vs-code-extension/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@
150150
"command": "as-notes.renameKanbanBoard",
151151
"title": "AS Notes: Rename Kanban Board"
152152
},
153+
{
154+
"command": "as-notes.convertTaskToKanbanCard",
155+
"title": "AS Notes: Convert Task to Kanban Card"
156+
},
153157
{
154158
"command": "as-notes.enterLicenceKey",
155159
"title": "AS Notes: Enter Licence Key"

vs-code-extension/src/KanbanEditorPanel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export class KanbanEditorPanel {
238238
card.labels = message.labels as string[] | undefined;
239239
card.dueDate = message.dueDate as string | undefined;
240240
card.description = (message.description ?? '').trim();
241+
card.waiting = message.waiting ? true : undefined;
241242

242243
await this._kanbanStore.save(card);
243244
break;
@@ -254,6 +255,7 @@ export class KanbanEditorPanel {
254255
card.assignee = message.assignee as string | undefined;
255256
card.labels = message.labels as string[] | undefined;
256257
card.dueDate = message.dueDate as string | undefined;
258+
card.waiting = message.waiting ? true : undefined;
257259
if (typeof message.description === 'string') {
258260
card.description = message.description.trim();
259261
}

vs-code-extension/src/KanbanStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ export class KanbanStore {
397397
if (card.sortOrder != null) { data.sortOrder = card.sortOrder; }
398398
if (card.slug) { data.slug = card.slug; }
399399
if (card.assets?.length) { data.assets = card.assets; }
400+
if (card.waiting) { data.waiting = card.waiting; }
400401
// No entries in frontmatter — they live in the markdown body
401402
const frontmatter = stringify(data, { lineWidth: 0 });
402403
return `---\n${frontmatter}---\n${existingBody}`;
@@ -442,6 +443,7 @@ export class KanbanStore {
442443
dueDate: (data.dueDate as string) || undefined,
443444
sortOrder: typeof data.sortOrder === 'number' ? data.sortOrder : undefined,
444445
slug: typeof data.slug === 'string' ? data.slug : undefined,
446+
waiting: (data.waiting as boolean) || undefined,
445447
parsedEntries: parsedEntries.length > 0 ? parsedEntries : undefined,
446448
assets: Array.isArray(data.assets)
447449
? (data.assets as AssetMeta[])

vs-code-extension/src/KanbanTypes.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type Priority = 'critical' | 'high' | 'medium' | 'low' | 'none';
1+
export type Priority = 'p1' | 'p2' | 'p3' | 'p4' | 'p5' | 'none';
22

33
export interface AssetMeta {
44
filename: string;
@@ -29,6 +29,8 @@ export interface Card {
2929
dueDate?: string;
3030
sortOrder?: number;
3131
slug?: string;
32+
/** When true, the card is waiting/blocked. Default false. */
33+
waiting?: boolean;
3234
/** Parsed from markdown body — never stored in frontmatter. */
3335
parsedEntries?: CardEntryDisplay[];
3436
assets?: AssetMeta[];

vs-code-extension/src/SlashCommandProvider.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,15 @@ export class SlashCommandProvider implements vscode.CompletionItemProvider {
331331
title: 'Insert Task Completion Date',
332332
};
333333
items.push(taskCompletionDateItem);
334+
// ── Convert to Kanban Card ─────────────────────────────
335+
const convertToCardItem = new vscode.CompletionItem('Convert to Kanban Card' + proSuffix, vscode.CompletionItemKind.Event);
336+
convertToCardItem.detail = 'Mark task done and create a Kanban card (with Waiting flag)';
337+
convertToCardItem.sortText = 'k-convert-to-kanban';
338+
convertToCardItem.filterText = '/Convert to Kanban Card';
339+
convertToCardItem.insertText = '';
340+
convertToCardItem.range = range;
341+
convertToCardItem.command = { command: 'as-notes.convertTaskToKanbanCard', title: 'Convert to Kanban Card' };
342+
items.push(convertToCardItem);
334343
}
335344

336345
return new vscode.CompletionList(items, false);

vs-code-extension/src/extension.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import { KanbanStore } from './KanbanStore.js';
4949
import { KanbanBoardConfigStore } from './KanbanBoardConfigStore.js';
5050
import { KanbanEditorPanel } from './KanbanEditorPanel.js';
5151
import { KanbanSidebarProvider } from './KanbanSidebarProvider.js';
52+
import type { Priority } from './KanbanTypes.js';
5253

5354
const MARKDOWN_SELECTOR: vscode.DocumentSelector = { language: 'markdown' };
5455
const ASNOTES_DIR = '.asnotes';
@@ -124,6 +125,7 @@ const FULL_MODE_COMMAND_IDS: string[] = [
124125
'as-notes.createKanbanBoard',
125126
'as-notes.deleteKanbanBoard',
126127
'as-notes.renameKanbanBoard',
128+
'as-notes.convertTaskToKanbanCard',
127129
'as-notes.insertTemplate',
128130
];
129131

@@ -219,6 +221,8 @@ async function showServerUnreachableWarning(): Promise<void> {
219221
* extension is running as the official published build.
220222
*/
221223
export function hasProEditor(): boolean {
224+
const override = process.env.AS_NOTES_LICENCE_OVERRIDE;
225+
if (override === 'pro_editor' || override === 'pro_ai_sync') { return true; }
222226
return isOfficialBuild && hasProEditorAccess(licenceState);
223227
}
224228

@@ -227,6 +231,8 @@ export function hasProEditor(): boolean {
227231
* extension is running as the official published build.
228232
*/
229233
export function hasProAiSync(): boolean {
234+
const override = process.env.AS_NOTES_LICENCE_OVERRIDE;
235+
if (override === 'pro_ai_sync') { return true; }
230236
return isOfficialBuild && hasProAiSyncAccess(licenceState);
231237
}
232238

@@ -850,6 +856,75 @@ async function enterFullMode(
850856
kanbanSidebarProvider?.refresh();
851857
}),
852858
);
859+
fullModeDisposables.push(
860+
vscode.commands.registerCommand('as-notes.convertTaskToKanbanCard', async () => {
861+
if (!hasProEditor()) {
862+
vscode.window.showWarningMessage('AS Notes: Convert to Kanban Card requires a Pro licence.');
863+
return;
864+
}
865+
866+
const editor = vscode.window.activeTextEditor;
867+
if (!editor) { return; }
868+
869+
const line = editor.selection.active.line;
870+
const lineText = editor.document.lineAt(line).text;
871+
872+
// Must be a task line
873+
if (!/^\s*-\s+\[[ xX]\]/.test(lineText)) { return; }
874+
875+
// Reject done tasks
876+
if (/^\s*-\s+\[[xX]\]/.test(lineText)) {
877+
vscode.window.showWarningMessage('Cannot convert done tasks to Kanban cards - uncheck to convert');
878+
return;
879+
}
880+
881+
// Ensure a board is selected
882+
if (!kanbanStore?.currentBoard) {
883+
vscode.window.showWarningMessage('No Kanban board selected. Please select or create a board first.');
884+
return;
885+
}
886+
887+
// Strip checkbox prefix and parse task metadata
888+
const taskText = lineText.replace(/^\s*-\s+\[ \]\s*/, '');
889+
const meta = IndexService.parseTaskMeta(taskText);
890+
const title = meta.cleanText.trim();
891+
if (!title) {
892+
vscode.window.showWarningMessage('Task has no text to create a card from.');
893+
return;
894+
}
895+
896+
const priority = meta.priority !== null ? `p${meta.priority}` as Priority : undefined;
897+
const dueDate = meta.dueDate ?? undefined;
898+
899+
// Create card in todo lane with waiting flag
900+
const card = kanbanStore.createCard(title, 'todo');
901+
card.priority = priority;
902+
card.dueDate = dueDate;
903+
card.waiting = true;
904+
905+
// Place at end of todo lane
906+
const todoCards = kanbanStore.getAll()
907+
.filter((c) => c.lane === 'todo')
908+
.sort((a, b) => (a.sortOrder ?? Date.parse(a.created)) - (b.sortOrder ?? Date.parse(b.created)));
909+
const lastOrder = todoCards.length > 0
910+
? (todoCards[todoCards.length - 1].sortOrder ?? Date.parse(todoCards[todoCards.length - 1].created))
911+
: 0;
912+
card.sortOrder = lastOrder + 1;
913+
914+
await kanbanStore.save(card);
915+
916+
// Mark the task line as done
917+
const doneLine = toggleTodoLine(lineText);
918+
await editor.edit((editBuilder) => {
919+
editBuilder.replace(editor.document.lineAt(line).range, doneLine);
920+
});
921+
922+
// Refresh kanban panel if open
923+
KanbanEditorPanel.currentPanel?.refresh();
924+
925+
vscode.window.showInformationMessage(`Kanban card created: "${title}"`);
926+
}),
927+
);
853928

854929
// Status bar: show indexing spinner
855930
statusBarItem.text = '$(sync~spin) AS Notes: Indexing...';

0 commit comments

Comments
 (0)