127 lines
3.6 KiB
JavaScript
127 lines
3.6 KiB
JavaScript
#!/usr/bin/env osascript -l JavaScript
|
|
|
|
// Get all OmniFocus projects with full folder hierarchy
|
|
// Returns JSON with project names, folders, and structure
|
|
|
|
function run() {
|
|
const app = Application('OmniFocus');
|
|
app.includeStandardAdditions = true;
|
|
|
|
const doc = app.defaultDocument;
|
|
const folders = doc.folders();
|
|
const projects = doc.flattenedProjects();
|
|
|
|
// Build folder structure
|
|
const folderStructure = [];
|
|
|
|
function processFolder(folder, depth = 0) {
|
|
const folderInfo = {
|
|
id: folder.id(),
|
|
name: folder.name(),
|
|
depth: depth,
|
|
projects: [],
|
|
subfolders: []
|
|
};
|
|
|
|
// Get projects in this folder
|
|
try {
|
|
const folderProjects = folder.projects();
|
|
for (let i = 0; i < folderProjects.length; i++) {
|
|
const proj = folderProjects[i];
|
|
folderInfo.projects.push({
|
|
id: proj.id(),
|
|
name: proj.name(),
|
|
status: proj.status(),
|
|
taskCount: proj.numberOfAvailableTasks()
|
|
});
|
|
}
|
|
} catch (e) {
|
|
// No projects in folder
|
|
}
|
|
|
|
// Get subfolders
|
|
try {
|
|
const subfolders = folder.folders();
|
|
for (let i = 0; i < subfolders.length; i++) {
|
|
folderInfo.subfolders.push(processFolder(subfolders[i], depth + 1));
|
|
}
|
|
} catch (e) {
|
|
// No subfolders
|
|
}
|
|
|
|
return folderInfo;
|
|
}
|
|
|
|
// Process top-level folders
|
|
for (let i = 0; i < folders.length; i++) {
|
|
folderStructure.push(processFolder(folders[i], 0));
|
|
}
|
|
|
|
// Get standalone projects (not in folders)
|
|
const standaloneProjects = [];
|
|
for (let i = 0; i < projects.length; i++) {
|
|
const proj = projects[i];
|
|
try {
|
|
const container = proj.container();
|
|
// If container is the document itself, it's standalone
|
|
if (container.class() === 'document') {
|
|
standaloneProjects.push({
|
|
id: proj.id(),
|
|
name: proj.name(),
|
|
status: proj.status(),
|
|
taskCount: proj.numberOfAvailableTasks()
|
|
});
|
|
}
|
|
} catch (e) {
|
|
// Skip if can't determine container
|
|
}
|
|
}
|
|
|
|
// Build flat list for easy lookup
|
|
const flatList = [];
|
|
|
|
function flattenStructure(folders, path = '') {
|
|
for (const folder of folders) {
|
|
const currentPath = path ? `${path} > ${folder.name}` : folder.name;
|
|
|
|
for (const proj of folder.projects) {
|
|
flatList.push({
|
|
id: proj.id,
|
|
name: proj.name,
|
|
path: `${currentPath} > ${proj.name}`,
|
|
folder: folder.name,
|
|
status: proj.status,
|
|
taskCount: proj.taskCount
|
|
});
|
|
}
|
|
|
|
if (folder.subfolders.length > 0) {
|
|
flattenStructure(folder.subfolders, currentPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
flattenStructure(folderStructure);
|
|
|
|
// Add standalone projects
|
|
for (const proj of standaloneProjects) {
|
|
flatList.push({
|
|
id: proj.id,
|
|
name: proj.name,
|
|
path: proj.name,
|
|
folder: null,
|
|
status: proj.status,
|
|
taskCount: proj.taskCount
|
|
});
|
|
}
|
|
|
|
const result = {
|
|
total_projects: flatList.length,
|
|
folder_structure: folderStructure,
|
|
standalone_projects: standaloneProjects,
|
|
flat_list: flatList
|
|
};
|
|
|
|
return JSON.stringify(result, null, 2);
|
|
}
|