powr-sdk-api 4.3.10 → 4.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/managers/tasks.js +122 -6
- package/dist/routes/tasks.js +26 -0
- package/package.json +1 -1
package/dist/managers/tasks.js
CHANGED
|
@@ -475,11 +475,35 @@ class TasksManager {
|
|
|
475
475
|
|
|
476
476
|
// Log workflow execution
|
|
477
477
|
await this.logWorkflowExecution(workflow, results);
|
|
478
|
+
|
|
479
|
+
// For one-time workflows, deactivate after execution
|
|
480
|
+
if (workflow.schedule && !this.isCronExpression(workflow.schedule)) {
|
|
481
|
+
try {
|
|
482
|
+
const db = await getDb();
|
|
483
|
+
await db.collection("tasks").updateOne({
|
|
484
|
+
_id: workflow._id
|
|
485
|
+
}, {
|
|
486
|
+
$set: {
|
|
487
|
+
isActive: false
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
console.log(`🔄 Deactivated one-time workflow: ${workflow.name}`);
|
|
491
|
+
} catch (error) {
|
|
492
|
+
console.error("❌ Failed to deactivate workflow:", error);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Determine overall success - consider it successful if at least one action executed successfully
|
|
497
|
+
const executedActions = results.filter(r => r.type === 'action' && !r.skipped);
|
|
498
|
+
const successfulActions = executedActions.filter(r => r.success);
|
|
499
|
+
const overallSuccess = executedActions.length === 0 || successfulActions.length > 0;
|
|
478
500
|
return {
|
|
479
|
-
success:
|
|
501
|
+
success: overallSuccess,
|
|
480
502
|
workflowName: workflow.name,
|
|
481
503
|
stepsExecuted: results.length,
|
|
482
|
-
results: results
|
|
504
|
+
results: results,
|
|
505
|
+
actionsExecuted: executedActions.length,
|
|
506
|
+
actionsSuccessful: successfulActions.length
|
|
483
507
|
};
|
|
484
508
|
} catch (error) {
|
|
485
509
|
console.error(`❌ Workflow execution failed: ${workflow.name}`, error);
|
|
@@ -554,15 +578,35 @@ class TasksManager {
|
|
|
554
578
|
return true; // No condition, always execute
|
|
555
579
|
}
|
|
556
580
|
|
|
557
|
-
//
|
|
558
|
-
// For now, support basic conditions like "step1 === true"
|
|
581
|
+
// Parse condition like "step1.result === 'rain'" or "step1.result !== 'rain'"
|
|
559
582
|
const condition = step.condition;
|
|
583
|
+
|
|
584
|
+
// Extract step ID and condition
|
|
585
|
+
const stepMatch = condition.match(/step(\d+)\.result\s*(===|!==)\s*['"]([^'"]+)['"]/);
|
|
586
|
+
if (stepMatch) {
|
|
587
|
+
const stepId = stepMatch[1];
|
|
588
|
+
const operator = stepMatch[2];
|
|
589
|
+
const expectedValue = stepMatch[3];
|
|
590
|
+
const stepResult = previousResults.find(r => r.stepId === stepId);
|
|
591
|
+
if (stepResult && stepResult.result) {
|
|
592
|
+
var _stepResult$result$da;
|
|
593
|
+
// Get actual value from the result structure
|
|
594
|
+
const actualValue = stepResult.result.actualValue || ((_stepResult$result$da = stepResult.result.data) === null || _stepResult$result$da === void 0 ? void 0 : _stepResult$result$da.currentWeather) || stepResult.result.condition || 'unknown';
|
|
595
|
+
console.log(`🔍 Condition check: ${actualValue} ${operator} ${expectedValue}`);
|
|
596
|
+
if (operator === '===') {
|
|
597
|
+
return actualValue.toLowerCase() === expectedValue.toLowerCase();
|
|
598
|
+
} else if (operator === '!==') {
|
|
599
|
+
return actualValue.toLowerCase() !== expectedValue.toLowerCase();
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Fallback: check for simple boolean conditions
|
|
560
605
|
if (condition.includes('step1') && condition.includes('=== true')) {
|
|
561
606
|
const step1Result = previousResults.find(r => r.stepId === 'step1');
|
|
562
607
|
return step1Result && step1Result.conditionMet === true;
|
|
563
608
|
}
|
|
564
|
-
|
|
565
|
-
// Add more condition parsing as needed
|
|
609
|
+
console.log(`⚠️ Could not parse condition: ${condition}, defaulting to execute`);
|
|
566
610
|
return true; // Default to execute if condition parsing fails
|
|
567
611
|
}
|
|
568
612
|
|
|
@@ -589,12 +633,20 @@ class TasksManager {
|
|
|
589
633
|
async logWorkflowExecution(workflow, results) {
|
|
590
634
|
try {
|
|
591
635
|
const db = await getDb();
|
|
636
|
+
|
|
637
|
+
// Calculate overall success
|
|
638
|
+
const executedActions = results.filter(r => r.type === 'action' && !r.skipped);
|
|
639
|
+
const successfulActions = executedActions.filter(r => r.success);
|
|
640
|
+
const overallSuccess = executedActions.length === 0 || successfulActions.length > 0;
|
|
592
641
|
await db.collection("workflow_executions").insertOne({
|
|
593
642
|
workflowId: workflow._id,
|
|
594
643
|
workflowName: workflow.name,
|
|
595
644
|
userId: workflow.userId,
|
|
596
645
|
projectId: workflow.projectId,
|
|
597
646
|
results: results,
|
|
647
|
+
success: overallSuccess,
|
|
648
|
+
actionsExecuted: executedActions.length,
|
|
649
|
+
actionsSuccessful: successfulActions.length,
|
|
598
650
|
executedAt: new Date()
|
|
599
651
|
});
|
|
600
652
|
} catch (error) {
|
|
@@ -602,6 +654,61 @@ class TasksManager {
|
|
|
602
654
|
}
|
|
603
655
|
}
|
|
604
656
|
|
|
657
|
+
// Get execution history for a task
|
|
658
|
+
async getTaskExecutions(taskId, userId, projectId, isAdmin = false) {
|
|
659
|
+
try {
|
|
660
|
+
const db = await getDb();
|
|
661
|
+
|
|
662
|
+
// First verify the task exists and user has access
|
|
663
|
+
let taskQuery = {
|
|
664
|
+
_id: new ObjectId(taskId)
|
|
665
|
+
};
|
|
666
|
+
if (isAdmin) {
|
|
667
|
+
taskQuery.projectId = projectId;
|
|
668
|
+
} else {
|
|
669
|
+
taskQuery.userId = userId;
|
|
670
|
+
taskQuery.projectId = projectId;
|
|
671
|
+
}
|
|
672
|
+
const task = await db.collection("tasks").findOne(taskQuery);
|
|
673
|
+
if (!task) {
|
|
674
|
+
return {
|
|
675
|
+
success: false,
|
|
676
|
+
message: "Task not found"
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Get execution history based on task type
|
|
681
|
+
let executions = [];
|
|
682
|
+
if (task.type === 'workflow') {
|
|
683
|
+
// Get workflow executions
|
|
684
|
+
executions = await db.collection("workflow_executions").find({
|
|
685
|
+
workflowId: new ObjectId(taskId)
|
|
686
|
+
}).sort({
|
|
687
|
+
executedAt: -1
|
|
688
|
+
}).limit(50) // Limit to last 50 executions
|
|
689
|
+
.toArray();
|
|
690
|
+
} else {
|
|
691
|
+
// Get task executions
|
|
692
|
+
executions = await db.collection("task_executions").find({
|
|
693
|
+
taskId: new ObjectId(taskId)
|
|
694
|
+
}).sort({
|
|
695
|
+
executedAt: -1
|
|
696
|
+
}).limit(50) // Limit to last 50 executions
|
|
697
|
+
.toArray();
|
|
698
|
+
}
|
|
699
|
+
return {
|
|
700
|
+
success: true,
|
|
701
|
+
executions
|
|
702
|
+
};
|
|
703
|
+
} catch (error) {
|
|
704
|
+
console.error("❌ Failed to get task executions:", error);
|
|
705
|
+
return {
|
|
706
|
+
success: false,
|
|
707
|
+
message: error.message
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
605
712
|
// Check if a string is a valid timestamp
|
|
606
713
|
isTimestamp(value) {
|
|
607
714
|
try {
|
|
@@ -612,6 +719,15 @@ class TasksManager {
|
|
|
612
719
|
}
|
|
613
720
|
}
|
|
614
721
|
|
|
722
|
+
// Check if a string is a cron expression
|
|
723
|
+
isCronExpression(value) {
|
|
724
|
+
if (!value || typeof value !== 'string') return false;
|
|
725
|
+
|
|
726
|
+
// Basic cron pattern: 5 or 6 fields separated by spaces
|
|
727
|
+
const cronPattern = /^(\*|\d+|\d+-\d+|\d+\/\d+)(\s+(\*|\d+|\d+-\d+|\d+\/\d+)){4,5}$/;
|
|
728
|
+
return cronPattern.test(value.trim());
|
|
729
|
+
}
|
|
730
|
+
|
|
615
731
|
// Check if a string is a cron expression
|
|
616
732
|
isCronExpression(value) {
|
|
617
733
|
try {
|
package/dist/routes/tasks.js
CHANGED
|
@@ -275,6 +275,32 @@ router.delete("/:taskId", async (req, res) => {
|
|
|
275
275
|
}
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
+
// GET /tasks/:taskId/executions - Get execution history for a task
|
|
279
|
+
router.get("/:taskId/executions", async (req, res) => {
|
|
280
|
+
try {
|
|
281
|
+
const taskId = req.params.taskId;
|
|
282
|
+
const isAdmin = req.user.access === 100;
|
|
283
|
+
const result = await tasksManager.getTaskExecutions(taskId, req.user.powrId, req.projectId, isAdmin);
|
|
284
|
+
if (result.success) {
|
|
285
|
+
res.json({
|
|
286
|
+
success: true,
|
|
287
|
+
executions: result.executions
|
|
288
|
+
});
|
|
289
|
+
} else {
|
|
290
|
+
res.status(400).json({
|
|
291
|
+
success: false,
|
|
292
|
+
message: result.message
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.error("❌ Error retrieving task executions:", error);
|
|
297
|
+
res.status(500).json({
|
|
298
|
+
success: false,
|
|
299
|
+
message: "Failed to retrieve task executions"
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
278
304
|
// POST /tasks/execute-scheduled - Execute all scheduled tasks (called by Atlas)
|
|
279
305
|
router.post("/execute-scheduled", async (req, res) => {
|
|
280
306
|
try {
|