1120 lines
43 KiB
Python
1120 lines
43 KiB
Python
"""
|
|
Analytics app forms for CRUD operations.
|
|
"""
|
|
|
|
from django import forms
|
|
from django.core.exceptions import ValidationError
|
|
from django.utils import timezone
|
|
from datetime import datetime, date
|
|
|
|
from .models import (
|
|
Dashboard, DashboardWidget, DataSource, Report,
|
|
MetricDefinition
|
|
)
|
|
|
|
|
|
class DashboardForm(forms.ModelForm):
|
|
"""
|
|
Form for creating and updating dashboards.
|
|
"""
|
|
|
|
class Meta:
|
|
model = Dashboard
|
|
fields = [
|
|
'name', 'description', 'dashboard_type', 'is_public',
|
|
'layout_config', 'refresh_interval', 'is_active'
|
|
]
|
|
widgets = {
|
|
'name': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter dashboard name'
|
|
}),
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter dashboard description'
|
|
}),
|
|
'dashboard_type': forms.Select(attrs={'class': 'form-control'}),
|
|
'is_public': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
|
'layout_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 5,
|
|
'placeholder': 'Enter JSON layout configuration'
|
|
}),
|
|
'refresh_interval': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 30,
|
|
'max': 3600,
|
|
'step': 30
|
|
}),
|
|
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
}
|
|
help_texts = {
|
|
'name': 'Unique name for this dashboard',
|
|
'dashboard_type': 'Dashboard type for organization',
|
|
'is_public': 'Whether this dashboard is publicly accessible',
|
|
'layout_config': 'JSON configuration for dashboard layout',
|
|
'refresh_interval': 'Auto-refresh interval in seconds (30-3600)',
|
|
}
|
|
|
|
def clean_name(self):
|
|
name = self.cleaned_data['name']
|
|
if len(name) < 3:
|
|
raise ValidationError('Dashboard name must be at least 3 characters long.')
|
|
return name
|
|
|
|
def clean_refresh_interval(self):
|
|
interval = self.cleaned_data['refresh_interval']
|
|
if interval and (interval < 30 or interval > 3600):
|
|
raise ValidationError('Refresh interval must be between 30 and 3600 seconds.')
|
|
return interval
|
|
|
|
|
|
class DashboardWidgetForm(forms.ModelForm):
|
|
"""
|
|
Form for creating and updating dashboard widgets.
|
|
"""
|
|
|
|
class Meta:
|
|
model = DashboardWidget
|
|
fields = [
|
|
'dashboard', 'name', 'widget_type', 'position_x', 'position_y',
|
|
'width', 'height', 'display_config', 'query_config', 'is_active'
|
|
]
|
|
widgets = {
|
|
'dashboard': forms.Select(attrs={'class': 'form-control'}),
|
|
'name': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter widget name'
|
|
}),
|
|
'widget_type': forms.Select(attrs={'class': 'form-control'}),
|
|
'position_x': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 0,
|
|
'max': 12
|
|
}),
|
|
'position_y': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 0
|
|
}),
|
|
'width': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 1,
|
|
'max': 12
|
|
}),
|
|
'height': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 1,
|
|
'max': 20
|
|
}),
|
|
'display_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Enter JSON display configuration'
|
|
}),
|
|
'query_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter query configuration'
|
|
}),
|
|
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
}
|
|
help_texts = {
|
|
'widget_type': 'Type of widget (chart, table, KPI, etc.)',
|
|
'position_x': 'Horizontal position (0-12 grid system)',
|
|
'position_y': 'Vertical position',
|
|
'width': 'Widget width (1-12 grid columns)',
|
|
'height': 'Widget height in grid rows',
|
|
'display_config': 'JSON configuration for widget display',
|
|
'query_config': 'Query configuration for widget content',
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
user = kwargs.pop('user', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if user:
|
|
self.fields['dashboard'].queryset = Dashboard.objects.filter(
|
|
tenant=user.tenant
|
|
).order_by('name')
|
|
|
|
def clean_position_x(self):
|
|
x = self.cleaned_data['position_x']
|
|
if x < 0 or x > 12:
|
|
raise ValidationError('Position X must be between 0 and 12.')
|
|
return x
|
|
|
|
def clean_width(self):
|
|
width = self.cleaned_data['width']
|
|
if width < 1 or width > 12:
|
|
raise ValidationError('Width must be between 1 and 12.')
|
|
return width
|
|
|
|
|
|
class DataSourceForm(forms.ModelForm):
|
|
"""
|
|
Form for creating and updating data sources.
|
|
"""
|
|
|
|
class Meta:
|
|
model = DataSource
|
|
fields = [
|
|
'name', 'description', 'source_type', 'connection_config',
|
|
'authentication_config', 'query_template', 'cache_duration',
|
|
'is_active'
|
|
]
|
|
widgets = {
|
|
'name': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter data source name'
|
|
}),
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter data source description'
|
|
}),
|
|
'source_type': forms.Select(attrs={'class': 'form-control'}),
|
|
'connection_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Enter JSON connection configuration'
|
|
}),
|
|
'authentication_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter JSON authentication configuration'
|
|
}),
|
|
'query_template': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Enter query template'
|
|
}),
|
|
'cache_duration': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 0,
|
|
'max': 86400,
|
|
'value': 300
|
|
}),
|
|
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
}
|
|
help_texts = {
|
|
'name': 'Unique name for this data source',
|
|
'source_type': 'Type of data source (database, API, file, etc.)',
|
|
'connection_config': 'JSON configuration for connection settings',
|
|
'authentication_config': 'JSON configuration for authentication',
|
|
'cache_duration': 'Cache duration in seconds (0-86400)',
|
|
}
|
|
|
|
def clean_name(self):
|
|
name = self.cleaned_data['name']
|
|
if len(name) < 3:
|
|
raise ValidationError('Data source name must be at least 3 characters long.')
|
|
return name
|
|
|
|
def clean_cache_duration(self):
|
|
cache_duration = self.cleaned_data['cache_duration']
|
|
if cache_duration < 0 or cache_duration > 86400:
|
|
raise ValidationError('Cache duration must be between 0 and 86400 seconds.')
|
|
return cache_duration
|
|
|
|
|
|
class ReportForm(forms.ModelForm):
|
|
"""
|
|
Form for creating and updating reports.
|
|
"""
|
|
|
|
class Meta:
|
|
model = Report
|
|
fields = [
|
|
'name', 'description', 'report_type', 'data_source',
|
|
'query_config', 'output_format', 'template_config',
|
|
'schedule_config', 'is_active'
|
|
]
|
|
widgets = {
|
|
'name': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter report name'
|
|
}),
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter report description'
|
|
}),
|
|
'report_type': forms.Select(attrs={'class': 'form-control'}),
|
|
'data_source': forms.Select(attrs={'class': 'form-control'}),
|
|
'query_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 8,
|
|
'placeholder': 'Enter query configuration'
|
|
}),
|
|
'template_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'Enter JSON template configuration'
|
|
}),
|
|
'output_format': forms.Select(attrs={'class': 'form-control'}),
|
|
'schedule_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter JSON schedule configuration'
|
|
}),
|
|
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
}
|
|
help_texts = {
|
|
'name': 'Unique name for this report',
|
|
'report_type': 'Report type for organization',
|
|
'query_config': 'Query configuration for report data',
|
|
'template_config': 'Template configuration for report formatting',
|
|
'output_format': 'Default output format for report',
|
|
'schedule_config': 'JSON configuration for automated scheduling',
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
user = kwargs.pop('user', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if user:
|
|
self.fields['data_source'].queryset = DataSource.objects.filter(
|
|
tenant=user.tenant,
|
|
is_active=True
|
|
).order_by('name')
|
|
|
|
def clean_report_name(self):
|
|
name = self.cleaned_data['report_name']
|
|
if len(name) < 3:
|
|
raise ValidationError('Report name must be at least 3 characters long.')
|
|
return name
|
|
|
|
def clean_query_definition(self):
|
|
query = self.cleaned_data['query_definition']
|
|
if len(query.strip()) < 10:
|
|
raise ValidationError('Query definition must be at least 10 characters long.')
|
|
return query
|
|
|
|
|
|
class MetricDefinitionForm(forms.ModelForm):
|
|
"""
|
|
Form for creating and updating metric definitions.
|
|
"""
|
|
|
|
class Meta:
|
|
model = MetricDefinition
|
|
fields = [
|
|
'name', 'description', 'metric_type', 'data_source',
|
|
'calculation_config', 'aggregation_period', 'unit_of_measure',
|
|
'target_value', 'warning_threshold', 'critical_threshold',
|
|
'aggregation_config', 'is_active'
|
|
]
|
|
widgets = {
|
|
'name': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Enter metric name'
|
|
}),
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter metric description'
|
|
}),
|
|
'metric_type': forms.Select(attrs={'class': 'form-control'}),
|
|
'data_source': forms.Select(attrs={'class': 'form-control'}),
|
|
'calculation_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 6,
|
|
'placeholder': 'Enter calculation configuration'
|
|
}),
|
|
'aggregation_period': forms.Select(attrs={'class': 'form-control'}),
|
|
'unit_of_measure': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'e.g., %, count, minutes, dollars'
|
|
}),
|
|
'target_value': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'step': 'any',
|
|
'placeholder': 'Target value for this metric'
|
|
}),
|
|
'warning_threshold': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'step': 'any',
|
|
'placeholder': 'Warning threshold value'
|
|
}),
|
|
'critical_threshold': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'step': 'any',
|
|
'placeholder': 'Critical threshold value'
|
|
}),
|
|
'aggregation_config': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Enter aggregation configuration'
|
|
}),
|
|
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
}
|
|
help_texts = {
|
|
'name': 'Unique name for this metric',
|
|
'metric_type': 'Metric type for organization',
|
|
'calculation_config': 'Configuration for metric calculation',
|
|
'aggregation_period': 'Period for metric aggregation',
|
|
'unit_of_measure': 'Unit of measurement for metric values',
|
|
'target_value': 'Target or goal value for this metric',
|
|
'warning_threshold': 'Value that triggers warning alerts',
|
|
'critical_threshold': 'Value that triggers critical alerts',
|
|
'aggregation_config': 'Configuration for metric aggregation',
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
user = kwargs.pop('user', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if user:
|
|
self.fields['data_source'].queryset = DataSource.objects.filter(
|
|
tenant=user.tenant,
|
|
is_active=True
|
|
).order_by('source_name')
|
|
|
|
def clean_metric_name(self):
|
|
name = self.cleaned_data['metric_name']
|
|
if len(name) < 3:
|
|
raise ValidationError('Metric name must be at least 3 characters long.')
|
|
return name
|
|
|
|
def clean_query_definition(self):
|
|
query = self.cleaned_data['query_definition']
|
|
if len(query.strip()) < 5:
|
|
raise ValidationError('Query definition must be at least 5 characters long.')
|
|
return query
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
target = cleaned_data.get('target_value')
|
|
warning = cleaned_data.get('threshold_warning')
|
|
critical = cleaned_data.get('threshold_critical')
|
|
|
|
# Validate threshold relationships
|
|
if target and warning and critical:
|
|
if warning == critical:
|
|
raise ValidationError('Warning and critical thresholds must be different.')
|
|
|
|
return cleaned_data
|
|
|
|
|
|
# from django import forms
|
|
# from django.core.exceptions import ValidationError
|
|
# from django.utils import timezone
|
|
# from crispy_forms.helper import FormHelper
|
|
# from crispy_forms.layout import Layout, Fieldset, Submit, Row, Column, HTML, Div
|
|
# from crispy_forms.bootstrap import FormActions
|
|
# import json
|
|
#
|
|
# from .models import Dashboard, DashboardWidget, DataSource, Report, MetricDefinition
|
|
# from core.models import Tenant
|
|
#
|
|
#
|
|
# class ReportGenerationForm(forms.ModelForm):
|
|
# """
|
|
# Form for report generation configuration
|
|
# """
|
|
# parameters = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4})
|
|
# )
|
|
# output_format = forms.ChoiceField(
|
|
# choices=[
|
|
# ('pdf', 'PDF'),
|
|
# ('excel', 'Excel'),
|
|
# ('csv', 'CSV'),
|
|
# ('json', 'JSON')
|
|
# ],
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# schedule_execution = forms.BooleanField(
|
|
# required=False,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# execution_time = forms.DateTimeField(
|
|
# required=False,
|
|
# widget=forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'})
|
|
# )
|
|
# email_recipients = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
|
|
# )
|
|
#
|
|
# class Meta:
|
|
# model = Report
|
|
# fields = [
|
|
# 'name', 'description', 'report_type', 'data_sources',
|
|
# 'parameters', 'output_format', 'schedule_execution',
|
|
# 'execution_time', 'email_recipients'
|
|
# ]
|
|
# widgets = {
|
|
# 'name': forms.TextInput(attrs={'class': 'form-control'}),
|
|
# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
|
# 'report_type': forms.Select(attrs={'class': 'form-control'}),
|
|
# 'data_sources': forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'})
|
|
# }
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# tenant = kwargs.pop('tenant', None)
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# if tenant:
|
|
# self.fields['data_sources'].queryset = DataSource.objects.filter(tenant=tenant)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Report Configuration',
|
|
# Row(
|
|
# Column('name', css_class='form-group col-md-6 mb-0'),
|
|
# Column('report_type', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'description',
|
|
# 'data_sources',
|
|
# 'parameters'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Output Settings',
|
|
# Row(
|
|
# Column('output_format', css_class='form-group col-md-6 mb-0'),
|
|
# Column('email_recipients', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# )
|
|
# ),
|
|
# Fieldset(
|
|
# 'Scheduling',
|
|
# HTML('<div class="form-check">'),
|
|
# 'schedule_execution',
|
|
# HTML(
|
|
# '<label class="form-check-label" for="id_schedule_execution">Schedule for later execution</label>'),
|
|
# HTML('</div>'),
|
|
# 'execution_time'
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Generate Report', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:report_list\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
# def clean_parameters(self):
|
|
# parameters = self.cleaned_data.get('parameters')
|
|
# if parameters:
|
|
# try:
|
|
# json.loads(parameters)
|
|
# except json.JSONDecodeError:
|
|
# raise ValidationError('Parameters must be valid JSON.')
|
|
# return parameters
|
|
#
|
|
# def clean(self):
|
|
# cleaned_data = super().clean()
|
|
# schedule_execution = cleaned_data.get('schedule_execution')
|
|
# execution_time = cleaned_data.get('execution_time')
|
|
#
|
|
# if schedule_execution and not execution_time:
|
|
# raise ValidationError('Execution time is required when scheduling execution.')
|
|
#
|
|
# return cleaned_data
|
|
#
|
|
#
|
|
# class DashboardCreationForm(forms.ModelForm):
|
|
# """
|
|
# Form for dashboard creation
|
|
# """
|
|
# layout_template = forms.ChoiceField(
|
|
# choices=[
|
|
# ('grid_2x2', '2x2 Grid'),
|
|
# ('grid_3x3', '3x3 Grid'),
|
|
# ('sidebar_main', 'Sidebar + Main'),
|
|
# ('top_bottom', 'Top + Bottom'),
|
|
# ('custom', 'Custom Layout')
|
|
# ],
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# copy_from_dashboard = forms.ModelChoiceField(
|
|
# queryset=None,
|
|
# required=False,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
#
|
|
# class Meta:
|
|
# model = Dashboard
|
|
# fields = [
|
|
# 'name', 'description', 'dashboard_type', 'layout_template',
|
|
# 'refresh_interval', 'is_public', 'allowed_roles',
|
|
# 'copy_from_dashboard'
|
|
# ]
|
|
# widgets = {
|
|
# 'name': forms.TextInput(attrs={'class': 'form-control'}),
|
|
# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
|
# 'dashboard_type': forms.Select(attrs={'class': 'form-control'}),
|
|
# 'refresh_interval': forms.NumberInput(attrs={'class': 'form-control'}),
|
|
# 'is_public': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
|
# 'allowed_roles': forms.Textarea(attrs={'class': 'form-control', 'rows': 2})
|
|
# }
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# tenant = kwargs.pop('tenant', None)
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# if tenant:
|
|
# self.fields['copy_from_dashboard'].queryset = Dashboard.objects.filter(
|
|
# tenant=tenant,
|
|
# is_active=True
|
|
# )
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Dashboard Information',
|
|
# Row(
|
|
# Column('name', css_class='form-group col-md-6 mb-0'),
|
|
# Column('dashboard_type', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'description'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Layout Configuration',
|
|
# Row(
|
|
# Column('layout_template', css_class='form-group col-md-6 mb-0'),
|
|
# Column('refresh_interval', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'copy_from_dashboard'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Access Control',
|
|
# HTML('<div class="form-check">'),
|
|
# 'is_public',
|
|
# HTML('<label class="form-check-label" for="id_is_public">Make dashboard public</label>'),
|
|
# HTML('</div>'),
|
|
# 'allowed_roles'
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Create Dashboard', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:dashboard_list\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
#
|
|
# class DataSourceConfigurationForm(forms.ModelForm):
|
|
# """
|
|
# Form for data source configuration
|
|
# """
|
|
# test_connection = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
#
|
|
# class Meta:
|
|
# model = DataSource
|
|
# fields = [
|
|
# 'name', 'description', 'source_type', 'connection_config',
|
|
# 'query_config', 'refresh_interval', 'is_active',
|
|
# 'test_connection'
|
|
# ]
|
|
# widgets = {
|
|
# 'name': forms.TextInput(attrs={'class': 'form-control'}),
|
|
# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
|
# 'source_type': forms.Select(attrs={'class': 'form-control'}),
|
|
# 'connection_config': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
|
|
# 'query_config': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
|
|
# 'refresh_interval': forms.NumberInput(attrs={'class': 'form-control'}),
|
|
# 'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# }
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Data Source Information',
|
|
# Row(
|
|
# Column('name', css_class='form-group col-md-6 mb-0'),
|
|
# Column('source_type', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'description'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Connection Configuration',
|
|
# 'connection_config',
|
|
# HTML('<small class="form-text text-muted">Enter connection details in JSON format</small>')
|
|
# ),
|
|
# Fieldset(
|
|
# 'Query Configuration',
|
|
# 'query_config',
|
|
# HTML('<small class="form-text text-muted">Enter query configuration in JSON format</small>')
|
|
# ),
|
|
# Fieldset(
|
|
# 'Settings',
|
|
# Row(
|
|
# Column('refresh_interval', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# HTML('<div class="form-check">'),
|
|
# 'is_active',
|
|
# HTML('<label class="form-check-label" for="id_is_active">Active</label>'),
|
|
# HTML('</div>'),
|
|
# HTML('<div class="form-check">'),
|
|
# 'test_connection',
|
|
# HTML('<label class="form-check-label" for="id_test_connection">Test connection after saving</label>'),
|
|
# HTML('</div>')
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Save Data Source', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:data_source_list\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
# def clean_connection_config(self):
|
|
# config = self.cleaned_data.get('connection_config')
|
|
# if config:
|
|
# try:
|
|
# json.loads(config)
|
|
# except json.JSONDecodeError:
|
|
# raise ValidationError('Connection configuration must be valid JSON.')
|
|
# return config
|
|
#
|
|
# def clean_query_config(self):
|
|
# config = self.cleaned_data.get('query_config')
|
|
# if config:
|
|
# try:
|
|
# json.loads(config)
|
|
# except json.JSONDecodeError:
|
|
# raise ValidationError('Query configuration must be valid JSON.')
|
|
# return config
|
|
#
|
|
#
|
|
# class MetricCalculationForm(forms.ModelForm):
|
|
# """
|
|
# Form for metric calculation configuration
|
|
# """
|
|
# calculate_now = forms.BooleanField(
|
|
# required=False,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# date_range_start = forms.DateField(
|
|
# required=False,
|
|
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
|
|
# )
|
|
# date_range_end = forms.DateField(
|
|
# required=False,
|
|
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
|
|
# )
|
|
#
|
|
# class Meta:
|
|
# model = MetricDefinition
|
|
# fields = [
|
|
# 'name', 'description', 'metric_type', 'data_source',
|
|
# 'calculation_config', 'aggregation_period', 'target_value',
|
|
# 'warning_threshold', 'critical_threshold', 'unit_of_measure',
|
|
# 'calculate_now', 'date_range_start', 'date_range_end'
|
|
# ]
|
|
# widgets = {
|
|
# 'name': forms.TextInput(attrs={'class': 'form-control'}),
|
|
# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
|
# 'metric_type': forms.Select(attrs={'class': 'form-control'}),
|
|
# 'data_source': forms.Select(attrs={'class': 'form-control'}),
|
|
# 'calculation_config': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
|
|
# 'aggregation_period': forms.Select(attrs={'class': 'form-control'}),
|
|
# 'target_value': forms.NumberInput(attrs={'class': 'form-control'}),
|
|
# 'warning_threshold': forms.NumberInput(attrs={'class': 'form-control'}),
|
|
# 'critical_threshold': forms.NumberInput(attrs={'class': 'form-control'}),
|
|
# 'unit_of_measure': forms.TextInput(attrs={'class': 'form-control'})
|
|
# }
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# tenant = kwargs.pop('tenant', None)
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# if tenant:
|
|
# self.fields['data_source'].queryset = DataSource.objects.filter(tenant=tenant)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Metric Definition',
|
|
# Row(
|
|
# Column('name', css_class='form-group col-md-6 mb-0'),
|
|
# Column('metric_type', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'description',
|
|
# Row(
|
|
# Column('data_source', css_class='form-group col-md-6 mb-0'),
|
|
# Column('aggregation_period', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'calculation_config'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Thresholds and Targets',
|
|
# Row(
|
|
# Column('target_value', css_class='form-group col-md-4 mb-0'),
|
|
# Column('warning_threshold', css_class='form-group col-md-4 mb-0'),
|
|
# Column('critical_threshold', css_class='form-group col-md-4 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'unit_of_measure'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Calculation Options',
|
|
# HTML('<div class="form-check">'),
|
|
# 'calculate_now',
|
|
# HTML('<label class="form-check-label" for="id_calculate_now">Calculate metric immediately</label>'),
|
|
# HTML('</div>'),
|
|
# Row(
|
|
# Column('date_range_start', css_class='form-group col-md-6 mb-0'),
|
|
# Column('date_range_end', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# )
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Save Metric', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:metric_list\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
# def clean_calculation_config(self):
|
|
# config = self.cleaned_data.get('calculation_config')
|
|
# if config:
|
|
# try:
|
|
# json.loads(config)
|
|
# except json.JSONDecodeError:
|
|
# raise ValidationError('Calculation configuration must be valid JSON.')
|
|
# return config
|
|
#
|
|
#
|
|
# class QualityAssuranceForm(forms.Form):
|
|
# """
|
|
# Form for quality assurance configuration
|
|
# """
|
|
# check_data_accuracy = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# validate_calculations = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# verify_data_sources = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# check_performance = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# generate_qa_report = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# qa_threshold = forms.DecimalField(
|
|
# max_digits=5,
|
|
# decimal_places=2,
|
|
# initial=95.0,
|
|
# widget=forms.NumberInput(attrs={'class': 'form-control'})
|
|
# )
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Quality Assurance Checks',
|
|
# HTML('<div class="form-check">'),
|
|
# 'check_data_accuracy',
|
|
# HTML('<label class="form-check-label" for="id_check_data_accuracy">Check Data Accuracy</label>'),
|
|
# HTML('</div>'),
|
|
# HTML('<div class="form-check">'),
|
|
# 'validate_calculations',
|
|
# HTML('<label class="form-check-label" for="id_validate_calculations">Validate Calculations</label>'),
|
|
# HTML('</div>'),
|
|
# HTML('<div class="form-check">'),
|
|
# 'verify_data_sources',
|
|
# HTML('<label class="form-check-label" for="id_verify_data_sources">Verify Data Sources</label>'),
|
|
# HTML('</div>'),
|
|
# HTML('<div class="form-check">'),
|
|
# 'check_performance',
|
|
# HTML('<label class="form-check-label" for="id_check_performance">Check Performance</label>'),
|
|
# HTML('</div>'),
|
|
# HTML('<div class="form-check">'),
|
|
# 'generate_qa_report',
|
|
# HTML('<label class="form-check-label" for="id_generate_qa_report">Generate QA Report</label>'),
|
|
# HTML('</div>')
|
|
# ),
|
|
# Fieldset(
|
|
# 'Quality Threshold',
|
|
# 'qa_threshold',
|
|
# HTML('<small class="form-text text-muted">Minimum quality score percentage (0-100)</small>')
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Start Quality Check', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:dashboard\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
#
|
|
# class DistributionForm(forms.Form):
|
|
# """
|
|
# Form for report distribution configuration
|
|
# """
|
|
# distribution_method = forms.ChoiceField(
|
|
# choices=[
|
|
# ('email', 'Email'),
|
|
# ('download', 'Download Link'),
|
|
# ('ftp', 'FTP Upload'),
|
|
# ('api', 'API Endpoint'),
|
|
# ('dashboard', 'Dashboard Publication')
|
|
# ],
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# recipients = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4})
|
|
# )
|
|
# subject = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.TextInput(attrs={'class': 'form-control'})
|
|
# )
|
|
# message = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4})
|
|
# )
|
|
# schedule_distribution = forms.BooleanField(
|
|
# required=False,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# distribution_time = forms.DateTimeField(
|
|
# required=False,
|
|
# widget=forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'})
|
|
# )
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Distribution Method',
|
|
# 'distribution_method',
|
|
# 'recipients',
|
|
# HTML('<small class="form-text text-muted">Enter email addresses separated by commas</small>')
|
|
# ),
|
|
# Fieldset(
|
|
# 'Message Content',
|
|
# 'subject',
|
|
# 'message'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Scheduling',
|
|
# HTML('<div class="form-check">'),
|
|
# 'schedule_distribution',
|
|
# HTML('<label class="form-check-label" for="id_schedule_distribution">Schedule distribution</label>'),
|
|
# HTML('</div>'),
|
|
# 'distribution_time'
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Distribute Report', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:report_list\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
# def clean(self):
|
|
# cleaned_data = super().clean()
|
|
# distribution_method = cleaned_data.get('distribution_method')
|
|
# recipients = cleaned_data.get('recipients')
|
|
# schedule_distribution = cleaned_data.get('schedule_distribution')
|
|
# distribution_time = cleaned_data.get('distribution_time')
|
|
#
|
|
# if distribution_method == 'email' and not recipients:
|
|
# raise ValidationError('Recipients are required for email distribution.')
|
|
#
|
|
# if schedule_distribution and not distribution_time:
|
|
# raise ValidationError('Distribution time is required when scheduling distribution.')
|
|
#
|
|
# return cleaned_data
|
|
#
|
|
#
|
|
# class VisualizationForm(forms.Form):
|
|
# """
|
|
# Form for visualization configuration
|
|
# """
|
|
# chart_type = forms.ChoiceField(
|
|
# choices=[
|
|
# ('line', 'Line Chart'),
|
|
# ('bar', 'Bar Chart'),
|
|
# ('pie', 'Pie Chart'),
|
|
# ('scatter', 'Scatter Plot'),
|
|
# ('heatmap', 'Heat Map'),
|
|
# ('gauge', 'Gauge'),
|
|
# ('table', 'Data Table')
|
|
# ],
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# title = forms.CharField(
|
|
# required=True,
|
|
# widget=forms.TextInput(attrs={'class': 'form-control'})
|
|
# )
|
|
# x_axis_label = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.TextInput(attrs={'class': 'form-control'})
|
|
# )
|
|
# y_axis_label = forms.CharField(
|
|
# required=False,
|
|
# widget=forms.TextInput(attrs={'class': 'form-control'})
|
|
# )
|
|
# color_scheme = forms.ChoiceField(
|
|
# choices=[
|
|
# ('default', 'Default'),
|
|
# ('blue', 'Blue Theme'),
|
|
# ('green', 'Green Theme'),
|
|
# ('red', 'Red Theme'),
|
|
# ('purple', 'Purple Theme'),
|
|
# ('custom', 'Custom Colors')
|
|
# ],
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# show_legend = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
# show_grid = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Chart Configuration',
|
|
# Row(
|
|
# Column('chart_type', css_class='form-group col-md-6 mb-0'),
|
|
# Column('color_scheme', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'title'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Axis Labels',
|
|
# Row(
|
|
# Column('x_axis_label', css_class='form-group col-md-6 mb-0'),
|
|
# Column('y_axis_label', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# )
|
|
# ),
|
|
# Fieldset(
|
|
# 'Display Options',
|
|
# HTML('<div class="form-check">'),
|
|
# 'show_legend',
|
|
# HTML('<label class="form-check-label" for="id_show_legend">Show Legend</label>'),
|
|
# HTML('</div>'),
|
|
# HTML('<div class="form-check">'),
|
|
# 'show_grid',
|
|
# HTML('<label class="form-check-label" for="id_show_grid">Show Grid</label>'),
|
|
# HTML('</div>')
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Create Visualization', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:dashboard\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|
|
#
|
|
# class AnalysisForm(forms.Form):
|
|
# """
|
|
# Form for data analysis configuration
|
|
# """
|
|
# analysis_type = forms.ChoiceField(
|
|
# choices=[
|
|
# ('descriptive', 'Descriptive Analysis'),
|
|
# ('trend', 'Trend Analysis'),
|
|
# ('correlation', 'Correlation Analysis'),
|
|
# ('regression', 'Regression Analysis'),
|
|
# ('forecasting', 'Forecasting'),
|
|
# ('anomaly', 'Anomaly Detection')
|
|
# ],
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# data_source = forms.ModelChoiceField(
|
|
# queryset=None,
|
|
# required=True,
|
|
# widget=forms.Select(attrs={'class': 'form-control'})
|
|
# )
|
|
# date_range_start = forms.DateField(
|
|
# required=True,
|
|
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
|
|
# )
|
|
# date_range_end = forms.DateField(
|
|
# required=True,
|
|
# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
|
|
# )
|
|
# confidence_level = forms.DecimalField(
|
|
# max_digits=5,
|
|
# decimal_places=2,
|
|
# initial=95.0,
|
|
# widget=forms.NumberInput(attrs={'class': 'form-control'})
|
|
# )
|
|
# generate_insights = forms.BooleanField(
|
|
# required=False,
|
|
# initial=True,
|
|
# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
|
|
# )
|
|
#
|
|
# def __init__(self, *args, **kwargs):
|
|
# tenant = kwargs.pop('tenant', None)
|
|
# super().__init__(*args, **kwargs)
|
|
#
|
|
# if tenant:
|
|
# self.fields['data_source'].queryset = DataSource.objects.filter(tenant=tenant)
|
|
#
|
|
# self.helper = FormHelper()
|
|
# self.helper.layout = Layout(
|
|
# Fieldset(
|
|
# 'Analysis Configuration',
|
|
# Row(
|
|
# Column('analysis_type', css_class='form-group col-md-6 mb-0'),
|
|
# Column('data_source', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# Row(
|
|
# Column('date_range_start', css_class='form-group col-md-6 mb-0'),
|
|
# Column('date_range_end', css_class='form-group col-md-6 mb-0'),
|
|
# css_class='form-row'
|
|
# ),
|
|
# 'confidence_level'
|
|
# ),
|
|
# Fieldset(
|
|
# 'Options',
|
|
# HTML('<div class="form-check">'),
|
|
# 'generate_insights',
|
|
# HTML('<label class="form-check-label" for="id_generate_insights">Generate Insights</label>'),
|
|
# HTML('</div>')
|
|
# ),
|
|
# FormActions(
|
|
# Submit('submit', 'Start Analysis', css_class='btn btn-primary'),
|
|
# HTML('<a href="{% url \'analytics:dashboard\' %}" class="btn btn-secondary">Cancel</a>')
|
|
# )
|
|
# )
|
|
#
|