TaskDecay v1.0.0 MVP — smart task review & archive Chrome extension

This commit is contained in:
Bun Bun
2026-06-17 06:48:47 +00:00
commit cc9aee68ee
38 changed files with 4710 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
// Notion API — queries a database for tasks
export async function fetchNotionTasks(config) {
if (!config.token)
throw new Error('Notion token not configured');
if (!config.projectIds || config.projectIds.length === 0) {
throw new Error('Notion database ID not configured. Set a database ID in options.');
}
const headers = {
'Authorization': `Bearer ${config.token}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json',
};
const allTasks = [];
for (const dbId of config.projectIds) {
const res = await fetch(`https://api.notion.com/v1/databases/${dbId}/query`, {
method: 'POST',
headers,
body: JSON.stringify({ page_size: 100 }),
});
if (!res.ok) {
console.warn(`Notion DB query failed for ${dbId}: ${res.status}`);
continue;
}
const data = await res.json();
const results = data.results || [];
for (const page of results) {
const props = page.properties || {};
const titleProp = Object.values(props).find((p) => p.type === 'title');
const title = titleProp?.title?.[0]?.plain_text || 'Untitled';
const statusProp = Object.values(props).find((p) => p.type === 'status' || p.type === 'select' || p.type === 'checkbox');
let done = false;
if (statusProp?.type === 'checkbox')
done = statusProp.checkbox;
else if (statusProp?.type === 'status')
done = statusProp.status?.name === 'Done';
else if (statusProp?.type === 'select')
done = statusProp.select?.name === 'Done';
if (done)
continue;
const dateProp = Object.values(props).find((p) => p.type === 'date');
const dueDate = dateProp?.date?.start ? new Date(dateProp.date.start) : null;
const multiSelect = Object.values(props).filter((p) => p.type === 'multi_select');
const labels = multiSelect.flatMap((p) => p.multi_select?.map((s) => s.name) || []);
const created = page.created_time ? new Date(page.created_time) : new Date();
const updated = page.last_edited_time ? new Date(page.last_edited_time) : created;
allTasks.push({
id: `notion-${page.id}`,
title,
priority: 1,
createdAt: created,
updatedAt: updated,
completedAt: null,
dueDate,
projectId: `notion-${dbId}`,
projectName: dbId.slice(0, 8),
labels,
url: page.url,
source: 'notion',
raw: page,
});
}
}
return allTasks;
}
export async function archiveNotionTask(taskId, token) {
const realId = taskId.replace('notion-', '');
const res = await fetch(`https://api.notion.com/v1/pages/${realId}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json',
},
body: JSON.stringify({ archived: true }),
});
if (!res.ok)
throw new Error(`Failed to archive Notion task: ${res.status}`);
}
export async function deleteNotionTask(taskId, token) {
const realId = taskId.replace('notion-', '');
const res = await fetch(`https://api.notion.com/v1/blocks/${realId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': '2022-06-28',
},
});
if (!res.ok)
throw new Error(`Failed to delete Notion task: ${res.status}`);
}