class AttributeTable(tables.Table): """ Table to render the list of attributes attached to a workflow """ name = tables.Column(verbose_name=_('Name')) value = tables.Column(verbose_name=_('Value')) operations = OperationsColumn( verbose_name='', template_file='workflow/includes/partial_attribute_operations.html', template_context=lambda record: { 'id': record['id'], }) def render_name(self, record): return format_html( """<a href="#" data-toggle="tooltip" class="js-attribute-edit" data-url="{0}" title="{1}">{2}</a>""", reverse('workflow:attribute_edit', kwargs={'pk': record['id']}), _('Edit the attribute'), record['name']) class Meta(object): fields = ('name', 'value', 'operations') attrs = { 'class': 'table', 'style': 'width: 100%;', 'id': 'attribute-table' }
class WorkflowShareTable(tables.Table): email = tables.Column(attrs={'td': { 'class': 'dt-body-center' }}, verbose_name=str('User')) operations = OperationsColumn( attrs={'td': { 'class': 'dt-body-center' }}, verbose_name='', orderable=False, template_file='workflow/includes/partial_share_operations.html', template_context=lambda x: {'id': x['id']}) class Meta: fields = ('email', 'id') sequence = ('email', 'operations') attrs = { 'class': 'table display', 'id': 'share-table', 'th': { 'class': 'dt-body-center' } }
class SQLConnectionTableRun(tables.Table): operations = OperationsColumn( verbose_name='Operations', template_file='dataops/includes/partial_sqlconn_runop.html', template_context=lambda record: {'id': record['id']}) def __init__(self, data, *args, **kwargs): table_id = kwargs.pop('id') super(SQLConnectionTableRun, self).__init__(data, *args, **kwargs) # If an ID was given, pass it on to the table attrs. if table_id: self.attrs['id'] = table_id class Meta: model = SQLConnection fields = ('name', 'description_txt', 'conn_type', 'conn_driver', 'db_user', 'db_password', 'db_host', 'db_port', 'db_name', 'db_table') sequence = ('name', 'description_txt', 'conn_type', 'conn_driver', 'db_user', 'db_password', 'db_host', 'db_port', 'db_name', 'db_table', 'operations') attrs = { 'class': 'table display table-bordered', 'id': 'sqlconn-table' }
class SQLConnectionTableRun(tables.Table): """Class to render the table of SQL connections.""" operations = OperationsColumn( verbose_name='', template_file='dataops/includes/partial_sqlconn_runop.html', template_context=lambda record: {'id': record['id']}, ) def render_name(self, record): """Render the name as a link.""" return format_html( '<a class="js-sqlconn-view" href="#" data-url="{0}">{1}</a>', reverse('dataops:sqlconn_view', kwargs={'pk': record['id']}), record['name'], ) class Meta(object): """Define models, fields, sequence and attributes.""" model = SQLConnection fields = ('name', 'description_txt') sequence = ('name', 'description_txt', 'operations') attrs = { 'class': 'table table-hover table-bordered shadow', 'style': 'width: 100%;', 'id': 'sqlconn-instructor-table', }
class ViewTable(tables.Table): """ Table to display the set of views handled in a workflow """ name = tables.Column(verbose_name=str('Name')) description_text = tables.Column( empty_values=[], verbose_name=str('Description') ) modified = tables.DateTimeColumn(verbose_name='Modified') operations = OperationsColumn( verbose_name='Operations', template_file='table/includes/partial_view_operations.html', template_context=lambda record: {'id': record['id']} ) class Meta: """ Select the model and specify fields, sequence and attributes """ model = View fields = ('name', 'description_text', 'modified', 'operations') sequence = ('name', 'description_text', 'modified', 'operations') attrs = { 'class': 'table display table-bordered', 'id': 'view-table' }
class ActionTable(tables.Table): """ Table to render the list of actions per workflow. The Operations column is taken from another class to centralise the customisation. """ name = tables.Column(verbose_name=_('Name')) description_text = tables.Column(verbose_name=_('Description')) action_type = tables.Column(verbose_name=_('Type')) last_executed_log = tables.Column(verbose_name=_('Last executed')) operations = OperationsColumn( verbose_name=_('Operations'), template_file='action/includes/partial_action_operations.html', template_context=lambda record: { 'id': record['id'], 'action_tval': record['action_tval'], 'is_out': int(record['is_out']), 'is_executable': record['is_executable'], 'serve_enabled': record['serve_enabled'] }) def render_last_executed_log(self, record): log_item = record['last_executed_log'] if not log_item: return "---" return format_html("""<a class="spin" href="{0}">{1}</a>""".format( reverse('logs:view', kwargs={'pk': log_item.id}), log_item.modified.astimezone(pytz.timezone(settings.TIME_ZONE)))) class Meta: model = Action fields = ('name', 'description_text', 'action_type', 'last_executed_log') sequence = ('name', 'description_text', 'action_type', 'last_executed_log') exclude = ('content', 'serve_enabled', 'columns', 'filter') attrs = {'class': 'table display table-bordered', 'id': 'action-table'} row_attrs = { 'style': 'text-align:center;', }
class ActionTable(tables.Table): """ Table to render the list of actions per workflow. The Operations column is taken from another class to centralise the customisation. """ name = tables.Column(verbose_name=str('Name')) is_out = tables.Column(verbose_name=str('Type')) description_text = tables.Column(verbose_name=str('Description')) modified = tables.DateTimeColumn(verbose_name='Modified') operations = OperationsColumn( verbose_name='Operations', template_file='action/includes/partial_action_operations.html', template_context=lambda record: { 'id': record['id'], 'is_out': int(record['is_out']), 'serve_enabled': record['serve_enabled'] } ) def render_is_out(self, record): if record['is_out']: return "OUT" else: return "IN" class Meta: model = Action fields = ('name', 'description_text', 'is_out', 'modified') sequence = ('name', 'description_text', 'is_out', 'modified') exclude = ('n_selected_rows', 'content', 'serve_enabled', 'columns', 'filter') attrs = { 'class': 'table display table-bordered', 'id': 'action-table' } row_attrs = { 'style': 'text-align:center;', 'class': lambda record: 'success' if record['is_out'] else '' }
class WorkflowTable(tables.Table): name = tables.Column(verbose_name=_('Name')) description_text = tables.Column(empty_values=[], verbose_name=_('Description')) nrows_cols = tables.Column(empty_values=[], verbose_name=_('Rows/Columns'), default=_('No data')) modified = tables.DateTimeColumn(verbose_name=_('Last modified')) def __init__(self, data, *args, **kwargs): table_id = kwargs.pop('id') super(WorkflowTable, self).__init__(data, *args, **kwargs) # If an ID was given, pass it on to the table attrs. if table_id: self.attrs['id'] = table_id def render_nrows_cols(self, record): if record['nrows'] == 0 and record['ncols'] == 0: return "No data" return format_html("{0}/{1}".format(record['nrows'], record['ncols'])) operations = OperationsColumn( verbose_name=_('Operations'), attrs={'td': { 'class': 'dt-body-center' }}, template_file='workflow/includes/workflow_basic_buttons.html', template_context=lambda record: {'workflow': record}) class Meta: model = Workflow fields = ('name', 'description_text', 'nrows_cols', 'modified') sequence = ('name', 'description_text', 'nrows_cols', 'modified') exclude = ('user', 'attributes', 'nrows', 'ncols', 'column_names', 'column_types', 'column_unique', 'query_builder_ops', 'data_frame_table_name') attrs = { 'class': 'table display table-bordered', 'id': 'workflow-table' }
class AttributeTable(tables.Table): """ Table to render the list of attributes attached to a workflow """ name = tables.Column(verbose_name=str('Name')) value = tables.Column(verbose_name=str('Value')) operations = OperationsColumn( verbose_name='Ops', template_file='workflow/includes/partial_attribute_operations.html', template_context=lambda record: { 'id': record['id'], }) class Meta: fields = ('name', 'value', 'operations') attrs = { 'class': 'table display table-bordered', 'id': 'attribute-table' }
class PluginRegistryTable(tables.Table): """ Table to render the list of plugins available for execution. The Operations column is inheriting from another class to centralise the customisation. """ filename = tables.Column(verbose_name=str('Folder')) name = tables.Column(verbose_name=str('Name')) description_txt = tables.Column(verbose_name=str('Description')) modified = tables.DateTimeColumn(verbose_name='Last modified') executed = tables.DateTimeColumn(verbose_name='Last executed') operations = OperationsColumn( verbose_name='Operations', template_file='dataops/includes/partial_plugin_operations.html', template_context=lambda record: { 'id': record.id, 'is_verified': record.is_verified }) class Meta: model = PluginRegistry fields = ('filename', 'name', 'description_txt', 'modified', 'is_verified', 'executed') sequence = ('filename', 'name', 'description_txt', 'modified', 'is_verified', 'executed') attrs = { 'class': 'table display table-bordered', 'id': 'transform-table' } row_attrs = { 'style': 'text-align:center;', }
class SQLConnectionTableAdmin(tables.Table): operations = OperationsColumn( verbose_name='', template_file='dataops/includes/partial_sqlconn_adminop.html', template_context=lambda record: {'id': record['id']}) def render_name(self, record): return format_html( """<a class="js-sqlconn-edit" href="#" data-url="{0}">{1}</a>""", reverse('dataops:sqlconn_edit', kwargs={'pk': record['id']}), record['name']) class Meta(object): model = SQLConnection fields = ('name', 'description_txt') sequence = ('name', 'description_txt', 'operations') attrs = { 'class': 'table table-hover table-bordered', 'style': 'width: 100%;', 'id': 'sqlconn-admin-table' }
class ViewTable(tables.Table): """Table to display the set of views handled in a workflow.""" name = tables.Column(verbose_name=_('Name')) description_text = tables.Column(empty_values=[], verbose_name=_('Description')) operations = OperationsColumn( verbose_name='', template_file='table/includes/partial_view_operations.html', template_context=lambda record: {'id': record['id']}, ) def render_name(self, record): """Render the name of the action as a link.""" return format_html( """<a href="#" class="js-view-edit" data-toggle="tooltip" data-url="{0}" title="{1}">{2}</a>""", reverse('table:view_edit', kwargs={'pk': record['id']}), _('Change the columns present in the view'), record['name'], ) class Meta(object): """Select the model and specify fields, sequence and attributes.""" model = View fields = ('name', 'description_text', 'operations') sequence = ('name', 'description_text', 'operations') attrs = { 'class': 'table table-hover table-bordered shadow', 'style': 'width: 100%;', 'id': 'view-table', }
class SQLConnectionTableRun(tables.Table): operations = OperationsColumn( verbose_name='', template_file='dataops/includes/partial_sqlconn_runop.html', template_context=lambda record: {'id': record['id']}) def render_name(self, record): return format_html( '<a class="js-sqlconn-view" href="#" data-url="{0}">{1}' ' <span class="fa fa-eye"></span> </a>', reverse('dataops:sqlconn_view', kwargs={'pk': record['id']}), record['name']) class Meta(object): model = SQLConnection fields = ('name', 'description_txt') sequence = ('name', 'description_txt', 'operations') attrs = { 'class': 'table table-hover table-bordered', 'style': 'width: 100%;', 'id': 'sqlconn-instructor-table' }
class ActionTable(tables.Table): """ Table to render the list of actions per workflow. The Operations column is taken from another class to centralise the customisation. """ name = tables.Column(verbose_name=_('Name')) description_text = tables.Column(verbose_name=_('Description')) action_type = tables.Column(verbose_name=_('Type')) last_executed_log = tables.Column(verbose_name=_('Last executed')) # # Operatiosn available per action type (see partial_action_operations.html) # # Action type | Email | ZIP | URL | RUN | # ------------------------------------------------------------ # Personalized text | X | X | X | | # Personalized canvas email | X | | | | # Personalized JSON | | | ? | X | # Survey | | | X | X | # Todo List | | | X | X | # operations = OperationsColumn( verbose_name='', template_file='action/includes/partial_action_operations.html', template_context=lambda record: { 'id': record.id, 'action_tval': record.action_type, 'is_out': int(record.is_out), 'is_executable': record.is_executable, 'serve_enabled': record.serve_enabled }) def render_name(self, record): return format_html( """<a href="{0}" data-toggle="tooltip" title="{1}">{2}</a>""", reverse('action:edit', kwargs={'pk': record.id}), _('Edit the text, conditions and filter'), record.name) def render_action_type(self, record): icon = 'file-text' title = 'Personalized text' if record.action_type == Action.PERSONALIZED_TEXT: icon = 'file-text' title = 'Personalized text' elif record.action_type == Action.PERSONALIZED_CANVAS_EMAIL: icon = 'envelope-square' title = 'Personalized Canvas Email' elif record.action_type == Action.PERSONALIZED_JSON: icon = 'code' title = 'Personalized JSON' elif record.action_type == Action.SURVEY: icon = 'question-circle-o' title = 'Survey' return format_html( """<div data-toggle="tooltip" title="{0}"> <span class="fa fa-{1}"></span></div>""", title, icon) def render_last_executed_log(self, record): log_item = record.last_executed_log if not log_item: return "---" return format_html("""<a class="spin" href="{0}">{1}</a>""", reverse('logs:view', kwargs={'pk': log_item.id}), simplify_datetime_str(log_item.modified)) class Meta(object): model = Action fields = ('name', 'description_text', 'action_type', 'last_executed_log') sequence = ('action_type', 'name', 'description_text', 'last_executed_log') exclude = ('content', 'serve_enabled', 'columns', 'filter') attrs = { 'class': 'table table-hover table-bordered', 'style': 'width: 100%;', 'id': 'action-table' }
class ScheduleActionTable(tables.Table): """Table to show the email actions scheduled for a workflow.""" action = tables.LinkColumn( verbose_name=_('Action'), viewname='action:edit', text=lambda record: record.action.name, kwargs={'pk': A('action.id')}, attrs={ 'a': { 'class': 'spin', 'data-toggle': 'tooltip', 'title': _('Edit the action scheduled for execution'), }, 'td': { 'data-backcolor': lambda record: record.action.action_type }, }, ) operations = OperationsColumn( verbose_name='', orderable=False, template_file='scheduler/includes/partial_scheduler_operations.html', template_context=lambda record: {'id': record.id}, ) name = tables.Column(verbose_name=_('Name')) execute = tables.DateTimeColumn(verbose_name=_('Scheduled')) status = tables.Column(verbose_name=_('Status'), accessor=A('get_status_display')) def render_name(self, record): """Render name as link.""" return format_html( '<a href="{0}" data-toggle="tooltip" title="{1}">{2}</a>', reverse('scheduler:edit', kwargs={'pk': record.id}), _('Edit this scheduled action execution'), record.name) def render_status(self, record): """Render status as a link.""" log_item = record.last_executed_log if not log_item: return record.get_status_display() # At this point, the object is not pending. Produce a link return format_html('<a class="spin" href="{0}">{1}</a>', reverse('logs:view', kwargs={'pk': log_item.id}), record.get_status_display()) class Meta(object): """Choose model, fields and sequence in the table.""" model = ScheduledAction fields = ('name', 'action', 'execute', 'status') sequence = ('name', 'action', 'execute', 'status', 'operations') attrs = { 'class': 'table table-hover table-bordered shadow', 'style': 'width: 100%;', 'id': 'scheduler-table' }
class ScheduleEmailActionTable(tables.Table): """ Table to show the email actions scheduled for a workflow """ operations = OperationsColumn( attrs={'td': { 'class': 'dt-body-center' }}, verbose_name=_('Operations'), orderable=False, template_file='scheduler/includes/partial_scheduler_operations.html', template_context=lambda record: {'id': record.id}) action = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Action'), accessor=A('action.name')) execute = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Scheduled')) status = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Status')) subject = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Subject')) email_column = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Email column'), ) cc_email = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('CC Emails'), ) bcc_email = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('BCC Emails'), ) send_confirmation = BooleanColumn( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Send confirmation'), get_field=lambda x: x.send_confirmation, ) track_read = BooleanColumn( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Track'), get_field=lambda x: x.track_read, ) message = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Execution message'), ) def render_action(self, record): return format_html('<a href="{0}">{1}</a>'.format( reverse('action:edit_out', kwargs={'pk': record.action.id}), record.action.name)) class Meta: model = ScheduledEmailAction fields = ('action', 'created', 'execute', 'status', 'subject', 'email_column', 'cc_email', 'bcc_email', 'send_confirmation', 'track_read', 'operations', 'message') sequence = ('operations', 'action', 'created', 'execute', 'status', 'subject', 'email_column', 'cc_email', 'bcc_email', 'send_confirmation', 'track_read', 'message') attrs = { 'class': 'table display table-bordered', 'id': 'scheduler-table' } row_attrs = { 'style': 'text-align:center;', 'class': lambda record: 'success' if record.status == 0 else '' }
def edit_action_in(request, workflow, action): """ View to handle the AJAX form to edit an action in (filter + columns). :param request: Request object :param workflow: workflow :param action: Action :return: HTTP response """ # Get filter or None filter_condition = action.get_filter() # Get the number of rows in DF selected by filter. if filter_condition: filter_condition.n_rows_selected = \ pandas_db.num_rows(action.workflow.id, filter_condition.formula) filter_condition.save() # Column names suitable to insert columns_selected = action.columns.filter(is_key=False).order_by('position') columns_to_insert = [ c for c in workflow.columns.all() if not c.is_key and c not in columns_selected ] # Has key column and has no-key column has_no_key = action.columns.filter(is_key=False).exists() has_empty_description = columns_selected.filter( description_text='').exists() # Create the context info. ctx = { 'action': action, 'filter_condition': filter_condition, 'selected_rows': filter_condition.n_rows_selected if filter_condition else -1, 'total_rows': workflow.nrows, 'query_builder_ops': workflow.get_query_builder_ops_as_str(), 'has_data': ops.workflow_has_table(action.workflow), 'key_selected': action.columns.filter(is_key=True).first(), 'columns_to_insert': columns_to_insert, 'column_selected_table': ColumnSelectedTable( columns_selected.values('id', 'name', 'description_text'), orderable=False, extra_columns=[('operations', OperationsColumn( verbose_name='Ops', template_file=ColumnSelectedTable.ops_template, template_context=lambda record: { 'id': record['id'], 'aid': action.id }))]), 'has_no_key': has_no_key, 'has_empty_description': has_empty_description } return render(request, 'action/edit_in.html', ctx)
def edit_action_in(request, pk): """ View to handle the AJAX form to edit an action in (filter + columns). :param request: Request object :param pk: Action PK :return: HTTP response """ # Check if the workflow is locked workflow = get_workflow(request) if not workflow: return redirect('workflow:index') if workflow.nrows == 0: messages.error(request, 'Workflow has no data. ' 'Go to Dataops to upload data.') return redirect(reverse('action:index')) # Get the action and the columns try: action = Action.objects.filter( Q(workflow__user=request.user) | Q(workflow__shared=request.user) ).distinct().prefetch_related('columns').get(pk=pk) except ObjectDoesNotExist: return redirect('action:index') if action.is_out: # Trying to edit an incorrect action. Redirect to index return redirect('action:index') # See if the action has a filter or not try: filter_condition = Condition.objects.get( action=action, is_filter=True ) except Condition.DoesNotExist: filter_condition = None except Condition.MultipleObjectsReturned: return render(request, 'error.html', {'message': 'Malfunction detected when retrieving filter ' '(action: {0})'.format(action.id)}) # Get the number of rows in DF selected by filter. if filter_condition: filter_condition.n_rows_selected = \ pandas_db.num_rows(action.workflow.id, filter_condition.formula) filter_condition.save() # Column names suitable to insert columns_selected = action.columns.filter(is_key=False).order_by('position') columns_to_insert = [c for c in workflow.columns.all() if not c.is_key and c not in columns_selected] # Has key column and has no-key column has_no_key = action.columns.filter(is_key=False).exists() has_empty_description = columns_selected.filter( description_text='' ).exists() # Create the context info. ctx = {'action': action, 'filter_condition': filter_condition, 'selected_rows': filter_condition.n_rows_selected if filter_condition else -1, 'total_rows': workflow.nrows, 'query_builder_ops': workflow.get_query_builder_ops_as_str(), 'has_data': ops.workflow_has_table(action.workflow), 'key_selected': action.columns.filter(is_key=True).first(), 'columns_to_insert': columns_to_insert, 'column_selected_table': ColumnSelectedTable( columns_selected.values('id', 'name', 'description_text'), orderable=False, extra_columns=[ ('operations', OperationsColumn( verbose_name='Ops', template_file=ColumnSelectedTable.ops_template, template_context=lambda record: {'id': record['id'], 'aid': action.id}) )] ), 'has_no_key': has_no_key, 'has_empty_description': has_empty_description} return render(request, 'action/edit_in.html', ctx)
def edit_action_in( request: HttpRequest, workflow: Workflow, action: Action, ) -> HttpResponse: """Edit an action in. :param request: Request object :param workflow: workflow :param action: Action :return: HTTP response """ # All tuples (action, column, condition) to consider tuples = action.column_condition_pair.all() # Columns all_columns = workflow.columns # Conditions filter_condition = action.get_filter() all_conditions = action.conditions.filter(is_filter=False) # Create the context info. context = { 'action': action, # Workflow elements 'total_rows': workflow.nrows, 'query_builder_ops': workflow.get_query_builder_ops_as_str(), 'has_data': workflow.has_table(), 'selected_rows': filter_condition.n_rows_selected if filter_condition else -1, 'all_false_conditions': any( cond.n_rows_selected == 0 for cond in all_conditions ), # Column elements 'key_columns': all_columns.filter(is_key=True), 'stat_columns': all_columns.filter(is_key=False), 'key_selected': tuples.filter(column__is_key=True).first(), 'has_no_key': tuples.filter(column__is_key=False).exists(), 'any_empty_description': tuples.filter( column__description_text='', column__is_key=False, ).exists(), 'columns_to_insert': all_columns.exclude( column_condition_pair__action=action, ).exclude( is_key=True, ).distinct().order_by('position'), 'column_selected_table': ColumnSelectedTable( tuples.filter(column__is_key=False).values( 'id', 'column__id', 'column__name', 'column__description_text', 'condition__name', ), orderable=False, extra_columns=[( 'operations', OperationsColumn( verbose_name='', template_file=ColumnSelectedTable.ops_template, template_context=lambda record: { 'id': record['column__id'], 'aid': action.id}), )], condition_list=all_conditions, ), # Conditions 'filter_condition': filter_condition, 'conditions': all_conditions, 'vis_scripts': PlotlyHandler.get_engine_scripts(), 'other_conditions': Condition.objects.filter( action__workflow=workflow, is_filter=False, ).exclude(action=action), } return render(request, 'action/edit_in.html', context)
class ScheduleActionTable(tables.Table): """ Table to show the email actions scheduled for a workflow """ operations = OperationsColumn( attrs={'td': { 'class': 'dt-body-center' }}, verbose_name=_('Operations'), orderable=False, template_file='scheduler/includes/partial_scheduler_operations.html', template_context=lambda record: {'id': record.id}) name = tables.Column(verbose_name=_('Name')) description_text = tables.Column(verbose_name=_('Description')) type = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Type'), accessor=A('action.get_action_type_display')) action = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Action'), accessor=A('action.name')) execute = tables.DateTimeColumn(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Scheduled')) status = tables.Column(attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Status'), accessor=A('get_status_display')) item_column = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Item column'), ) exclude_values = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Exclude'), ) payload = tables.Column( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Parameters'), ) last_executed_log = tables.DateTimeColumn( attrs={'td': { 'class': 'dt-center' }}, verbose_name=_('Result'), ) def render_action(self, record): return format_html('<a class="spin" href="{0}">{1}</a>'.format( reverse('action:edit', kwargs={'pk': record.action.id}), record.action.name)) def render_exclude_values(self, record): return ', '.join(record.exclude_values) def render_payload(self, record): result = '' if not record.payload: return result for k, v in sorted(record.payload.items()): if isinstance(v, list): result += '<li>{0}: {1}</li>'.format( escape(str(k)), escape(', '.join([str(x) for x in v]))) else: result += '<li>{0}: {1}</li>'.format(escape(str(k)), escape(str(v))) return format_html( '<ul style="text-align:left;">{0}<ul>'.format(result)) def render_last_executed_log(self, record): log_item = record.last_executed_log if not log_item: return "---" return format_html("""<a class="spin" href="{0}">{1}</a>""".format( reverse('logs:view', kwargs={'pk': log_item.id}), log_item.modified.astimezone(pytz.timezone(settings.TIME_ZONE)))) class Meta: model = ScheduledAction fields = ('name', 'description_text', 'action', 'execute', 'status', 'item_column', 'exclude_values', 'operations', 'last_executed_log') sequence = ('operations', 'name', 'description_text', 'type', 'action', 'execute', 'status', 'item_column', 'exclude_values', 'last_executed_log') attrs = { 'class': 'table display table-bordered', 'id': 'scheduler-table' } row_attrs = { 'style': 'text-align:center;', 'class': lambda record: 'success' \ if record.status == ScheduledAction.STATUS_PENDING else '' }
class ActionTable(tables.Table): """Class to render the list of actions per workflow. The Operations column is taken from another class to centralise the customisation. """ name = tables.Column(verbose_name=_('Name')) description_text = tables.Column(verbose_name=_('Description')) action_type = tables.TemplateColumn( template_name='action/includes/partial_action_type.html', verbose_name=_('Type'), attrs={ 'td': { 'data-backcolor': lambda record: record.action_type, }, }, ) last_executed_log = tables.LinkColumn( verbose_name=_('Last executed'), empty_values=['', None], viewname='logs:view', text=lambda record: simplify_datetime_str( record.last_executed_log.modified), kwargs={'pk': A('last_executed_log.id')}, attrs={'a': {'class': 'spin'}}, ) # # Operatiosn available per action type (see partial_action_operations.html) # # Action type | Email | ZIP | URL | RUN | # ------------------------------------------------------------ # Personalized text | X | X | X | X | # Personalized canvas email | X | | | X | # Personalized JSON | | | ? | X | # Survey | | | X | X | # Todo List | | | X | X | # operations = OperationsColumn( verbose_name='', template_file='action/includes/partial_action_operations.html', template_context=lambda record: { 'id': record.id, 'action_tval': record.action_type, 'is_out': int(record.is_out), 'is_executable': record.is_executable, 'serve_enabled': record.serve_enabled}, ) def render_name(self, record): """Render name as a link with a potential flag.""" return render_to_string( 'action/includes/partial_action_name.html', context={ 'action_id': record.id, 'danger_msg': ( record.get_row_all_false_count or not record.is_executable ), 'action_name': record.name, }, ) class Meta(object): """Define model, fields and ordering.""" model = Action fields = ( 'name', 'description_text', 'action_type', 'last_executed_log', ) sequence = ( 'action_type', 'name', 'description_text', 'last_executed_log', ) exclude = ('content', 'serve_enabled', 'filter') attrs = { 'class': 'table table-hover table-bordered shadow', 'style': 'width: 100%;', 'id': 'action-table', }