diff --git a/apps/analysis/enums.py b/apps/analysis/enums.py index e52ea30d84..41111c31a8 100644 --- a/apps/analysis/enums.py +++ b/apps/analysis/enums.py @@ -19,6 +19,13 @@ AnalysisReportBorderStyleSerializer, AnalysisReportImageContentStyleSerializer, AnalysisReportHeadingConfigurationSerializer, + AnalysisReportHorizontalAxisSerializer, + AnalysisReportVerticalAxisSerializer, + AnalysisReportBarChartConfigurationSerializer, + AnalysisReportCategoricalLegendStyleSerializer, + AnalysisReportMapLayerConfigurationSerializer, + AnalysisReportSymbolLayerConfigurationSerializer, + AnalysisReportLineLayerStyleSerializer, ) @@ -50,6 +57,26 @@ ReportEnum.ImageContentStyleFit, name='AnalysisReportImageContentStyleFitEnum') AnalysisReportHeadingConfigurationVariantEnum = convert_enum_to_graphene_enum( ReportEnum.HeadingConfigurationVariant, name='AnalysisReportHeadingConfigurationVariantEnum') +AnalysisReportHorizontalAxisTypeEnum = convert_enum_to_graphene_enum( + ReportEnum.HorizontalAxisType, name='AnalysisReportHorizontalAxisTypeEnum') +AnalysisReportBarChartTypeEnum = convert_enum_to_graphene_enum( + ReportEnum.BarChartType, name='AnalysisReportBarChartTypeEnum') +AnalysisReportBarChartDirectionEnum = convert_enum_to_graphene_enum( + ReportEnum.BarChartDirection, name='AnalysisReportBarChartDirectionEnum') +AnalysisReportLegendPositionEnum = convert_enum_to_graphene_enum( + ReportEnum.LegendPosition, name='AnalysisReportLegendPositionEnum') +AnalysisReportLegendDotShapeEnum = convert_enum_to_graphene_enum( + ReportEnum.LegendDotShape, name='AnalysisReportLegendDotShapeEnum') +AnalysisReportAggregationTypeEnum = convert_enum_to_graphene_enum( + ReportEnum.AggregationType, name='AnalysisReportAggregationTypeEnum') +AnalysisReportMapLayerTypeEnum = convert_enum_to_graphene_enum( + ReportEnum.MapLayerType, name='AnalysisReportMapLayerTypeEnum') +AnalysisReportScaleTypeEnum = convert_enum_to_graphene_enum( + ReportEnum.ScaleType, name='AnalysisReportScaleTypeEnum') +AnalysisReportScalingTechniqueEnum = convert_enum_to_graphene_enum( + ReportEnum.ScalingTechnique, name='AnalysisReportScalingTechniqueEnum') +AnalysisReportLineLayerStrokeTypeEnum = convert_enum_to_graphene_enum( + ReportEnum.LineLayerStrokeType, name='AnalysisReportLineLayerStrokeTypeEnum') # Model field mapping enum_map = { @@ -75,5 +102,15 @@ (AnalysisReportBorderStyleSerializer, 'style', AnalysisReportBorderStyleStyleEnum), (AnalysisReportImageContentStyleSerializer, 'fit', AnalysisReportImageContentStyleFitEnum), (AnalysisReportHeadingConfigurationSerializer, 'variant', AnalysisReportHeadingConfigurationVariantEnum), + (AnalysisReportHorizontalAxisSerializer, 'type', AnalysisReportHorizontalAxisTypeEnum), + (AnalysisReportBarChartConfigurationSerializer, 'type', AnalysisReportBarChartTypeEnum), + (AnalysisReportBarChartConfigurationSerializer, 'direction', AnalysisReportBarChartDirectionEnum), + (AnalysisReportCategoricalLegendStyleSerializer, 'position', AnalysisReportLegendPositionEnum), + (AnalysisReportCategoricalLegendStyleSerializer, 'shape', AnalysisReportLegendDotShapeEnum), + (AnalysisReportVerticalAxisSerializer, 'aggregation_type', AnalysisReportAggregationTypeEnum), + (AnalysisReportMapLayerConfigurationSerializer, 'type', AnalysisReportMapLayerTypeEnum), + (AnalysisReportSymbolLayerConfigurationSerializer, 'scale_type', AnalysisReportScaleTypeEnum), + (AnalysisReportSymbolLayerConfigurationSerializer, 'scaling_technique', AnalysisReportScalingTechniqueEnum), + (AnalysisReportLineLayerStyleSerializer, 'stroke_type', AnalysisReportLineLayerStrokeTypeEnum), ] }) diff --git a/apps/analysis/filter_set.py b/apps/analysis/filter_set.py index 639b9a1812..67794b52c9 100644 --- a/apps/analysis/filter_set.py +++ b/apps/analysis/filter_set.py @@ -130,6 +130,7 @@ def search_filter(self, qs, _, value): class AnalysisReportUploadGQFilterSet(django_filters.FilterSet): + search = django_filters.CharFilter(method='search_filter') report = IDListFilter(field_name='report') types = MultipleInputFilter(AnalysisReportUploadTypeEnum, field_name='type') @@ -137,6 +138,13 @@ class Meta: model = AnalysisReportUpload fields = [] + def search_filter(self, qs, _, value): + if value: + qs = qs.filter( + models.Q(file__title__icontains=value) + ).distinct() + return qs + class AnalysisReportSnapshotGQFilterSet(django_filters.FilterSet): report = IDListFilter(field_name='report') diff --git a/apps/analysis/migrations/0013_alter_analysisreportcontainer_content_type.py b/apps/analysis/migrations/0013_alter_analysisreportcontainer_content_type.py new file mode 100644 index 0000000000..1b02948422 --- /dev/null +++ b/apps/analysis/migrations/0013_alter_analysisreportcontainer_content_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2024-03-06 05:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('analysis', '0012_remove_analysisreportcontainer_content_style'), + ] + + operations = [ + migrations.AlterField( + model_name='analysisreportcontainer', + name='content_type', + field=models.SmallIntegerField(choices=[(1, 'Text'), (2, 'Heading'), (3, 'Image'), (4, 'URL'), (5, 'Timeline Chart'), (6, 'KPIs'), (7, 'Bar Chart')]), + ), + ] diff --git a/apps/analysis/migrations/0013_alter_analysisreportcontainer_content_type_squashed_0017_merge_20240318_0519.py b/apps/analysis/migrations/0013_alter_analysisreportcontainer_content_type_squashed_0017_merge_20240318_0519.py new file mode 100644 index 0000000000..495546c3fd --- /dev/null +++ b/apps/analysis/migrations/0013_alter_analysisreportcontainer_content_type_squashed_0017_merge_20240318_0519.py @@ -0,0 +1,58 @@ +# Generated by Django 3.2.25 on 2024-04-26 09:14 + +from django.db import migrations, models + + +# Functions from the following migrations need manual copying. +# Move them and any dependencies into this file, then update the +# RunPython operations to refer to the local versions: +# analysis.migrations.0015_analysisreportcontainerdata_client_reference_id + +class Migration(migrations.Migration): + + replaces = [ + ('analysis', '0013_alter_analysisreportcontainer_content_type'), + ('analysis', '0014_alter_analysisreportcontainer_content_type'), + ('analysis', '0015_analysisreportcontainerdata_client_reference_id'), + ('analysis', '0016_alter_analysisreportcontainer_content_type'), + ('analysis', '0013_auto_20240315_0501'), + ('analysis', '0017_merge_20240318_0519'), + ] + + dependencies = [ + ('analysis', '0012_remove_analysisreportcontainer_content_style'), + ] + + operations = [ + migrations.AlterField( + model_name='analysisreportcontainer', + name='content_type', + field=models.SmallIntegerField(choices=[(1, 'Text'), (2, 'Heading'), (3, 'Image'), (4, 'URL'), (5, 'Timeline Chart'), (6, 'KPIs'), (7, 'Bar Chart')]), + ), + migrations.AlterField( + model_name='analysisreportcontainer', + name='content_type', + field=models.SmallIntegerField(choices=[(1, 'Text'), (2, 'Heading'), (3, 'Image'), (4, 'URL'), (5, 'Timeline Chart'), (6, 'KPIs'), (7, 'Bar Chart'), (8, 'Map')]), + ), + migrations.AddField( + model_name='analysisreportcontainerdata', + name='client_reference_id', + field=models.CharField(max_length=20), + preserve_default=False, + ), + migrations.AlterField( + model_name='analysisreportcontainer', + name='content_type', + field=models.SmallIntegerField(choices=[(1, 'Text'), (2, 'Heading'), (3, 'Image'), (4, 'URL'), (5, 'Timeline Chart'), (6, 'KPIs'), (7, 'Bar Chart'), (8, 'Map'), (9, 'Line Chart')]), + ), + migrations.AddField( + model_name='analyticalstatement', + name='title', + field=models.CharField(blank=True, max_length=150), + ), + migrations.AddField( + model_name='topicmodelcluster', + name='title', + field=models.CharField(blank=True, max_length=150), + ), + ] diff --git a/apps/analysis/migrations/0014_alter_analysisreportcontainer_content_type.py b/apps/analysis/migrations/0014_alter_analysisreportcontainer_content_type.py new file mode 100644 index 0000000000..4477bbafdf --- /dev/null +++ b/apps/analysis/migrations/0014_alter_analysisreportcontainer_content_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2024-03-08 10:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('analysis', '0013_alter_analysisreportcontainer_content_type'), + ] + + operations = [ + migrations.AlterField( + model_name='analysisreportcontainer', + name='content_type', + field=models.SmallIntegerField(choices=[(1, 'Text'), (2, 'Heading'), (3, 'Image'), (4, 'URL'), (5, 'Timeline Chart'), (6, 'KPIs'), (7, 'Bar Chart'), (8, 'Map')]), + ), + ] diff --git a/apps/analysis/migrations/0015_analysisreportcontainerdata_client_reference_id.py b/apps/analysis/migrations/0015_analysisreportcontainerdata_client_reference_id.py new file mode 100644 index 0000000000..edd324e55a --- /dev/null +++ b/apps/analysis/migrations/0015_analysisreportcontainerdata_client_reference_id.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.17 on 2024-03-11 08:56 + +from django.utils.crypto import get_random_string +from django.db import migrations, models + + +def generate_random_reference_id(): + return get_random_string(length=16) + + +class Migration(migrations.Migration): + + dependencies = [ + ('analysis', '0014_alter_analysisreportcontainer_content_type'), + ] + + operations = [ + migrations.AddField( + model_name='analysisreportcontainerdata', + name='client_reference_id', + # NOTE: This will not generate random values, we don't have much data before this migrations. + # So, for now just ignoring. + field=models.CharField(default=generate_random_reference_id, max_length=20), + preserve_default=False, + ), + ] diff --git a/apps/analysis/migrations/0016_alter_analysisreportcontainer_content_type.py b/apps/analysis/migrations/0016_alter_analysisreportcontainer_content_type.py new file mode 100644 index 0000000000..9085bb148c --- /dev/null +++ b/apps/analysis/migrations/0016_alter_analysisreportcontainer_content_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2024-03-12 13:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('analysis', '0015_analysisreportcontainerdata_client_reference_id'), + ] + + operations = [ + migrations.AlterField( + model_name='analysisreportcontainer', + name='content_type', + field=models.SmallIntegerField(choices=[(1, 'Text'), (2, 'Heading'), (3, 'Image'), (4, 'URL'), (5, 'Timeline Chart'), (6, 'KPIs'), (7, 'Bar Chart'), (8, 'Map'), (9, 'Line Chart')]), + ), + ] diff --git a/apps/analysis/migrations/0017_merge_20240318_0519.py b/apps/analysis/migrations/0017_merge_20240318_0519.py new file mode 100644 index 0000000000..ec66197ad8 --- /dev/null +++ b/apps/analysis/migrations/0017_merge_20240318_0519.py @@ -0,0 +1,14 @@ +# Generated by Django 3.2.17 on 2024-03-18 05:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('analysis', '0013_auto_20240315_0501'), + ('analysis', '0016_alter_analysisreportcontainer_content_type'), + ] + + operations = [ + ] diff --git a/apps/analysis/models.py b/apps/analysis/models.py index f9c7edf291..3ff9ee39c0 100644 --- a/apps/analysis/models.py +++ b/apps/analysis/models.py @@ -601,6 +601,11 @@ class ContentType(models.IntegerChoices): HEADING = 2, 'Heading' IMAGE = 3, 'Image' URL = 4, 'URL' + TIMELINE_CHART = 5, 'Timeline Chart' + KPI = 6, 'KPIs' + BAR_CHART = 7, 'Bar Chart' + MAP = 8, 'Map' + LINE_CHART = 9, 'Line Chart' report = models.ForeignKey(AnalysisReport, on_delete=models.CASCADE) row = models.SmallIntegerField() @@ -616,6 +621,8 @@ class ContentType(models.IntegerChoices): class AnalysisReportContainerData(models.Model): container = models.ForeignKey(AnalysisReportContainer, on_delete=models.CASCADE) upload = models.ForeignKey(AnalysisReportUpload, on_delete=models.PROTECT) + # NOTE: This is used by client for internal references in JSON data + client_reference_id = models.CharField(max_length=20) # Generic for now. Client will define this later data = models.JSONField(default=dict) diff --git a/apps/analysis/schema.py b/apps/analysis/schema.py index a77c6bb04b..d81d6bcc8c 100644 --- a/apps/analysis/schema.py +++ b/apps/analysis/schema.py @@ -587,6 +587,7 @@ class Meta: 'id', 'upload', # AnalysisReportUploadType 'data', # NOTE: This is Generic for now + 'client_reference_id', ) @staticmethod diff --git a/apps/analysis/serializers.py b/apps/analysis/serializers.py index e7a540dac2..3026f77205 100644 --- a/apps/analysis/serializers.py +++ b/apps/analysis/serializers.py @@ -550,6 +550,7 @@ class VariableType(models.TextChoices): TEXT = 'text' NUMBER = 'number' DATE = 'date' + BOOLEAN = 'boolean' class TextStyleAlign(models.TextChoices): START = 'start' @@ -577,9 +578,63 @@ class HeadingConfigurationVariant(models.TextChoices): H3 = 'h3' H4 = 'h4' + class HorizontalAxisType(models.TextChoices): + CATEGORICAL = 'categorical' + NUMERIC = 'numeric' + DATE = 'date' + + class BarChartType(models.TextChoices): + SIDE_BY_SIDE = 'side-by-side' + STACKED = 'stacked' + + class BarChartDirection(models.TextChoices): + VERTICAL = 'vertical' + HORIZONTAL = 'horizontal' + + class LegendPosition(models.TextChoices): + TOP = 'top' + LEFT = 'left' + BOTTOM = 'bottom' + RIGHT = 'right' + + class LegendDotShape(models.TextChoices): + CIRCLE = 'circle' + TRIANGLE = 'triangle' + SQUARE = 'square' + DIAMOND = 'diamond' + + class AggregationType(models.TextChoices): + COUNT = 'count' + SUM = 'sum' + MEAN = 'mean' + MEDIAN = 'median' + MIN = 'min' + MAX = 'max' + + class ScaleType(models.TextChoices): + FIXED = 'fixed' + PROPORTIONAL = 'proportional' + + class ScalingTechnique(models.TextChoices): + ABSOLUTE = 'absolute' + FLANNERY = 'flannery' + + class MapLayerType(models.TextChoices): + OSM_LAYER = 'OSM Layer' + MAPBOX_LAYER = 'Mapbox Layer' + SYMBOL_LAYER = 'Symbol Layer' + POLYGON_LAYER = 'Polygon Layer' + LINE_LAYER = 'Line Layer' + HEAT_MAP_LAYER = 'Heatmap Layer' + + class LineLayerStrokeType(models.TextChoices): + DASH = 'dash' + SOLID = 'solid' + class AnalysisReportVariableSerializer(serializers.Serializer): name = serializers.CharField(required=False, allow_null=True) + client_id = serializers.CharField(required=False) type = serializers.ChoiceField(choices=ReportEnum.VariableType.choices, required=False, allow_null=True) completeness = serializers.IntegerField(required=False, allow_null=True) @@ -592,6 +647,14 @@ class AnalysisReportTextStyleSerializer(serializers.Serializer): align = serializers.ChoiceField(choices=ReportEnum.TextStyleAlign.choices, required=False, allow_null=True) +class AnalysisReportLineLayerStyleSerializer(serializers.Serializer): + dash_spacing = serializers.IntegerField(required=False, allow_null=True) + stroke = serializers.CharField(required=False, allow_null=True) + # NOTE: Might need to change this later to enum + stroke_type = serializers.ChoiceField(choices=ReportEnum.LineLayerStrokeType.choices, required=False, allow_null=True) + stroke_width = serializers.IntegerField(required=False, allow_null=True) + + class AnalysisReportMarginStyleSerializer(serializers.Serializer): top = serializers.IntegerField(required=False, allow_null=True) bottom = serializers.IntegerField(required=False, allow_null=True) @@ -677,6 +740,177 @@ class AnalysisReportUrlConfigurationSerializer(serializers.Serializer): url = serializers.CharField(required=False, allow_null=True) +class AnalysisReportKpiItemStyleConfigurationSerializer(serializers.Serializer): + title_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + subtitle_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + source_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + value_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportKpiItemConfigurationSerializer(serializers.Serializer): + title = serializers.CharField(required=False, allow_null=True) + subtitle = serializers.CharField(required=False, allow_null=True) + source = serializers.CharField(required=False, allow_null=True) + source_url = serializers.CharField(required=False, allow_null=True) + color = serializers.CharField(required=False, allow_null=True) + date = serializers.DateField(required=False, allow_null=True) + value = serializers.IntegerField(required=False, allow_null=True) + client_id = serializers.CharField(required=False, allow_null=True) + abbreviate_value = serializers.BooleanField(required=False, allow_null=True) + style = AnalysisReportKpiItemStyleConfigurationSerializer(required=False, allow_null=True) + + def validate_date(self, date): + if date: + return date.isoformat() + + +class AnalysisReportCategoricalLegendStyleSerializer(serializers.Serializer): + position = serializers.ChoiceField(choices=ReportEnum.LegendPosition.choices, required=False, allow_null=True) + shape = serializers.ChoiceField(choices=ReportEnum.LegendDotShape.choices, required=False, allow_null=True) + heading = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + label = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportBarStyleSerializer(serializers.Serializer): + border = AnalysisReportBorderStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportGridLineStyleSerializer(serializers.Serializer): + line_color = serializers.CharField(required=False, allow_null=True) + line_width = serializers.IntegerField(required=False, allow_null=True) + line_opacity = serializers.IntegerField(required=False, allow_null=True) + + +class AnalysisReportTickStyleSerializer(serializers.Serializer): + line_color = serializers.CharField(required=False, allow_null=True) + line_width = serializers.IntegerField(required=False, allow_null=True) + line_opacity = serializers.IntegerField(required=False, allow_null=True) + + +class AnalysisReportBarChartStyleSerializer(serializers.Serializer): + title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + sub_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + legend = AnalysisReportCategoricalLegendStyleSerializer(required=False, allow_null=True) + bar = AnalysisReportBarStyleSerializer(required=False, allow_null=True) + + horizontal_axis_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + vertical_axis_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + horizontal_axis_tick_label = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + vertical_axis_tick_label = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + vertical_grid_line = AnalysisReportGridLineStyleSerializer(required=False, allow_null=True) + horizontal_grid_line = AnalysisReportGridLineStyleSerializer(required=False, allow_null=True) + vertical_tick = AnalysisReportTickStyleSerializer(required=False, allow_null=True) + horizontal_tick = AnalysisReportTickStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportLineChartStyleSerializer(serializers.Serializer): + title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + sub_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + legend = AnalysisReportCategoricalLegendStyleSerializer(required=False, allow_null=True) + + horizontal_axis_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + vertical_axis_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + horizontal_axis_tick_label = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + vertical_axis_tick_label = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + vertical_grid_line = AnalysisReportGridLineStyleSerializer(required=False, allow_null=True) + horizontal_grid_line = AnalysisReportGridLineStyleSerializer(required=False, allow_null=True) + vertical_tick = AnalysisReportTickStyleSerializer(required=False, allow_null=True) + horizontal_tick = AnalysisReportTickStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportHorizontalAxisSerializer(serializers.Serializer): + field = serializers.CharField(required=False, allow_null=True) + type = serializers.ChoiceField(choices=ReportEnum.HorizontalAxisType.choices, required=False, allow_null=True) + + +class AnalysisReportLineHorizontalAxisSerializer(serializers.Serializer): + field = serializers.CharField(required=False, allow_null=True) + + +class AnalysisReportVerticalAxisSerializer(serializers.Serializer): + client_id = serializers.CharField(required=False) + label = serializers.CharField(required=False) + field = serializers.CharField(required=False, allow_null=True) + aggregation_type = serializers.ChoiceField(choices=ReportEnum.AggregationType.choices, required=False, allow_null=True) + color = serializers.CharField(required=False, allow_null=True) + + +class AnalysisReportBarChartConfigurationSerializer(serializers.Serializer): + sheet = serializers.CharField(required=False, allow_null=True) + type = serializers.ChoiceField(choices=ReportEnum.BarChartType.choices, required=True) + direction = serializers.ChoiceField(choices=ReportEnum.BarChartDirection.choices, required=True) + + horizontal_axis = AnalysisReportHorizontalAxisSerializer(required=True) + vertical_axis = AnalysisReportVerticalAxisSerializer(many=True) + + horizontal_axis_title = serializers.CharField(required=False, allow_null=True) + vertical_axis_title = serializers.CharField(required=False, allow_null=True) + + title = serializers.CharField(required=False, allow_null=True) + sub_title = serializers.CharField(required=False, allow_null=True) + + legend_heading = serializers.CharField(required=False, allow_null=True) + + horizontal_tick_label_rotation = serializers.IntegerField(required=False, allow_null=True) + horizontal_axis_line_visible = serializers.BooleanField(required=False, allow_null=True) + vertical_axis_line_visible = serializers.BooleanField(required=False, allow_null=True) + vertical_axis_extend_minimum_value = serializers.IntegerField(required=False, allow_null=True) + vertical_axis_extend_maximum_value = serializers.IntegerField(required=False, allow_null=True) + vertical_grid_line_visible = serializers.BooleanField(required=False, allow_null=True) + horizontal_grid_line_visible = serializers.BooleanField(required=False, allow_null=True) + vertical_tick_visible = serializers.BooleanField(required=False, allow_null=True) + horizontal_tick_visible = serializers.BooleanField(required=False, allow_null=True) + + style = AnalysisReportBarChartStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportLineChartConfigurationSerializer(serializers.Serializer): + sheet = serializers.CharField(required=False, allow_null=True) + + horizontal_axis = AnalysisReportLineHorizontalAxisSerializer(required=True) + vertical_axis = AnalysisReportVerticalAxisSerializer(many=True) + + horizontal_axis_title = serializers.CharField(required=False, allow_null=True) + vertical_axis_title = serializers.CharField(required=False, allow_null=True) + + title = serializers.CharField(required=False, allow_null=True) + sub_title = serializers.CharField(required=False, allow_null=True) + + legend_heading = serializers.CharField(required=False, allow_null=True) + + horizontal_tick_label_rotation = serializers.IntegerField(required=False, allow_null=True) + horizontal_axis_line_visible = serializers.BooleanField(required=False, allow_null=True) + vertical_axis_line_visible = serializers.BooleanField(required=False, allow_null=True) + vertical_axis_extend_minimum_value = serializers.IntegerField(required=False, allow_null=True) + vertical_axis_extend_maximum_value = serializers.IntegerField(required=False, allow_null=True) + vertical_grid_line_visible = serializers.BooleanField(required=False, allow_null=True) + horizontal_grid_line_visible = serializers.BooleanField(required=False, allow_null=True) + vertical_tick_visible = serializers.BooleanField(required=False, allow_null=True) + horizontal_tick_visible = serializers.BooleanField(required=False, allow_null=True) + + style = AnalysisReportLineChartStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportTimelineChartConfigurationSerializer(serializers.Serializer): + sheet = serializers.CharField(required=False, allow_null=True) + date = serializers.CharField(required=True) + title = serializers.CharField(required=True) + detail = serializers.CharField(required=False, allow_null=True) + category = serializers.CharField(required=False, allow_null=True) + source = serializers.CharField(required=False, allow_null=True) + source_url = serializers.CharField(required=False, allow_null=True) + + +class AnalysisReportKpiConfigurationSerializer(serializers.Serializer): + items = AnalysisReportKpiItemConfigurationSerializer(many=True) + title_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + subtitle_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + source_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + value_content_style = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + class AnalysisReportImageConfigurationSerializer(serializers.Serializer): caption = serializers.CharField(required=False, allow_null=True) altText = serializers.CharField(required=False, allow_null=True) @@ -703,11 +937,104 @@ class AnalysisReportConfigurationSerializer(serializers.Serializer): url_content_style = AnalysisReportUrlConfigurationSerializer(required=False, allow_null=True) +class AnalysisReportMapboxLayerConfigurationSerializer(serializers.Serializer): + mapbox_style = serializers.CharField(required=False, allow_null=True) + access_token = serializers.CharField(required=False, allow_null=True) + + +class AnalysisReportLineLayerStyleConfigurationSerializer(serializers.Serializer): + line = AnalysisReportLineLayerStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportLineLayerConfigurationSerializer(serializers.Serializer): + # NOTE: This reference will be handled in frontend + content_reference_id = serializers.CharField(required=True, allow_null=False) + style = AnalysisReportLineLayerStyleConfigurationSerializer(required=False) + + +class AnalysisReportSymbolLayerStyleConfigurationSerializer(serializers.Serializer): + symbol = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + label = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportSymbolLayerConfigurationSerializer(serializers.Serializer): + # NOTE: This reference will be handled in frontend + content_reference_id = serializers.CharField(required=True, allow_null=False) + label_property_key = serializers.CharField(required=True) + scale = serializers.IntegerField(required=False, allow_null=False) + scale_type = serializers.ChoiceField(choices=ReportEnum.ScaleType.choices, required=False, allow_null=True) + scaling_technique = serializers.ChoiceField(choices=ReportEnum.ScalingTechnique.choices, required=False, allow_null=True) + show_labels = serializers.BooleanField(required=False, allow_null=False) + symbol = serializers.CharField(required=True) + style = AnalysisReportSymbolLayerStyleConfigurationSerializer(required=False) + + +class AnalysisReportPolygonLayerConfigurationSerializer(serializers.Serializer): + # NOTE: This reference will be handled in frontend + content_reference_id = serializers.CharField(required=True, allow_null=False) + label_column = serializers.CharField(required=True) + + +class AnalysisReportHeatmapLayerConfigurationSerializer(serializers.Serializer): + # NOTE: This reference will be handled in frontend + content_reference_id = serializers.CharField(required=True, allow_null=False) + weight_property_key = serializers.CharField(required=True) + fill_palette = serializers.CharField(required=False, allow_null=False) + radius = serializers.FloatField(required=False, allow_null=False) + blur = serializers.FloatField(required=False, allow_null=False) + scale_data_max = serializers.IntegerField(required=False, allow_null=False) + weighted = serializers.BooleanField(required=False, allow_null=False) + + +class AnalysisReportLayerConfigSerializer(serializers.Serializer): + mapbox_layer = AnalysisReportMapboxLayerConfigurationSerializer(required=False, allow_null=True) + line_layer = AnalysisReportLineLayerConfigurationSerializer(required=False, allow_null=True) + symbol_layer = AnalysisReportSymbolLayerConfigurationSerializer(required=False, allow_null=True) + polygon_layer = AnalysisReportPolygonLayerConfigurationSerializer(required=False, allow_null=True) + heatmap_layer = AnalysisReportHeatmapLayerConfigurationSerializer(required=False, allow_null=True) + + +class AnalysisReportMapLayerConfigurationSerializer(serializers.Serializer): + client_id = serializers.CharField(required=True) + name = serializers.CharField(required=True) + visible = serializers.BooleanField(required=True) + order = serializers.IntegerField(required=True) + opacity = serializers.IntegerField(required=False, allow_null=True) + type = serializers.ChoiceField(choices=ReportEnum.MapLayerType.choices, required=False, allow_null=True) + layer_config = AnalysisReportLayerConfigSerializer(required=False, allow_null=True) + + +class AnalysisReportMapStyleConfigSerializer(serializers.Serializer): + title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + sub_title = AnalysisReportTextStyleSerializer(required=False, allow_null=True) + + +class AnalysisReportMapConfigurationSerializer(serializers.Serializer): + title = serializers.CharField(required=False, allow_null=True) + sub_title = serializers.CharField(required=False, allow_null=True) + min_zoom = serializers.IntegerField(required=False, allow_null=True) + max_zoom = serializers.IntegerField(required=False, allow_null=True) + zoom = serializers.IntegerField(required=False, allow_null=True) + show_scale = serializers.BooleanField(required=False, allow_null=True) + map_height = serializers.IntegerField(required=False, allow_null=True) + scale_bar = serializers.BooleanField(required=False, allow_null=True) + enable_zoom_controls = serializers.BooleanField(required=False, allow_null=True) + center_longitude = serializers.FloatField(required=False, allow_null=True) + center_latitude = serializers.FloatField(required=False, allow_null=True) + layers = AnalysisReportMapLayerConfigurationSerializer(many=True) + style = AnalysisReportMapStyleConfigSerializer(required=False, allow_null=True) + + class AnalysisReportContainerContentConfigurationSerializer(serializers.Serializer): text = AnalysisReportTextConfigurationSerializer(required=False, allow_null=True) heading = AnalysisReportHeadingConfigurationSerializer(required=False, allow_null=True) image = AnalysisReportImageConfigurationSerializer(required=False, allow_null=True) url = AnalysisReportUrlConfigurationSerializer(required=False, allow_null=True) + kpi = AnalysisReportKpiConfigurationSerializer(required=False, allow_null=True) + bar_chart = AnalysisReportBarChartConfigurationSerializer(required=False, allow_null=True) + line_chart = AnalysisReportLineChartConfigurationSerializer(required=False, allow_null=True) + map = AnalysisReportMapConfigurationSerializer(required=False, allow_null=True) + timeline_chart = AnalysisReportTimelineChartConfigurationSerializer(required=False, allow_null=True) class AnalysisReportContainerDataSerializer(TempClientIdMixin, serializers.ModelSerializer): @@ -718,6 +1045,7 @@ class Meta: fields = ( 'id', 'client_id', + 'client_reference_id', 'upload', 'data', ) @@ -857,6 +1185,7 @@ def update(self, _): class AnalysisReportUploadMetadataXlsxSheetSerializer(serializers.Serializer): name = serializers.CharField(required=False) header_row = serializers.IntegerField(required=False) + client_id = serializers.CharField(required=False) variables = AnalysisReportVariableSerializer(many=True) diff --git a/apps/analysis/tests/test_mutations.py b/apps/analysis/tests/test_mutations.py index ca710b3ba0..f04c09adaf 100644 --- a/apps/analysis/tests/test_mutations.py +++ b/apps/analysis/tests/test_mutations.py @@ -1070,9 +1070,10 @@ def _query_check(_id, **kwargs): report1_upload1, report1_upload2 = AnalysisReportUploadFactory.create_batch(2, report_id=report1_id) - minput['containers'][0]['contentData'] = [ - {'upload': str(report1_upload1.pk)}, - ] + minput['containers'][0]['contentData'] = [{ + 'clientReferenceId': 'upload-1-id', + 'upload': str(report1_upload1.pk), + }] # -- Validation check errors = _create_mutation_check( @@ -1119,9 +1120,10 @@ def _query_check(_id, **kwargs): } minput.pop('id') # Invalid data - minput['containers'][0]['contentData'] = [ - {'upload': str(report1_upload2.pk)}, - ] + minput['containers'][0]['contentData'] = [{ + 'clientReferenceId': 'upload-2-id', + 'upload': str(report1_upload2.pk), + }] errors = _update_mutation_check( report2_id, minput, @@ -1131,9 +1133,10 @@ def _query_check(_id, **kwargs): assert errors == error_2_data report2_upload1 = AnalysisReportUploadFactory.create(report_id=report2_id) - minput['containers'][0]['contentData'] = [ - {'upload': str(report2_upload1.pk)}, - ] + minput['containers'][0]['contentData'] = [{ + 'clientReferenceId': 'upload-1-id', + 'upload': str(report2_upload1.pk), + }] response = _update_mutation_check(report2_id, minput, okay=True) updated_report_data = response['data']['project']['analysisReportUpdate']['result'] assert updated_report_data != created_report2_data diff --git a/apps/commons/schema_snapshots.py b/apps/commons/schema_snapshots.py index 60ddedadf6..376018d168 100644 --- a/apps/commons/schema_snapshots.py +++ b/apps/commons/schema_snapshots.py @@ -200,6 +200,16 @@ class AnalysisReport: } } } + fragment GridLineStyle on AnalysisReportGridLineStyleType { + lineColor + lineOpacity + lineWidth + } + fragment TickStyle on AnalysisReportTickStyleType { + lineColor + lineOpacity + lineWidth + } fragment TextStyle on AnalysisReportTextStyleType { align color @@ -298,6 +308,39 @@ class AnalysisReport: file { id } + type + metadata { + csv { + headerRow + variables { + clientId + completeness + name + type + } + } + xlsx { + sheets { + clientId + headerRow + name + variables { + clientId + completeness + name + type + } + } + } + geojson { + variables { + clientId + completeness + name + type + } + } + } } } contentConfiguration { @@ -328,9 +371,277 @@ class AnalysisReport: } } } + kpi { + items { + abbreviateValue + clientId + color + date + source + sourceUrl + subtitle + title + value + style { + sourceContentStyle { + ...TextStyle + } + subtitleContentStyle { + ...TextStyle + } + titleContentStyle { + ...TextStyle + } + valueContentStyle { + ...TextStyle + } + } + } + sourceContentStyle { + ...TextStyle + } + subtitleContentStyle { + ...TextStyle + } + titleContentStyle { + ...TextStyle + } + valueContentStyle { + ...TextStyle + } + } + barChart { + direction + horizontalAxis { + field + type + } + horizontalAxisLineVisible + horizontalAxisTitle + horizontalGridLineVisible + horizontalTickVisible + legendHeading + sheet + subTitle + title + type + verticalAxis { + label + aggregationType + clientId + color + field + } + verticalAxisExtendMinimumValue + verticalAxisExtendMaximumValue + verticalAxisLineVisible + verticalAxisTitle + verticalGridLineVisible + verticalTickVisible + horizontalTickLabelRotation + style { + bar { + border { + ...BorderStyle + } + } + horizontalAxisTickLabel { + ...TextStyle + } + horizontalAxisTitle { + ...TextStyle + } + horizontalGridLine { + ...GridLineStyle + } + horizontalTick { + ...TickStyle + } + legend { + heading { + ...TextStyle + } + label { + ...TextStyle + } + position + shape + } + subTitle { + ...TextStyle + } + title { + ...TextStyle + } + verticalAxisTickLabel { + ...TextStyle + } + verticalAxisTitle { + ...TextStyle + } + verticalGridLine { + ...GridLineStyle + } + verticalTick { + ...TickStyle + } + } + } + lineChart { + horizontalAxis { + field + } + horizontalAxisLineVisible + horizontalAxisTitle + horizontalGridLineVisible + horizontalTickVisible + legendHeading + sheet + subTitle + title + verticalAxis { + label + aggregationType + clientId + color + field + } + verticalAxisExtendMinimumValue + verticalAxisExtendMaximumValue + verticalAxisLineVisible + verticalAxisTitle + verticalGridLineVisible + verticalTickVisible + horizontalTickLabelRotation + style { + horizontalAxisTickLabel { + ...TextStyle + } + horizontalAxisTitle { + ...TextStyle + } + horizontalGridLine { + ...GridLineStyle + } + horizontalTick { + ...TickStyle + } + legend { + heading { + ...TextStyle + } + label { + ...TextStyle + } + position + shape + } + subTitle { + ...TextStyle + } + title { + ...TextStyle + } + verticalAxisTickLabel { + ...TextStyle + } + verticalAxisTitle { + ...TextStyle + } + verticalGridLine { + ...GridLineStyle + } + verticalTick { + ...TickStyle + } + } + } + timelineChart { + category + date + detail + sheet + source + sourceUrl + title + } url { url } + map { + title + subTitle + mapHeight + maxZoom + minZoom + scaleBar + showScale + zoom + enableZoomControls + centerLatitude + centerLongitude + style { + title { + ...TextStyle + } + subTitle { + ...TextStyle + } + } + layers { + clientId + name + visible + opacity + order + type + layerConfig { + mapboxLayer { + mapboxStyle + accessToken + } + lineLayer { + contentReferenceId + style { + line { + strokeType + dashSpacing + stroke + strokeWidth + } + } + } + polygonLayer { + contentReferenceId + labelColumn + } + symbolLayer { + contentReferenceId + labelPropertyKey + scaleType + showLabels + symbol + style { + symbol { + ...TextStyle + } + label { + ...TextStyle + } + } + } + heatmapLayer { + blur + contentReferenceId + fillPalette + radius + weighted + weightPropertyKey + scaleDataMax + } + } + } + } } } } diff --git a/schema.graphql b/schema.graphql index 74d5800263..c8fe6ed00e 100644 --- a/schema.graphql +++ b/schema.graphql @@ -342,6 +342,15 @@ type AnalysisPublicationDateType { endDate: Date! } +enum AnalysisReportAggregationTypeEnum { + COUNT + SUM + MEAN + MEDIAN + MIN + MAX +} + input AnalysisReportBackgroundStyleInputType { color: String opacity: Int @@ -352,6 +361,100 @@ type AnalysisReportBackgroundStyleType { opacity: Int } +input AnalysisReportBarChartConfigurationInputType { + sheet: String + type: AnalysisReportBarChartTypeEnum! + direction: AnalysisReportBarChartDirectionEnum! + horizontalAxis: AnalysisReportHorizontalAxisInputType! + verticalAxis: [AnalysisReportVerticalAxisInputType!]! + horizontalAxisTitle: String + verticalAxisTitle: String + title: String + subTitle: String + legendHeading: String + horizontalTickLabelRotation: Int + horizontalAxisLineVisible: Boolean + verticalAxisLineVisible: Boolean + verticalAxisExtendMinimumValue: Int + verticalAxisExtendMaximumValue: Int + verticalGridLineVisible: Boolean + horizontalGridLineVisible: Boolean + verticalTickVisible: Boolean + horizontalTickVisible: Boolean + style: AnalysisReportBarChartStyleInputType +} + +type AnalysisReportBarChartConfigurationType { + sheet: String + type: AnalysisReportBarChartTypeEnum! + direction: AnalysisReportBarChartDirectionEnum! + horizontalAxis: AnalysisReportHorizontalAxisType! + verticalAxis: [AnalysisReportVerticalAxisType!]! + horizontalAxisTitle: String + verticalAxisTitle: String + title: String + subTitle: String + legendHeading: String + horizontalTickLabelRotation: Int + horizontalAxisLineVisible: Boolean + verticalAxisLineVisible: Boolean + verticalAxisExtendMinimumValue: Int + verticalAxisExtendMaximumValue: Int + verticalGridLineVisible: Boolean + horizontalGridLineVisible: Boolean + verticalTickVisible: Boolean + horizontalTickVisible: Boolean + style: AnalysisReportBarChartStyleType +} + +enum AnalysisReportBarChartDirectionEnum { + VERTICAL + HORIZONTAL +} + +input AnalysisReportBarChartStyleInputType { + title: AnalysisReportTextStyleInputType + subTitle: AnalysisReportTextStyleInputType + legend: AnalysisReportCategoricalLegendStyleInputType + bar: AnalysisReportBarStyleInputType + horizontalAxisTitle: AnalysisReportTextStyleInputType + verticalAxisTitle: AnalysisReportTextStyleInputType + horizontalAxisTickLabel: AnalysisReportTextStyleInputType + verticalAxisTickLabel: AnalysisReportTextStyleInputType + verticalGridLine: AnalysisReportGridLineStyleInputType + horizontalGridLine: AnalysisReportGridLineStyleInputType + verticalTick: AnalysisReportTickStyleInputType + horizontalTick: AnalysisReportTickStyleInputType +} + +type AnalysisReportBarChartStyleType { + title: AnalysisReportTextStyleType + subTitle: AnalysisReportTextStyleType + legend: AnalysisReportCategoricalLegendStyleType + bar: AnalysisReportBarStyleType + horizontalAxisTitle: AnalysisReportTextStyleType + verticalAxisTitle: AnalysisReportTextStyleType + horizontalAxisTickLabel: AnalysisReportTextStyleType + verticalAxisTickLabel: AnalysisReportTextStyleType + verticalGridLine: AnalysisReportGridLineStyleType + horizontalGridLine: AnalysisReportGridLineStyleType + verticalTick: AnalysisReportTickStyleType + horizontalTick: AnalysisReportTickStyleType +} + +enum AnalysisReportBarChartTypeEnum { + SIDE_BY_SIDE + STACKED +} + +input AnalysisReportBarStyleInputType { + border: AnalysisReportBorderStyleInputType +} + +type AnalysisReportBarStyleType { + border: AnalysisReportBorderStyleType +} + input AnalysisReportBodyStyleInputType { gap: Int } @@ -382,6 +485,20 @@ type AnalysisReportBorderStyleType { style: AnalysisReportBorderStyleStyleEnum } +input AnalysisReportCategoricalLegendStyleInputType { + position: AnalysisReportLegendPositionEnum + shape: AnalysisReportLegendDotShapeEnum + heading: AnalysisReportTextStyleInputType + label: AnalysisReportTextStyleInputType +} + +type AnalysisReportCategoricalLegendStyleType { + position: AnalysisReportLegendPositionEnum + shape: AnalysisReportLegendDotShapeEnum + heading: AnalysisReportTextStyleType + label: AnalysisReportTextStyleType +} + input AnalysisReportConfigurationInputType { pageStyle: AnalysisReportPageStyleInputType headerStyle: AnalysisReportHeaderStyleInputType @@ -409,6 +526,11 @@ input AnalysisReportContainerContentConfigurationInputType { heading: AnalysisReportHeadingConfigurationInputType image: AnalysisReportImageConfigurationInputType url: AnalysisReportUrlConfigurationInputType + kpi: AnalysisReportKpiConfigurationInputType + barChart: AnalysisReportBarChartConfigurationInputType + lineChart: AnalysisReportLineChartConfigurationInputType + map: AnalysisReportMapConfigurationInputType + timelineChart: AnalysisReportTimelineChartConfigurationInputType } type AnalysisReportContainerContentConfigurationType { @@ -416,6 +538,11 @@ type AnalysisReportContainerContentConfigurationType { heading: AnalysisReportHeadingConfigurationType image: AnalysisReportImageConfigurationType url: AnalysisReportUrlConfigurationType + kpi: AnalysisReportKpiConfigurationType + barChart: AnalysisReportBarChartConfigurationType + lineChart: AnalysisReportLineChartConfigurationType + map: AnalysisReportMapConfigurationType + timelineChart: AnalysisReportTimelineChartConfigurationType } enum AnalysisReportContainerContentTypeEnum { @@ -423,11 +550,17 @@ enum AnalysisReportContainerContentTypeEnum { HEADING IMAGE URL + TIMELINE_CHART + KPI + BAR_CHART + MAP + LINE_CHART } input AnalysisReportContainerDataInputType { id: ID clientId: String + clientReferenceId: String! upload: ID! data: GenericScalar } @@ -435,6 +568,7 @@ input AnalysisReportContainerDataInputType { type AnalysisReportContainerDataType { id: ID! upload: AnalysisReportUploadType! + clientReferenceId: String! data: GenericScalar! clientId: ID! } @@ -478,6 +612,18 @@ type AnalysisReportContainerType { contentData: [AnalysisReportContainerDataType!]! } +input AnalysisReportGridLineStyleInputType { + lineColor: String + lineWidth: Int + lineOpacity: Int +} + +type AnalysisReportGridLineStyleType { + lineColor: String + lineWidth: Int + lineOpacity: Int +} + input AnalysisReportHeaderStyleInputType { padding: AnalysisReportPaddingStyleInputType border: AnalysisReportBorderStyleInputType @@ -535,6 +681,42 @@ type AnalysisReportHeadingContentStyleType { h4: AnalysisReportTextStyleType } +input AnalysisReportHeatmapLayerConfigurationInputType { + contentReferenceId: String! + weightPropertyKey: String! + fillPalette: String + radius: Float + blur: Float + scaleDataMax: Int + weighted: Boolean +} + +type AnalysisReportHeatmapLayerConfigurationType { + contentReferenceId: String! + weightPropertyKey: String! + fillPalette: String + radius: Float + blur: Float + scaleDataMax: Int + weighted: Boolean +} + +input AnalysisReportHorizontalAxisInputType { + field: String + type: AnalysisReportHorizontalAxisTypeEnum +} + +type AnalysisReportHorizontalAxisType { + field: String + type: AnalysisReportHorizontalAxisTypeEnum +} + +enum AnalysisReportHorizontalAxisTypeEnum { + CATEGORICAL + NUMERIC + DATE +} + input AnalysisReportImageConfigurationInputType { caption: String altText: String @@ -587,6 +769,207 @@ input AnalysisReportInputUpdateType { containers: [AnalysisReportContainerInputType!] } +input AnalysisReportKpiConfigurationInputType { + items: [AnalysisReportKpiItemConfigurationInputType!]! + titleContentStyle: AnalysisReportTextStyleInputType + subtitleContentStyle: AnalysisReportTextStyleInputType + sourceContentStyle: AnalysisReportTextStyleInputType + valueContentStyle: AnalysisReportTextStyleInputType +} + +type AnalysisReportKpiConfigurationType { + items: [AnalysisReportKpiItemConfigurationType!]! + titleContentStyle: AnalysisReportTextStyleType + subtitleContentStyle: AnalysisReportTextStyleType + sourceContentStyle: AnalysisReportTextStyleType + valueContentStyle: AnalysisReportTextStyleType +} + +input AnalysisReportKpiItemConfigurationInputType { + title: String + subtitle: String + source: String + sourceUrl: String + color: String + date: Date + value: Int + clientId: String + abbreviateValue: Boolean + style: AnalysisReportKpiItemStyleConfigurationInputType +} + +type AnalysisReportKpiItemConfigurationType { + title: String + subtitle: String + source: String + sourceUrl: String + color: String + date: Date + value: Int + clientId: String + abbreviateValue: Boolean + style: AnalysisReportKpiItemStyleConfigurationType +} + +input AnalysisReportKpiItemStyleConfigurationInputType { + titleContentStyle: AnalysisReportTextStyleInputType + subtitleContentStyle: AnalysisReportTextStyleInputType + sourceContentStyle: AnalysisReportTextStyleInputType + valueContentStyle: AnalysisReportTextStyleInputType +} + +type AnalysisReportKpiItemStyleConfigurationType { + titleContentStyle: AnalysisReportTextStyleType + subtitleContentStyle: AnalysisReportTextStyleType + sourceContentStyle: AnalysisReportTextStyleType + valueContentStyle: AnalysisReportTextStyleType +} + +input AnalysisReportLayerConfigInputType { + mapboxLayer: AnalysisReportMapboxLayerConfigurationInputType + lineLayer: AnalysisReportLineLayerConfigurationInputType + symbolLayer: AnalysisReportSymbolLayerConfigurationInputType + polygonLayer: AnalysisReportPolygonLayerConfigurationInputType + heatmapLayer: AnalysisReportHeatmapLayerConfigurationInputType +} + +type AnalysisReportLayerConfigType { + mapboxLayer: AnalysisReportMapboxLayerConfigurationType + lineLayer: AnalysisReportLineLayerConfigurationType + symbolLayer: AnalysisReportSymbolLayerConfigurationType + polygonLayer: AnalysisReportPolygonLayerConfigurationType + heatmapLayer: AnalysisReportHeatmapLayerConfigurationType +} + +enum AnalysisReportLegendDotShapeEnum { + CIRCLE + TRIANGLE + SQUARE + DIAMOND +} + +enum AnalysisReportLegendPositionEnum { + TOP + LEFT + BOTTOM + RIGHT +} + +input AnalysisReportLineChartConfigurationInputType { + sheet: String + horizontalAxis: AnalysisReportLineHorizontalAxisInputType! + verticalAxis: [AnalysisReportVerticalAxisInputType!]! + horizontalAxisTitle: String + verticalAxisTitle: String + title: String + subTitle: String + legendHeading: String + horizontalTickLabelRotation: Int + horizontalAxisLineVisible: Boolean + verticalAxisLineVisible: Boolean + verticalAxisExtendMinimumValue: Int + verticalAxisExtendMaximumValue: Int + verticalGridLineVisible: Boolean + horizontalGridLineVisible: Boolean + verticalTickVisible: Boolean + horizontalTickVisible: Boolean + style: AnalysisReportLineChartStyleInputType +} + +type AnalysisReportLineChartConfigurationType { + sheet: String + horizontalAxis: AnalysisReportLineHorizontalAxisType! + verticalAxis: [AnalysisReportVerticalAxisType!]! + horizontalAxisTitle: String + verticalAxisTitle: String + title: String + subTitle: String + legendHeading: String + horizontalTickLabelRotation: Int + horizontalAxisLineVisible: Boolean + verticalAxisLineVisible: Boolean + verticalAxisExtendMinimumValue: Int + verticalAxisExtendMaximumValue: Int + verticalGridLineVisible: Boolean + horizontalGridLineVisible: Boolean + verticalTickVisible: Boolean + horizontalTickVisible: Boolean + style: AnalysisReportLineChartStyleType +} + +input AnalysisReportLineChartStyleInputType { + title: AnalysisReportTextStyleInputType + subTitle: AnalysisReportTextStyleInputType + legend: AnalysisReportCategoricalLegendStyleInputType + horizontalAxisTitle: AnalysisReportTextStyleInputType + verticalAxisTitle: AnalysisReportTextStyleInputType + horizontalAxisTickLabel: AnalysisReportTextStyleInputType + verticalAxisTickLabel: AnalysisReportTextStyleInputType + verticalGridLine: AnalysisReportGridLineStyleInputType + horizontalGridLine: AnalysisReportGridLineStyleInputType + verticalTick: AnalysisReportTickStyleInputType + horizontalTick: AnalysisReportTickStyleInputType +} + +type AnalysisReportLineChartStyleType { + title: AnalysisReportTextStyleType + subTitle: AnalysisReportTextStyleType + legend: AnalysisReportCategoricalLegendStyleType + horizontalAxisTitle: AnalysisReportTextStyleType + verticalAxisTitle: AnalysisReportTextStyleType + horizontalAxisTickLabel: AnalysisReportTextStyleType + verticalAxisTickLabel: AnalysisReportTextStyleType + verticalGridLine: AnalysisReportGridLineStyleType + horizontalGridLine: AnalysisReportGridLineStyleType + verticalTick: AnalysisReportTickStyleType + horizontalTick: AnalysisReportTickStyleType +} + +input AnalysisReportLineHorizontalAxisInputType { + field: String +} + +type AnalysisReportLineHorizontalAxisType { + field: String +} + +input AnalysisReportLineLayerConfigurationInputType { + contentReferenceId: String! + style: AnalysisReportLineLayerStyleConfigurationInputType +} + +type AnalysisReportLineLayerConfigurationType { + contentReferenceId: String! + style: AnalysisReportLineLayerStyleConfigurationType +} + +enum AnalysisReportLineLayerStrokeTypeEnum { + DASH + SOLID +} + +input AnalysisReportLineLayerStyleConfigurationInputType { + line: AnalysisReportLineLayerStyleInputType +} + +type AnalysisReportLineLayerStyleConfigurationType { + line: AnalysisReportLineLayerStyleType +} + +input AnalysisReportLineLayerStyleInputType { + dashSpacing: Int + stroke: String + strokeType: AnalysisReportLineLayerStrokeTypeEnum + strokeWidth: Int +} + +type AnalysisReportLineLayerStyleType { + dashSpacing: Int + stroke: String + strokeType: AnalysisReportLineLayerStrokeTypeEnum + strokeWidth: Int +} + type AnalysisReportListType { results: [AnalysisReportType!] totalCount: Int @@ -594,6 +977,87 @@ type AnalysisReportListType { pageSize: Int } +input AnalysisReportMapConfigurationInputType { + title: String + subTitle: String + minZoom: Int + maxZoom: Int + zoom: Int + showScale: Boolean + mapHeight: Int + scaleBar: Boolean + enableZoomControls: Boolean + centerLongitude: Float + centerLatitude: Float + layers: [AnalysisReportMapLayerConfigurationInputType!]! + style: AnalysisReportMapStyleConfigInputType +} + +type AnalysisReportMapConfigurationType { + title: String + subTitle: String + minZoom: Int + maxZoom: Int + zoom: Int + showScale: Boolean + mapHeight: Int + scaleBar: Boolean + enableZoomControls: Boolean + centerLongitude: Float + centerLatitude: Float + layers: [AnalysisReportMapLayerConfigurationType!]! + style: AnalysisReportMapStyleConfigType +} + +input AnalysisReportMapLayerConfigurationInputType { + clientId: String! + name: String! + visible: Boolean! + order: Int! + opacity: Int + type: AnalysisReportMapLayerTypeEnum + layerConfig: AnalysisReportLayerConfigInputType +} + +type AnalysisReportMapLayerConfigurationType { + clientId: String! + name: String! + visible: Boolean! + order: Int! + opacity: Int + type: AnalysisReportMapLayerTypeEnum + layerConfig: AnalysisReportLayerConfigType +} + +enum AnalysisReportMapLayerTypeEnum { + OSM_LAYER + MAPBOX_LAYER + SYMBOL_LAYER + POLYGON_LAYER + LINE_LAYER + HEAT_MAP_LAYER +} + +input AnalysisReportMapStyleConfigInputType { + title: AnalysisReportTextStyleInputType + subTitle: AnalysisReportTextStyleInputType +} + +type AnalysisReportMapStyleConfigType { + title: AnalysisReportTextStyleType + subTitle: AnalysisReportTextStyleType +} + +input AnalysisReportMapboxLayerConfigurationInputType { + mapboxStyle: String + accessToken: String +} + +type AnalysisReportMapboxLayerConfigurationType { + mapboxStyle: String + accessToken: String +} + input AnalysisReportMarginStyleInputType { top: Int bottom: Int @@ -632,6 +1096,26 @@ type AnalysisReportPageStyleType { background: AnalysisReportBackgroundStyleType } +input AnalysisReportPolygonLayerConfigurationInputType { + contentReferenceId: String! + labelColumn: String! +} + +type AnalysisReportPolygonLayerConfigurationType { + contentReferenceId: String! + labelColumn: String! +} + +enum AnalysisReportScaleTypeEnum { + FIXED + PROPORTIONAL +} + +enum AnalysisReportScalingTechniqueEnum { + ABSOLUTE + FLANNERY +} + input AnalysisReportSnapshotInputType { report: ID! } @@ -652,6 +1136,38 @@ type AnalysisReportSnapshotType { files: [GalleryFileType!]! } +input AnalysisReportSymbolLayerConfigurationInputType { + contentReferenceId: String! + labelPropertyKey: String! + scale: Int + scaleType: AnalysisReportScaleTypeEnum + scalingTechnique: AnalysisReportScalingTechniqueEnum + showLabels: Boolean + symbol: String! + style: AnalysisReportSymbolLayerStyleConfigurationInputType +} + +type AnalysisReportSymbolLayerConfigurationType { + contentReferenceId: String! + labelPropertyKey: String! + scale: Int + scaleType: AnalysisReportScaleTypeEnum + scalingTechnique: AnalysisReportScalingTechniqueEnum + showLabels: Boolean + symbol: String! + style: AnalysisReportSymbolLayerStyleConfigurationType +} + +input AnalysisReportSymbolLayerStyleConfigurationInputType { + symbol: AnalysisReportTextStyleInputType + label: AnalysisReportTextStyleInputType +} + +type AnalysisReportSymbolLayerStyleConfigurationType { + symbol: AnalysisReportTextStyleType + label: AnalysisReportTextStyleType +} + input AnalysisReportTextConfigurationInputType { content: String style: AnalysisReportTextContentStyleInputType @@ -693,6 +1209,38 @@ type AnalysisReportTextStyleType { align: AnalysisReportTextStyleAlignEnum } +input AnalysisReportTickStyleInputType { + lineColor: String + lineWidth: Int + lineOpacity: Int +} + +type AnalysisReportTickStyleType { + lineColor: String + lineWidth: Int + lineOpacity: Int +} + +input AnalysisReportTimelineChartConfigurationInputType { + sheet: String + date: String! + title: String! + detail: String + category: String + source: String + sourceUrl: String +} + +type AnalysisReportTimelineChartConfigurationType { + sheet: String + date: String! + title: String! + detail: String + category: String + source: String + sourceUrl: String +} + type AnalysisReportType { id: ID! isPublic: Boolean! @@ -762,12 +1310,14 @@ input AnalysisReportUploadMetadataXlsxInputType { input AnalysisReportUploadMetadataXlsxSheetInputType { name: String headerRow: Int + clientId: String variables: [AnalysisReportVariableInputType!]! } type AnalysisReportUploadMetadataXlsxSheetType { name: String headerRow: Int + clientId: String variables: [AnalysisReportVariableType!]! } @@ -800,12 +1350,14 @@ type AnalysisReportUrlConfigurationType { input AnalysisReportVariableInputType { name: String + clientId: String type: AnalysisReportVariableTypeEnum completeness: Int } type AnalysisReportVariableType { name: String + clientId: String type: AnalysisReportVariableTypeEnum completeness: Int } @@ -814,6 +1366,23 @@ enum AnalysisReportVariableTypeEnum { TEXT NUMBER DATE + BOOLEAN +} + +input AnalysisReportVerticalAxisInputType { + clientId: String + label: String + field: String + aggregationType: AnalysisReportAggregationTypeEnum + color: String +} + +type AnalysisReportVerticalAxisType { + clientId: String + label: String + field: String + aggregationType: AnalysisReportAggregationTypeEnum + color: String } type AnalysisTopicModelClusterType { @@ -1026,6 +1595,16 @@ type AppEnumCollection { AnalysisReportBorderStyleSerializerStyle: [AppEnumCollectionAnalysisReportBorderStyleSerializerStyle!] AnalysisReportImageContentStyleSerializerFit: [AppEnumCollectionAnalysisReportImageContentStyleSerializerFit!] AnalysisReportHeadingConfigurationSerializerVariant: [AppEnumCollectionAnalysisReportHeadingConfigurationSerializerVariant!] + AnalysisReportHorizontalAxisSerializerType: [AppEnumCollectionAnalysisReportHorizontalAxisSerializerType!] + AnalysisReportBarChartConfigurationSerializerType: [AppEnumCollectionAnalysisReportBarChartConfigurationSerializerType!] + AnalysisReportBarChartConfigurationSerializerDirection: [AppEnumCollectionAnalysisReportBarChartConfigurationSerializerDirection!] + AnalysisReportCategoricalLegendStyleSerializerPosition: [AppEnumCollectionAnalysisReportCategoricalLegendStyleSerializerPosition!] + AnalysisReportCategoricalLegendStyleSerializerShape: [AppEnumCollectionAnalysisReportCategoricalLegendStyleSerializerShape!] + AnalysisReportVerticalAxisSerializerAggregationType: [AppEnumCollectionAnalysisReportVerticalAxisSerializerAggregationType!] + AnalysisReportMapLayerConfigurationSerializerType: [AppEnumCollectionAnalysisReportMapLayerConfigurationSerializerType!] + AnalysisReportSymbolLayerConfigurationSerializerScaleType: [AppEnumCollectionAnalysisReportSymbolLayerConfigurationSerializerScaleType!] + AnalysisReportSymbolLayerConfigurationSerializerScalingTechnique: [AppEnumCollectionAnalysisReportSymbolLayerConfigurationSerializerScalingTechnique!] + AnalysisReportLineLayerStyleSerializerStrokeType: [AppEnumCollectionAnalysisReportLineLayerStyleSerializerStrokeType!] NotificationNotificationType: [AppEnumCollectionNotificationNotificationType!] NotificationStatus: [AppEnumCollectionNotificationStatus!] ConnectorSourceSource: [AppEnumCollectionConnectorSourceSource!] @@ -1080,12 +1659,36 @@ type AppEnumCollectionAnalysisFrameworkRoleType { description: String } +type AppEnumCollectionAnalysisReportBarChartConfigurationSerializerDirection { + enum: AnalysisReportBarChartDirectionEnum! + label: String! + description: String +} + +type AppEnumCollectionAnalysisReportBarChartConfigurationSerializerType { + enum: AnalysisReportBarChartTypeEnum! + label: String! + description: String +} + type AppEnumCollectionAnalysisReportBorderStyleSerializerStyle { enum: AnalysisReportBorderStyleStyleEnum! label: String! description: String } +type AppEnumCollectionAnalysisReportCategoricalLegendStyleSerializerPosition { + enum: AnalysisReportLegendPositionEnum! + label: String! + description: String +} + +type AppEnumCollectionAnalysisReportCategoricalLegendStyleSerializerShape { + enum: AnalysisReportLegendDotShapeEnum! + label: String! + description: String +} + type AppEnumCollectionAnalysisReportContainerContentType { enum: AnalysisReportContainerContentTypeEnum! label: String! @@ -1098,12 +1701,42 @@ type AppEnumCollectionAnalysisReportHeadingConfigurationSerializerVariant { description: String } +type AppEnumCollectionAnalysisReportHorizontalAxisSerializerType { + enum: AnalysisReportHorizontalAxisTypeEnum! + label: String! + description: String +} + type AppEnumCollectionAnalysisReportImageContentStyleSerializerFit { enum: AnalysisReportImageContentStyleFitEnum! label: String! description: String } +type AppEnumCollectionAnalysisReportLineLayerStyleSerializerStrokeType { + enum: AnalysisReportLineLayerStrokeTypeEnum! + label: String! + description: String +} + +type AppEnumCollectionAnalysisReportMapLayerConfigurationSerializerType { + enum: AnalysisReportMapLayerTypeEnum! + label: String! + description: String +} + +type AppEnumCollectionAnalysisReportSymbolLayerConfigurationSerializerScaleType { + enum: AnalysisReportScaleTypeEnum! + label: String! + description: String +} + +type AppEnumCollectionAnalysisReportSymbolLayerConfigurationSerializerScalingTechnique { + enum: AnalysisReportScalingTechniqueEnum! + label: String! + description: String +} + type AppEnumCollectionAnalysisReportTextStyleSerializerAlign { enum: AnalysisReportTextStyleAlignEnum! label: String! @@ -1122,6 +1755,12 @@ type AppEnumCollectionAnalysisReportVariableSerializerType { description: String } +type AppEnumCollectionAnalysisReportVerticalAxisSerializerAggregationType { + enum: AnalysisReportAggregationTypeEnum! + label: String! + description: String +} + type AppEnumCollectionAnalyticalStatementGeoTaskStatus { enum: AnalyticalStatementGeoTaskStatusEnum! label: String! @@ -4506,7 +5145,7 @@ type ProjectDetailType { analysisReport(id: ID!): AnalysisReportType analysisReports(search: String, analyses: [ID!], isPublic: Boolean, organizations: [ID!], page: Int = 1, ordering: String, pageSize: Int): AnalysisReportListType analysisReportUpload(id: ID!): AnalysisReportUploadType - analysisReportUploads(report: [ID!], types: [AnalysisReportUploadTypeEnum!], page: Int = 1, ordering: String, pageSize: Int): AnalysisReportUploadListType + analysisReportUploads(search: String, report: [ID!], types: [AnalysisReportUploadTypeEnum!], page: Int = 1, ordering: String, pageSize: Int): AnalysisReportUploadListType analysisReportSnapshot(id: ID!): AnalysisReportSnapshotType analysisReportSnapshots(report: [ID!], page: Int = 1, ordering: String, pageSize: Int): AnalysisReportSnapshotListType assessment(id: ID!): AssessmentType