TaskDecay v1.0.0 MVP — smart task review & archive Chrome extension
This commit is contained in:
@@ -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}`);
|
||||
}
|
||||
Reference in New Issue
Block a user