Add automation runs quota tracking to quota management page

- Add max_automation_runs to QUOTA_CONFIG in QuotaService
- Add runs_this_month and runs_month_started fields to TenantDefaultFlow
- Add increment_run_count() method for tracking flow executions
- Add Bot icon for automation quotas in frontend QuotaSettings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-22 01:50:58 -05:00
parent fb97091cb9
commit dd24eede87
4 changed files with 79 additions and 1 deletions

View File

@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
import { useOutletContext, Link } from 'react-router-dom'; import { useOutletContext, Link } from 'react-router-dom';
import { import {
AlertTriangle, Archive, Check, ChevronDown, ChevronUp, AlertTriangle, Archive, Check, ChevronDown, ChevronUp,
Clock, Download, Users, Briefcase, Calendar, RefreshCw Clock, Download, Users, Briefcase, Calendar, RefreshCw, Bot
} from 'lucide-react'; } from 'lucide-react';
import { Business, User, QuotaOverage } from '../../types'; import { Business, User, QuotaOverage } from '../../types';
import { import {
@@ -136,6 +136,10 @@ const QuotaSettings: React.FC = () => {
return <Briefcase className="h-5 w-5" />; return <Briefcase className="h-5 w-5" />;
case 'MAX_SERVICES': case 'MAX_SERVICES':
return <Calendar className="h-5 w-5" />; return <Calendar className="h-5 w-5" />;
case 'MAX_AUTOMATION_RUNS':
return <Bot className="h-5 w-5" />;
case 'MAX_AUTOMATED_TASKS':
return <Bot className="h-5 w-5" />;
default: default:
return <AlertTriangle className="h-5 w-5" />; return <AlertTriangle className="h-5 w-5" />;
} }

View File

@@ -59,6 +59,12 @@ class QuotaService:
'display_name': 'automated tasks', 'display_name': 'automated tasks',
'count_method': 'count_automated_tasks', 'count_method': 'count_automated_tasks',
}, },
'MAX_AUTOMATION_RUNS': {
'model': None, # No archivable model - informational only
'display_name': 'automation runs this month',
'count_method': 'count_automation_runs',
'is_archivable': False, # Can't archive runs, just throttle
},
} }
def __init__(self, tenant: Tenant): def __init__(self, tenant: Tenant):
@@ -94,6 +100,21 @@ class QuotaService:
from smoothschedule.scheduling.schedule.models import ScheduledTask from smoothschedule.scheduling.schedule.models import ScheduledTask
return ScheduledTask.objects.count() return ScheduledTask.objects.count()
def count_automation_runs(self) -> int:
"""
Count automation flow executions this month.
Uses TenantDefaultFlow records to track usage.
"""
from smoothschedule.integrations.activepieces.models import TenantDefaultFlow
from django.db.models import Sum
# Get total runs from all default flows
result = TenantDefaultFlow.objects.filter(
tenant=self.tenant
).aggregate(total=Sum('runs_this_month'))
return result['total'] or 0
# ========================================================================= # =========================================================================
# Limit Retrieval # Limit Retrieval
# ========================================================================= # =========================================================================
@@ -115,6 +136,7 @@ class QuotaService:
'MAX_RESOURCES': 'max_resources', 'MAX_RESOURCES': 'max_resources',
'MAX_SERVICES': 'max_services', 'MAX_SERVICES': 'max_services',
'MAX_AUTOMATED_TASKS': 'max_automated_tasks', 'MAX_AUTOMATED_TASKS': 'max_automated_tasks',
'MAX_AUTOMATION_RUNS': 'max_automation_runs',
} }
feature_code = feature_code_map.get(quota_type, quota_type.lower()) feature_code = feature_code_map.get(quota_type, quota_type.lower())

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.2.8 on 2025-12-22 06:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('activepieces', '0002_add_tenant_default_flow'),
]
operations = [
migrations.AddField(
model_name='tenantdefaultflow',
name='runs_month_started',
field=models.DateField(blank=True, help_text='When the current run count period started (resets monthly)', null=True),
),
migrations.AddField(
model_name='tenantdefaultflow',
name='runs_this_month',
field=models.PositiveIntegerField(default=0, help_text='Number of times this flow has run this billing month'),
),
]

View File

@@ -124,6 +124,16 @@ class TenantDefaultFlow(models.Model):
default=True, default=True,
help_text="Whether this flow is enabled in Activepieces", help_text="Whether this flow is enabled in Activepieces",
) )
# Usage tracking for quota management
runs_this_month = models.PositiveIntegerField(
default=0,
help_text="Number of times this flow has run this billing month",
)
runs_month_started = models.DateField(
null=True,
blank=True,
help_text="When the current run count period started (resets monthly)",
)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
@@ -139,3 +149,22 @@ class TenantDefaultFlow(models.Model):
def __str__(self): def __str__(self):
return f"{self.tenant.name} - {self.get_flow_type_display()}" return f"{self.tenant.name} - {self.get_flow_type_display()}"
def increment_run_count(self):
"""
Increment the run count for this flow.
Resets the counter if a new month has started.
"""
from django.utils import timezone
today = timezone.now().date()
current_month_start = today.replace(day=1)
# Reset counter if new month
if self.runs_month_started is None or self.runs_month_started < current_month_start:
self.runs_this_month = 1
self.runs_month_started = current_month_start
else:
self.runs_this_month += 1
self.save(update_fields=['runs_this_month', 'runs_month_started'])