This is a preview of the Reports functionality.
It allows defining report templates and then create reports based on the templates. A template defines: - parameters - to be set in the report (currently only selection of campaigns, in the future to be extended to selection of lists/segments, and selection from pre-defined options) - data retrieval / processing code (in Javascript) - rendering template (in Handlebars) This main functionality is accompanied by a few minor tweaks here and there. Worth notice is the ability to use server-side ajax table s for multi-selection of campaigns. This is meant for reports that compare data across multiple campaigns. This could possibly be even used for some poor man's A/B testing. Note that the execution of custom JavaScript in the data retrieval / processing code and definition of custom Handlebars templates is a security issue. This should however be OK in the general case once proper user management with granular permissions is in. This is because definition of a report template is anyway such an expert task that it would normally be performed only by admin. Instantiation of reports based on report templates can be then done by any user because this should no longer be any security problem.
This commit is contained in:
parent
2afeb74e68
commit
6ba04d7ff4
31 changed files with 1737 additions and 13 deletions
24
views/report-templates/create.hbs
Normal file
24
views/report-templates/create.hbs
Normal file
|
@ -0,0 +1,24 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li><a href="/report-templates">{{#translate}}Templates{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Create Template{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<h2>{{#translate}}Create Report Template{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<form class="form-horizontal" method="post" action="/report-templates/create">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
|
||||
{{> report_template_fields }}
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-plus"></i> {{#translate}}Create Template{{/translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
36
views/report-templates/edit.hbs
Normal file
36
views/report-templates/edit.hbs
Normal file
|
@ -0,0 +1,36 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li><a href="/report-templates">{{#translate}}Templates{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Edit Template{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<h2>{{#translate}}Edit Report Template{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<form method="post" class="delete-form" id="report-templates-delete" action="/report-templates/delete">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
<input type="hidden" name="id" value="{{id}}" />
|
||||
</form>
|
||||
|
||||
|
||||
<form class="form-horizontal" method="post" action="/report-templates/edit">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
<input type="hidden" name="id" value="{{id}}" />
|
||||
|
||||
{{> report_template_fields }}
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="pull-right">
|
||||
<button type="submit" form="report-templates-delete" class="btn btn-danger"><i class="glyphicon glyphicon-remove"></i> {{#translate}}Delete Template{{/translate}}</button>
|
||||
</div>
|
||||
<button type="submit" name="submit" value="update-and-stay" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> {{#translate}}Update and Stay{{/translate}}</button>
|
||||
<button type="submit" name="submit" value="update-and-leave" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> {{#translate}}Update and Leave{{/translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
59
views/report-templates/partials/report-template-fields.hbs
Normal file
59
views/report-templates/partials/report-template-fields.hbs
Normal file
|
@ -0,0 +1,59 @@
|
|||
<div class="form-group">
|
||||
<label for="name" class="col-sm-2 control-label">{{#translate}}Name{{/translate}}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control input-lg" name="name" id="name" value="{{name}}" placeholder="{{#translate}}Template Name{{/translate}}" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-sm-2 control-label">{{#translate}}Description{{/translate}}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" rows="3" name="description" id="description">{{description}}</textarea>
|
||||
<span class="help-block">{{#translate}}HTML is allowed{{/translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="mimeType" class="col-sm-2 control-label">{{#translate}}Type{{/translate}}</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="mimeType" class="form-control">
|
||||
{{#each mimeTypes}}
|
||||
<option value="{{key}}" {{#if selected}} selected {{/if}}>{{value}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{#translate}}User selectable fields{{/translate}}</label>
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="help-block" style="margin-top: -8px;">
|
||||
<small>JSON specification of user selectable fields.</small>
|
||||
</div>
|
||||
<div class="code-editor-json" style="height: 250px; border: 1px solid #ccc;"></div>
|
||||
<input type="hidden" name="userFields" value="{{userFields}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{#translate}}Data processing code{{/translate}}</label>
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="help-block" style="margin-top: -8px;">
|
||||
<small>Write the body of the JavaScript function with signature <code>function(inputs, callback)</code> that returns an object to be rendered by the Handlebars template below.</small>
|
||||
</div>
|
||||
<div class="code-editor-javascript" style="height: 700px; border: 1px solid #ccc;"></div>
|
||||
<input type="hidden" name="js" value="{{js}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{#translate}}Rendering template{{/translate}}</label>
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="help-block" style="margin-top: -8px;">
|
||||
<small>Use HTML with Handlebars syntax. See documentation <a href="http://handlebarsjs.com/">here</a>.</small>
|
||||
</div>
|
||||
<div class="code-editor-handlebars" style="height: 700px; border: 1px solid #ccc;"></div>
|
||||
<input type="hidden" name="hbs" value="{{hbs}}">
|
||||
</div>
|
||||
</div>
|
||||
|
44
views/report-templates/report-templates.hbs
Normal file
44
views/report-templates/report-templates.hbs
Normal file
|
@ -0,0 +1,44 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Templates{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{#translate}}Create Template{{/translate}} <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/report-templates/create">{{#translate}}Blank{{/translate}}</a></li>
|
||||
<li><a href="/report-templates/create?type=subscribers-all">{{#translate}}All Subscribers{{/translate}}</a></li>
|
||||
<li><a href="/report-templates/create?type=subscribers-grouped">{{#translate}}Grouped Subscribers{{/translate}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>{{#translate}}Report Templates{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/report-templates" data-sort-column="2" data-sort-order="desc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,0,1,0">
|
||||
<thead>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Name{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Description{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Created{{/translate}}
|
||||
</th>
|
||||
<th class="col-md-1">
|
||||
|
||||
</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
23
views/reports/create-select-template.hbs
Normal file
23
views/reports/create-select-template.hbs
Normal file
|
@ -0,0 +1,23 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Create Report{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<h2>{{#translate}}Create Report{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<form class="form-horizontal" method="get" action="/reports/create">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
|
||||
{{> report_select_template }}
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-chevron-right"></i> {{#translate}}Next{{/translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
23
views/reports/create.hbs
Normal file
23
views/reports/create.hbs
Normal file
|
@ -0,0 +1,23 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Create Report{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<h2>{{#translate}}Create Report{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<form class="form-horizontal" method="post" action="/reports/create">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
|
||||
{{> report_fields }}
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-plus"></i> {{#translate}}Create Report{{/translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
34
views/reports/edit.hbs
Normal file
34
views/reports/edit.hbs
Normal file
|
@ -0,0 +1,34 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Edit Report{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<h2>{{#translate}}Edit Report{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<form method="post" class="delete-form" id="reports-delete" action="/reports/delete">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
<input type="hidden" name="id" value="{{id}}" />
|
||||
</form>
|
||||
|
||||
|
||||
<form class="form-horizontal" method="post" action="/reports/edit">
|
||||
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
||||
<input type="hidden" name="id" value="{{id}}" />
|
||||
|
||||
{{> report_fields }}
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="pull-right">
|
||||
<button type="submit" form="reports-delete" class="btn btn-danger"><i class="glyphicon glyphicon-remove"></i> {{#translate}}Delete Report{{/translate}}</button>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> {{#translate}}Update{{/translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
49
views/reports/partials/report-fields.hbs
Normal file
49
views/reports/partials/report-fields.hbs
Normal file
|
@ -0,0 +1,49 @@
|
|||
{{> report_select_template options="readonly" }}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-sm-2 control-label">{{#translate}}Name{{/translate}}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control input-lg" name="name" id="name" value="{{name}}" placeholder="{{#translate}}Report Name{{/translate}}" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-sm-2 control-label">{{#translate}}Description{{/translate}}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" rows="3" name="description" id="description">{{description}}</textarea>
|
||||
<span class="help-block">{{#translate}}HTML is allowed{{/translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#each userFields}}
|
||||
{{#switch type}}
|
||||
{{#case "campaign"}}
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-sm-2 control-label">{{name}}</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/campaigns/quicklist" data-sort-column="2" data-sort-order="desc" class="table table-bordered table-hover data-table-ajax data-table-{{#if isMulti}}multi{{/if}}selectable display nowrap" width="100%" data-row-sort="0,1,0,1">
|
||||
<thead>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Name{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Description{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Created{{/translate}}
|
||||
</th>
|
||||
</thead>
|
||||
</table>
|
||||
<input type="hidden" name="{{id}}Selection" value="{{value}}" />
|
||||
</div>
|
||||
<span class="help-block">{{#translate}}Select a campaign in the table above by clicking on the respective row number.{{/translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/case}}
|
||||
{{/switch}}
|
||||
{{/each}}
|
||||
|
11
views/reports/partials/report-select-template.hbs
Normal file
11
views/reports/partials/report-select-template.hbs
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div class="form-group">
|
||||
<label for="name" class="col-sm-2 control-label">{{#translate}}Report Template{{/translate}}</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="reportTemplate" name="reportTemplate" required {{options}}>
|
||||
<option value=""> –– {{#translate}}Select{{/translate}} –– </option>
|
||||
{{#each reportTemplates}}
|
||||
<option value="{{id}}" {{#if selected}} selected {{/if}}>{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
39
views/reports/reports.hbs
Normal file
39
views/reports/reports.hbs
Normal file
|
@ -0,0 +1,39 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li class="active">{{#translate}}Reports{{/translate}}</li>
|
||||
</ol>
|
||||
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" href="/reports/create" role="button"><i class="glyphicon glyphicon-plus"></i> {{#translate}}Create Report{{/translate}}</a>
|
||||
|
||||
<a class="btn btn-primary" href="/report-templates" role="button">{{#translate}}Report Templates{{/translate}}</a>
|
||||
</div>
|
||||
|
||||
<h2>{{#translate}}Reports{{/translate}}</h2>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/reports" data-sort-column="2" data-sort-order="desc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,0,1,0">
|
||||
<thead>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Name{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Template{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Description{{/translate}}
|
||||
</th>
|
||||
<th>
|
||||
{{#translate}}Created{{/translate}}
|
||||
</th>
|
||||
<th class="col-md-1">
|
||||
|
||||
</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
7
views/reports/view.hbs
Normal file
7
views/reports/view.hbs
Normal file
|
@ -0,0 +1,7 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">{{#translate}}Home{{/translate}}</a></li>
|
||||
<li><a href="/reports/">{{#translate}}Reports{{/translate}}</a></li>
|
||||
<li class="active">{{title}}</li>
|
||||
</ol>
|
||||
|
||||
{{report}}
|
Loading…
Add table
Add a link
Reference in a new issue