From 7d64e1af55f2be573b7eee7e69a2b72bd51b148e Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Thu, 28 Sep 2023 01:03:40 +0300 Subject: [PATCH 01/23] Apex chart initial Ok --- demo_proj/demo_app/helpers.py | 1 + demo_proj/demo_app/reports.py | 30 ++++++++++ demo_proj/demo_proj/settings.py | 11 +++- demo_proj/templates/demo/apex_report.html | 35 ++++++++++++ docs/source/howto/customize_frontend.rst | 23 ++++++++ docs/source/topics/custom_chart_engine.rst | 31 +++++++++++ slick_reporting/app_settings.py | 22 +++++++- .../slick_reporting.chartsjs.js | 55 +++++++++++++------ .../slick_reporting.highchart.js | 34 +----------- .../slick_reporting.report_loader.js | 14 ++++- .../slick_reporting/js_resources.html | 3 + .../templates/slick_reporting/report.html | 5 +- .../templatetags/slick_reporting_tags.py | 17 +++++- slick_reporting/views.py | 1 + 14 files changed, 224 insertions(+), 58 deletions(-) create mode 100644 demo_proj/templates/demo/apex_report.html create mode 100644 docs/source/topics/custom_chart_engine.rst diff --git a/demo_proj/demo_app/helpers.py b/demo_proj/demo_app/helpers.py index a639d04..97a1d92 100644 --- a/demo_proj/demo_app/helpers.py +++ b/demo_proj/demo_app/helpers.py @@ -40,6 +40,7 @@ ] OTHER = [ ("chartjs-examples", reports.ChartJSExample), + ("apexcharts-examples", reports.ProductSalesApexChart), ] diff --git a/demo_proj/demo_app/reports.py b/demo_proj/demo_app/reports.py index 30cf19d..c1b916c 100644 --- a/demo_proj/demo_app/reports.py +++ b/demo_proj/demo_app/reports.py @@ -607,3 +607,33 @@ class ChartJSExample(TimeSeriesReport): # plot_total=True, ), ] + + +class ProductSalesApexChart(ReportView): + report_title = _("Product Sales Apex Charts") + report_model = SalesTransaction + date_field = "date" + group_by = "product" + chart_engine = "apexcharts" + template_name = "demo/apex_report.html" + + columns = [ + "name", + ComputationField.create( + method=Sum, + field="value", + name="value__sum", + verbose_name="Total sold $", + is_summable=True, + ), + ] + + # Charts + chart_settings = [ + Chart( + "Total sold $", + type="pie", + data_source=["value__sum"], + title_source=["name"], + ), + ] diff --git a/demo_proj/demo_proj/settings.py b/demo_proj/demo_proj/settings.py index a447da6..7853800 100644 --- a/demo_proj/demo_proj/settings.py +++ b/demo_proj/demo_proj/settings.py @@ -37,7 +37,6 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - "demo_app", "crispy_forms", "crispy_bootstrap5", @@ -130,3 +129,13 @@ CRISPY_TEMPLATE_PACK = "bootstrap5" CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" + +SLICK_REPORTING_SETTINGS = { + "CHARTS": { + "apexcharts": { + "entryPoint": "DisplayApexPieChart", + "js": "https://cdn.jsdelivr.net/npm/apexcharts", + "css": "https://cdn.jsdelivr.net/npm/apexcharts/dist/apexcharts.min.css", + }, + }, +} diff --git a/demo_proj/templates/demo/apex_report.html b/demo_proj/templates/demo/apex_report.html new file mode 100644 index 0000000..46c57cf --- /dev/null +++ b/demo_proj/templates/demo/apex_report.html @@ -0,0 +1,35 @@ +{% extends "slick_reporting/report.html" %} + +{% block content %} + {{ block.super }} + + +{% endblock %} diff --git a/docs/source/howto/customize_frontend.rst b/docs/source/howto/customize_frontend.rst index 3dafcef..30a797a 100644 --- a/docs/source/howto/customize_frontend.rst +++ b/docs/source/howto/customize_frontend.rst @@ -112,3 +112,26 @@ Let's have a look } +The ajax response structure +--------------------------- + +Understanding how the response is structured is imperative in order to customize how the report is displayed on the front end + +Let's have a look + +.. code-block:: python + + + # Ajax response or `report_results` template context variable. + response = { + "report_slug": "", # the report slug, defaults to the class name all lower + "data": [], # a list of objects representing the actual results of the report + "columns": [], # A list explaining the columns/keys in the data results. + # ie: len(response.columns) == len(response.data[i].keys()) + # A List of objects. each object contain field needed information like verbose name , if summable and hints about the data type. + "metadata": {}, # Contains information about the report as whole if it's time series or a a crosstab + # And what's the actual and verbose names of the time series or crosstab specific columns. + "chart_settings": [], # a list of objects mirror of the set charts_settings + } + + diff --git a/docs/source/topics/custom_chart_engine.rst b/docs/source/topics/custom_chart_engine.rst new file mode 100644 index 0000000..8026b38 --- /dev/null +++ b/docs/source/topics/custom_chart_engine.rst @@ -0,0 +1,31 @@ +Custom Charting Engine +====================== + + +To add a new chart engine you add it to the settings and provide an entry point function for the front end + +.. code-block:: python + + SLICK_REPORTING_SETTINGS_DEFAULT = { + "CHARTS": { + "apexcharts": { + "entryPoint": "DisplayChart", + "js": ("https://cdn.jsdelivr.net/npm/apexcharts",), + "css": "https://cdn.jsdelivr.net/npm/apexcharts/dist/apexcharts.min.css", + } + }, + } + +and then you add the entry point function to the front end + +.. code-block:: javascript + + function displayChart(data, $elem, chart_id) { + // data is the ajax response coming from server + // $elem is the jquery element where the chart should be rendered + // chart_id is the id of the chart, which is teh index of teh needed chart in the [data.chart_settings] array + + } + + +The data is a json object with the following structure \ No newline at end of file diff --git a/slick_reporting/app_settings.py b/slick_reporting/app_settings.py index 30c1876..1ade347 100644 --- a/slick_reporting/app_settings.py +++ b/slick_reporting/app_settings.py @@ -52,8 +52,14 @@ def get_end_date(): }, }, "CHARTS": { - "highcharts": "$.slick_reporting.highcharts.displayChart", - "chartjs": "$.slick_reporting.chartjs.displayChart", + "highcharts": { + "entryPoint": "$.slick_reporting.highcharts.displayChart", + }, + "chartsjs": { + "entryPoint": "$.slick_reporting.chartsjs.displayChart", + } + # "highcharts": "$.slick_reporting.highcharts.displayChart", + # "chartjs": "$.slick_reporting.chartjs.displayChart", }, "MESSAGES": { "total": _("Total"), @@ -62,7 +68,17 @@ def get_end_date(): def get_slick_reporting_settings(): - slick_settings = {**SLICK_REPORTING_SETTINGS_DEFAULT, **getattr(settings, "SLICK_REPORTING_SETTINGS", {})} + slick_settings = SLICK_REPORTING_SETTINGS_DEFAULT.copy() + slick_chart_settings = slick_settings["CHARTS"].copy() + + user_settings = getattr(settings, "SLICK_REPORTING_SETTINGS", {}) + user_chart_settings = user_settings.get("CHARTS", {}) + + slick_chart_settings.update(user_chart_settings) + slick_settings.update(user_settings) + slick_settings["CHARTS"] = slick_chart_settings + + # slick_settings = {**SLICK_REPORTING_SETTINGS_DEFAULT, **getattr(settings, "SLICK_REPORTING_SETTINGS", {})} start_date = getattr(settings, "SLICK_REPORTING_DEFAULT_START_DATE", False) end_date = getattr(settings, "SLICK_REPORTING_DEFAULT_END_DATE", False) # backward compatibility, todo remove in next major release diff --git a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js index f8f3447..51a7b02 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js @@ -17,8 +17,8 @@ return response['metadata']['time_series_column_names']; } - function createChartObject(response, chartId, extraOptions) { - let chartOptions = $.slick_reporting.getObjFromArray(response.chart_settings, 'id', chartId, true); + function createChartObject(response, chartOptions, extraOptions) { + // let chartOptions = $.slick_reporting.getObjFromArray(response.chart_settings, 'id', chartId, true); let extractedData = extractDataFromResponse(response, chartOptions); let chartObject = { @@ -69,6 +69,27 @@ return chartObject } + function getGroupByLabelAndSeries(response, chartOptions) { + + let legendResults = []; + let datasetData = []; + let dataFieldName = chartOptions['data_source']; + let titleFieldName = chartOptions['title_source']; + + for (let i = 0; i < response.data.length; i++) { + let row = response.data[i]; + if (titleFieldName !== '') { + let txt = row[titleFieldName]; + txt = $(txt).text() || txt; // the title is an "); } @@ -162,7 +184,7 @@ console.error(e) } - let chartObject = $.slick_reporting.chartsjs.createChartObject(data, chart_id); + let chartObject = $.slick_reporting.chartsjs.createChartObject(data, chartOptions); let $chart = $elem.find('canvas'); try { _chart_cache[cache_key] = new Chart($chart, chartObject); @@ -178,6 +200,7 @@ $.slick_reporting = {} } $.slick_reporting.chartsjs = { + getGroupByLabelAndSeries: getGroupByLabelAndSeries, createChartObject: createChartObject, displayChart: displayChart, defaults: { diff --git a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js index 219d917..61e8fe3 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js @@ -19,39 +19,7 @@ return output } - function getObjFromArray(objList, obj_key, key_value, failToFirst) { - failToFirst = typeof (failToFirst) !== 'undefined'; - if (key_value !== '') { - for (let i = 0; i < objList.length; i++) { - if (objList[i][obj_key] === key_value) { - return objList[i]; - } - } - } - if (failToFirst && objList.length > 0) { - return objList[0] - } - - return false; - } - var ra_chart_settings = { - - - //exporting: { - // allowHTML:true, - // enabled: faelse, - //}, - - - func2: function () { - var tooltip = '' + this.point.key + '' + - '' + - '
' + this.series.name + ': ' + - this.point.y + '
{Percentage}:' + this.point.percentage + ' %
' - } - }; let _chart_cache = {}; function normalStackedTooltipFormatter() { @@ -87,7 +55,7 @@ // First specifying the global default // second, Get the data from the serponse // Adjust the Chart Object accordingly - let chartOptions = getObjFromArray(response.chart_settings, 'id', chart_id, true) + let chartOptions = $.slick_reporting.getObjFromArray(response.chart_settings, 'id', chart_id, true) try { diff --git a/slick_reporting/static/slick_reporting/slick_reporting.report_loader.js b/slick_reporting/static/slick_reporting/slick_reporting.report_loader.js index 105265d..8c4e673 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.report_loader.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.report_loader.js @@ -37,6 +37,7 @@ function displayChart(data, $elem, chart_id) { let engine = "highcharts"; + let chartOptions = $.slick_reporting.getObjFromArray(data.chart_settings, 'id', chart_id, true); try { if (chart_id === '' || typeof (chart_id) === "undefined") { engine = data.chart_settings[0]['engine_name']; @@ -46,7 +47,7 @@ } catch (e) { console.error(e); } - $.slick_reporting.executeFunctionByName($.slick_reporting.report_loader.chart_engines[engine], window, data, $elem, chart_id); + $.slick_reporting.executeFunctionByName($.slick_reporting.report_loader.chart_engines[engine], window, data, $elem, chartOptions); } @@ -86,14 +87,20 @@ function initialize() { settings = JSON.parse(document.getElementById('slick_reporting_settings').textContent); + let chartSettings = {}; $('[data-report-widget]').not('[data-no-auto-load]').each(function (i, elem) { refreshReportWidget($(elem)); }); + + Object.keys(settings["CHARTS"]).forEach(function (key) { + chartSettings[key] = settings.CHARTS[key].entryPoint; + }) + $.slick_reporting.report_loader.chart_engines = chartSettings; } function _get_chart_icon(chart_type) { try { - return ""; + return ""; } catch (e) { console.error(e); } @@ -136,8 +143,11 @@ }); + + $.slick_reporting.report_loader = { cache: $.slick_reporting.cache, + // "extractDataFromResponse": extractDataFromResponse, initialize: initialize, refreshReportWidget: refreshReportWidget, failFunction: failFunction, diff --git a/slick_reporting/templates/slick_reporting/js_resources.html b/slick_reporting/templates/slick_reporting/js_resources.html index 67b51f3..d852668 100644 --- a/slick_reporting/templates/slick_reporting/js_resources.html +++ b/slick_reporting/templates/slick_reporting/js_resources.html @@ -26,6 +26,9 @@ + + + {{ slick_reporting_settings|json_script:"slick_reporting_settings" }} -{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/demo_proj/templates/menu.html b/demo_proj/templates/menu.html index 561dabd..01a2740 100644 --- a/demo_proj/templates/menu.html +++ b/demo_proj/templates/menu.html @@ -163,6 +163,21 @@ +
+ + \ No newline at end of file diff --git a/docs/source/topics/custom_chart_engine.rst b/docs/source/topics/custom_chart_engine.rst index 8026b38..d3128ef 100644 --- a/docs/source/topics/custom_chart_engine.rst +++ b/docs/source/topics/custom_chart_engine.rst @@ -1,31 +1,47 @@ Custom Charting Engine ====================== +In this guide we will add some Apex charts to the demo app. +to demonstrate how you can add your own charting engine to slick reporting. -To add a new chart engine you add it to the settings and provide an entry point function for the front end +#. We need to add the new chart Engine to the settings .. code-block:: python - SLICK_REPORTING_SETTINGS_DEFAULT = { + SLICK_REPORTING_SETTINGS = { "CHARTS": { "apexcharts": { "entryPoint": "DisplayChart", "js": ("https://cdn.jsdelivr.net/npm/apexcharts",), - "css": "https://cdn.jsdelivr.net/npm/apexcharts/dist/apexcharts.min.css", + "css": { + "all": "https://cdn.jsdelivr.net/npm/apexcharts/dist/apexcharts.min.css" + }, } }, } -and then you add the entry point function to the front end +#. and then you add the entry point function to the front end javascript .. code-block:: javascript - function displayChart(data, $elem, chart_id) { + function displayChart(data, $elem, chartOptions) { // data is the ajax response coming from server // $elem is the jquery element where the chart should be rendered - // chart_id is the id of the chart, which is teh index of teh needed chart in the [data.chart_settings] array + // chartOptions is the relevant chart dictionary/object in your ReportView chart_settings } -The data is a json object with the following structure \ No newline at end of file +Complete example: +----------------- + +.. code-block:: python + + class ProductSalesApexChart(ReportView): + report_title = _("Product Sales Apex Charts") + report_model = SalesTransaction + date_field = "date" + group_by = "product" + + chart_engine = "apexcharts" # + template_name = "demo/apex_report.html" diff --git a/slick_reporting/app_settings.py b/slick_reporting/app_settings.py index 1ade347..d01988d 100644 --- a/slick_reporting/app_settings.py +++ b/slick_reporting/app_settings.py @@ -41,6 +41,24 @@ def get_end_date(): "JQUERY_URL": SLICK_REPORTING_JQUERY_URL, "DEFAULT_START_DATE_TIME": get_start_date(), "DEFAULT_END_DATE_TIME": get_end_date(), + "MEDIA": { + "override": False, + "js": ( + "https://cdn.jsdelivr.net/momentjs/latest/moment.min.js", + "https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js", + "https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js", + "https://cdn.datatables.net/1.13.4/js/dataTables.bootstrap5.min.js", + "slick_reporting/slick_reporting.js", + "slick_reporting/slick_reporting.report_loader.js", + "slick_reporting/slick_reporting.datatable.js", + ), + "css": { + "all": ( + "https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css", + "https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css", + ) + }, + }, "FONT_AWESOME": { "CSS_URL": "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css", "ICONS": { @@ -54,12 +72,12 @@ def get_end_date(): "CHARTS": { "highcharts": { "entryPoint": "$.slick_reporting.highcharts.displayChart", + "js": ("https://code.highcharts.com/highcharts.js", "slick_reporting/slick_reporting.highchart.js"), }, "chartsjs": { "entryPoint": "$.slick_reporting.chartsjs.displayChart", - } - # "highcharts": "$.slick_reporting.highcharts.displayChart", - # "chartjs": "$.slick_reporting.chartjs.displayChart", + "js": ("https://cdn.jsdelivr.net/npm/chart.js", "slick_reporting/slick_reporting.chartsjs.js"), + }, }, "MESSAGES": { "total": _("Total"), @@ -91,3 +109,7 @@ def get_slick_reporting_settings(): SLICK_REPORTING_SETTINGS = lazy(get_slick_reporting_settings, dict)() + + +def get_media(): + return SLICK_REPORTING_SETTINGS["MEDIA"] diff --git a/slick_reporting/static/slick_reporting/slick_reporting.js b/slick_reporting/static/slick_reporting/slick_reporting.js index 5442699..bc575d9 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.js @@ -10,11 +10,11 @@ try { func = context[func]; if (typeof func == 'undefined') { - throw 'Function {0} is not found the context {1}'.format(functionName, context); + throw `Function ${functionName} is not found in the context ${context}` } } catch (err) { - console.error('Function {0} is not found the context {1}'.format(functionName, context), err) + console.error(`Function ${functionName} is not found in the context ${context}`, err) } return func.apply(context, args); } diff --git a/slick_reporting/templates/slick_reporting/base.html b/slick_reporting/templates/slick_reporting/base.html index 6795984..6464070 100644 --- a/slick_reporting/templates/slick_reporting/base.html +++ b/slick_reporting/templates/slick_reporting/base.html @@ -32,9 +32,11 @@

{{ report_title }}

-{% include "slick_reporting/js_resources.html" %} + {% block extrajs %} + {% include "slick_reporting/js_resources.html" %} + {% endblock %} \ No newline at end of file diff --git a/slick_reporting/templates/slick_reporting/js_resources.html b/slick_reporting/templates/slick_reporting/js_resources.html index d852668..7fc3766 100644 --- a/slick_reporting/templates/slick_reporting/js_resources.html +++ b/slick_reporting/templates/slick_reporting/js_resources.html @@ -3,31 +3,33 @@ {% get_slick_reporting_settings as slick_reporting_settings %} {% add_jquery %} - - - - - - - +{% get_slick_reporting_media as media %} +{{ media }} +{##} +{##} +{##} + +{##} +{##} +{##} - - +{##} +{##} - - - - - +{##} +{##} +{##} +{##} +{##} - +{##} {{ slick_reporting_settings|json_script:"slick_reporting_settings" }} -{% endblock %} {% block content %}
@@ -51,4 +36,26 @@
+{% endblock %} + +{% block extrajs %} + {% include "slick_reporting/js_resources.html" %} + {# make sure to have the js_resources added to the dashboard page #} + + {% get_charts_media "all" %} + {# make sure to add all charts needed media, here the "all" arguments add all charts media to the page, #} + {# You can skip it and add needed media by hand #} + + + {% endblock %} \ No newline at end of file diff --git a/demo_proj/templates/demo/apex_report.html b/demo_proj/templates/demo/apex_report.html index 72744ad..58a9b92 100644 --- a/demo_proj/templates/demo/apex_report.html +++ b/demo_proj/templates/demo/apex_report.html @@ -7,15 +7,21 @@ {% endblock %} {% block extrajs %} -{{ block.super }} - {% get_charts_media report.get_chart_settings %} + {{ block.super }} diff --git a/slick_reporting/templates/slick_reporting/report.html b/slick_reporting/templates/slick_reporting/report.html index 59b710b..4081667 100644 --- a/slick_reporting/templates/slick_reporting/report.html +++ b/slick_reporting/templates/slick_reporting/report.html @@ -13,8 +13,17 @@

{% trans "Filters" %}

{% endif %} diff --git a/slick_reporting/views.py b/slick_reporting/views.py index b335d7a..c62c23c 100644 --- a/slick_reporting/views.py +++ b/slick_reporting/views.py @@ -116,6 +116,8 @@ class ReportViewBase(ReportGeneratorAPI, FormView): template_name = "slick_reporting/report.html" + export_actions = None + @staticmethod def form_filter_func(fkeys_dict): # todo revise @@ -152,6 +154,33 @@ def get_doc_types_q_filters(self): return [], [] + def get_export_actions(self): + """ + Hook to get the export options + :return: list of export options + """ + actions = ["export_csv"] if self.csv_export_class else [] + + if self.export_actions: + actions = actions + self.export_actions + + export_actions = [] + + for action in actions: + func = getattr(self, action, None) + parameter = action.replace("export_", "") + + export_actions.append( + { + "name": action, + "title": getattr(func, "title", action.replace("_", " ").title()), + "icon": getattr(func, "icon", ""), + "css_class": getattr(func, "css_class", ""), + "parameter": parameter, + } + ) + return export_actions + def get(self, request, *args, **kwargs): form_class = self.get_form_class() self.form = self.get_form(form_class) @@ -181,6 +210,10 @@ def get(self, request, *args, **kwargs): def export_csv(self, report_data): return self.csv_export_class(self.request, report_data, self.report_title).get_response() + export_csv.title = SLICK_REPORTING_SETTINGS["MESSAGES"]["export_to_csv"] + export_csv.css_class = "btn btn-primary" + export_csv.icon = "" + @classmethod def get_report_model(cls): if cls.queryset is not None: From 2f90e991d4abdef760dc5c0b236b3c67c1da90cc Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Thu, 28 Sep 2023 19:46:51 +0300 Subject: [PATCH 05/23] Adjusting the export docs --- docs/source/topics/exporting.rst | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/source/topics/exporting.rst b/docs/source/topics/exporting.rst index face7d3..3246892 100644 --- a/docs/source/topics/exporting.rst +++ b/docs/source/topics/exporting.rst @@ -7,19 +7,36 @@ To trigger an export to CSV, just add ``?_export=csv`` to the url. This is perfo This will call the export_csv on the view class, engaging a `ExportToStreamingCSV` -You can extend the functionality, say you want to export to pdf. -Add a ``export_pdf`` method to the view class, accepting the report_data json response and return the response you want. -This ``export_pdf` will be called automatically when url parameter contain ``?_export=pdf`` - Having an `_export` parameter not implemented, ie the view class do not implement ``export_{parameter_name}``, will be ignored. +Configuring the CSV export option +--------------------------------- + +You can disable the CSV export option by setting the ``csv_export_class`` attribute to ``False`` on the view class. +and you can override the function and its attributes to customize the button text + +.. code-block:: python + + class CustomExportReport(GroupByReport): + report_title = _("Custom Export Report") + + def export_csv(self, report_data): + return super().export_csv(report_data) + + export_csv.title = _("My Custom CSV export Title") + export_csv.css_class = "btn btn-success" + + Adding an export option ----------------------- -To add an export option you need to add the function to the view class. +You can extend the functionality, say you want to export to pdf. +Add a ``export_pdf`` method to the view class, accepting the report_data json response and return the response you want. +This ``export_pdf` will be called automatically when url parameter contain ``?_export=pdf`` -For example, to add a pdf export option, add the following to the view class: + +Example to add a pdf export option: .. code-block:: python @@ -36,20 +53,3 @@ For example, to add a pdf export option, add the following to the view class: The export function should accept the report_data json response and return the response you want. -Configuring the CSV export option ---------------------------------- - -You can disable the CSV export option by setting the ``csv_export_class`` attribute to ``False`` on the view class. -and you can override the function and its attributes to customize the button text - -.. code-block:: python - - class CustomExportReport(GroupByReport): - report_title = _("Custom Export Report") - - def export_csv(self, report_data): - return super().export_csv(report_data) - - export_csv.title = _("My Custom CSV export Title") - export_csv.css_class = "btn btn-success" - From c02e5c8caaac66cc11805dd6e0b95bc30c5ef58d Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Thu, 28 Sep 2023 20:09:41 +0300 Subject: [PATCH 06/23] working on the docs --- demo_proj/templates/demo/apex_report.html | 10 +- docs/source/howto/customize_frontend.rst | 17 --- docs/source/ref/settings.rst | 3 +- .../{custom_chart_engine.rst => charts.rst} | 100 ++++++++++++------ docs/source/topics/index.rst | 1 + 5 files changed, 77 insertions(+), 54 deletions(-) rename docs/source/topics/{custom_chart_engine.rst => charts.rst} (53%) diff --git a/demo_proj/templates/demo/apex_report.html b/demo_proj/templates/demo/apex_report.html index 58a9b92..08d5bac 100644 --- a/demo_proj/templates/demo/apex_report.html +++ b/demo_proj/templates/demo/apex_report.html @@ -1,5 +1,5 @@ {% extends "slick_reporting/report.html" %} -{% load i18n slick_reporting_tags %} +{% load slick_reporting_tags %} {% block content %} {{ block.super }} @@ -12,13 +12,13 @@ + + {% endblock %} + +Adding a new charting engine +---------------------------- + +In the following part we will add some Apex charts to the demo app to demonstrate how you can add your own charting engine to slick reporting. + +#. We need to add the new chart Engine to the settings. Note that the css and js are specified and handled like Django's ``Form.Media`` .. code-block:: python @@ -24,7 +87,7 @@ to demonstrate how you can add your own charting engine to slick reporting. }, } -#. and then you add the entry point function to the javascript file `js_file_for_apex_chart.js` in this example. +#. Add the entry point function to the javascript file `js_file_for_apex_chart.js` in this example. It can look something like this: @@ -76,28 +139,3 @@ It can look something like this: chart.render(); } - -Customizing the entryPoint for a chart --------------------------------------- - -Sometimes you want just to display the chart differently, in this case, you can just change the entryPoint function - -Example: - -.. code-block:: python - - class ProductSalesApexChart(ReportView): - # .. - chart_settings = [ - # .. - Chart( - "Total sold $", - type="bar", - data_source=["value__sum"], - title_source=["name"], - entryPoint="displayChartCustomEntryPoint", # this is the new entryPoint - ), - ] - - - diff --git a/docs/source/topics/index.rst b/docs/source/topics/index.rst index 3cfc7e2..e638d4f 100644 --- a/docs/source/topics/index.rst +++ b/docs/source/topics/index.rst @@ -33,4 +33,5 @@ You saw how to use the ReportView class in the tutorial and you identified the t filter_form widgets integrating_slick_reporting + charts exporting From 49d9de564922312f06bf63736d391b5af8d7b0a4 Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Mon, 2 Oct 2023 00:17:18 +0300 Subject: [PATCH 07/23] Clean code and add to CHANGELOG.md --- CHANGELOG.md | 7 ++++++ .../slick_reporting.chartsjs.js | 9 -------- .../slick_reporting.report_loader.js | 1 - .../slick_reporting/js_resources.html | 22 ------------------- 4 files changed, 7 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 177c64a..9d7cd60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [1.1.2] - 2023-09-29 +- Enhance Chartjs internal +- Moving all css and js resources to be handled by `Media` governed by `settings.SLICK_REPORTING_SETTINGS` +- Add ``get_slick_reporting_media`` and ``get_charts_media`` templatetags +- Simplify adding export options and customizing the builtin export to csv button +- Simplify adding custom buttons to the report page + ## [1.1.1] - 2023-09-25 - Change settings to be a dict , adding support JQUERY_URL and FONT AWESOME customization #79 & #81 - Fix issue with chartjs not being loaded #80 diff --git a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js index 51a7b02..304de13 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js @@ -140,15 +140,6 @@ 'datasets': datasets, } } - // for (let i = 0; i < response.data.length; i++) { - // let row = response.data[i]; - // if (titleFieldName !== '') { - // let txt = row[titleFieldName]; - // txt = $(txt).text() || txt; // the title is an #} -{##} -{##} - -{##} -{##} -{##} - -{##} -{##} - - -{##} -{##} -{##} -{##} -{##} - -{##} - {{ slick_reporting_settings|json_script:"slick_reporting_settings" }} + + +Live example: +------------- + +You can see a live example of the widgets in the `Demo project- Dashboard Page `_. diff --git a/slick_reporting/templates/slick_reporting/js_resources.html b/slick_reporting/templates/slick_reporting/js_resources.html index 500c245..26263d2 100644 --- a/slick_reporting/templates/slick_reporting/js_resources.html +++ b/slick_reporting/templates/slick_reporting/js_resources.html @@ -10,8 +10,3 @@ href="{{ slick_reporting_settings.FONT_AWESOME.CSS_URL }}"/> {{ slick_reporting_settings|json_script:"slick_reporting_settings" }} - - From 8a5ec47ffa66bf3f949d5a8700e19f09a92176e6 Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Tue, 10 Oct 2023 08:27:03 +0300 Subject: [PATCH 23/23] Release preparation --- CHANGELOG.md | 11 +++++---- slick_reporting/__init__.py | 4 ++-- .../templates/slick_reporting/report.html | 10 +++----- .../templatetags/slick_reporting_tags.py | 24 ------------------- 4 files changed, 11 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dec84b..998c451 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,15 @@ All notable changes to this project will be documented in this file. -## [1.1.2] - 2023-09-29 -- Enhance Chartjs internal -- Moving all css and js resources to be handled by `Media` governed by `settings.SLICK_REPORTING_SETTINGS` +## [1.2.0] - 2023-10-10 - Add ``get_slick_reporting_media`` and ``get_charts_media`` templatetags -- Simplify adding export options and customizing the builtin export to csv button -- Simplify adding custom buttons to the report page - Add `get_group_by_custom_querysets` hook to ReportView +- Enhance and document adding export options and customizing the builtin export to csv button +- Enhance and document adding custom buttons to the report page +- Enhance and document adding a new chart engine - Fix in SlickReportingListView +- Move all css and js resources to be handled by `Media` governed by `settings.SLICK_REPORTING_SETTINGS` + ## [1.1.1] - 2023-09-25 - Change settings to be a dict , adding support JQUERY_URL and FONT AWESOME customization #79 & #81 diff --git a/slick_reporting/__init__.py b/slick_reporting/__init__.py index 1c16be3..343aaab 100644 --- a/slick_reporting/__init__.py +++ b/slick_reporting/__init__.py @@ -1,5 +1,5 @@ default_app_config = "slick_reporting.apps.ReportAppConfig" -VERSION = (1, 1, 1) +VERSION = (1, 2, 0) -__version__ = "1.1.1" +__version__ = "1.2.0" diff --git a/slick_reporting/templates/slick_reporting/report.html b/slick_reporting/templates/slick_reporting/report.html index 4081667..8665422 100644 --- a/slick_reporting/templates/slick_reporting/report.html +++ b/slick_reporting/templates/slick_reporting/report.html @@ -17,13 +17,11 @@

{% trans "Filters" %}

{% for export_action in report.get_export_actions %} - - -{# #} {% endfor %} -{# #} {% endif %} @@ -48,8 +46,6 @@
{% trans "Results" %}
-{# {% get_charts_js_resources report %}#} -{# {% get_charts_css_resources report %}#} {% endblock %} {% block extrajs %} diff --git a/slick_reporting/templatetags/slick_reporting_tags.py b/slick_reporting/templatetags/slick_reporting_tags.py index 36db0a2..a2ff394 100644 --- a/slick_reporting/templatetags/slick_reporting_tags.py +++ b/slick_reporting/templatetags/slick_reporting_tags.py @@ -9,28 +9,6 @@ register = template.Library() -@register.simple_tag -def get_data(row, column): - return row[column["name"]] - - -# -# def jsonify(object): -# def date_handler(obj): -# if hasattr(obj, "isoformat"): -# return obj.isoformat() -# elif isinstance(obj, Promise): -# return force_str(obj) -# -# if isinstance(object, QuerySet): -# return serialize("json", object) -# -# return mark_safe(json.dumps(object, use_decimal=True, default=date_handler)) -# -# -# register.filter("jsonify", jsonify) - - @register.simple_tag def get_widget_from_url(url_name=None, url=None, **kwargs): _url = "" @@ -104,6 +82,4 @@ def get_slick_reporting_media(): @register.simple_tag def get_slick_reporting_settings(): - from slick_reporting.app_settings import SLICK_REPORTING_SETTINGS - return dict(SLICK_REPORTING_SETTINGS)