Пример #1
0
    def ready(self):
        """Auto load Trionyx"""
        enable_db_logger()

        models_config.auto_load_configs()

        from trionyx import widgets  # noqa F401
        self.auto_load_app_modules(['layouts', 'signals', 'forms', 'widgets'])

        app_menu.auto_load_model_menu()

        auto_register_search_models()

        from trionyx.views import tabs
        tabs.auto_generate_missing_tabs()

        from trionyx.trionyx.auditlog import init_auditlog
        init_auditlog()

        # Add admin menu items
        from trionyx.urls import model_url
        app_menu.add_item('dashboard',
                          _('Dashboard'),
                          url='/',
                          icon='fa fa-dashboard',
                          order=1)
        app_menu.add_item('admin',
                          _('Admin'),
                          icon='fa fa-cogs',
                          order=9000,
                          permission='is_superuser')
        app_menu.add_item('admin/users',
                          _('Users'),
                          url=model_url('trionyx.user', 'list'),
                          order=9010,
                          permission='is_superuser')
        app_menu.add_item('admin/groups',
                          _('Permission groups'),
                          url=model_url('auth.group', 'list'),
                          order=9010,
                          permission='is_superuser')
        app_menu.add_item('admin/logs',
                          _('Logs'),
                          url=model_url('trionyx.log', 'list'),
                          order=9090,
                          permission='is_superuser')

        # Add User renderer
        from trionyx.renderer import renderer
        renderer.register(
            get_user_model(), lambda value, **options:
            """<img src="{url}" class="avatar-sm" title="{user}">""".format(
                url=value.avatar.url
                if value.avatar else static('img/avatar.png'),
                user=str(value)))

        # Enable api route generation
        from trionyx.trionyx.urls import api_auto_router
        api_auto_router.app_ready = True
Пример #2
0
 def get_url(self,
             view_name: str,
             model: Model = None,
             code: str = None) -> str:
     """Get url for model"""
     from trionyx.urls import model_url
     return model_url(model if model else self.model, view_name, code)
Пример #3
0
    def get_layout(self, code, object, layout_id=None):
        """Get complete layout for given object"""
        if code not in self.layouts:
            raise LookupError('layout does not exist')

        layout_config = self.layouts.get(code)

        layout = layout_config['layout'](object)
        if isinstance(layout, Component):
            layout = Layout(layout)

        if isinstance(layout, list):
            layout = Layout(*layout)

        for update_layout in layout_config['updates']:
            try:
                update_layout(layout, object)
            except Exception as e:
                logger.error('Could not update layout for {}: {}'.format(
                    code, str(e)))

        from trionyx.urls import model_url

        if layout_id:
            layout.id = layout_id

        layout.update_url = model_url(object, 'layout-update', code=code)
        layout.set_object(object)

        return layout
Пример #4
0
def get_add_address_url(obj, context):
    """Get add address url"""
    from trionyx.urls import model_url
    return model_url('trionyx_accounts.address',
                     'dialog-create',
                     params={
                         'account': obj.id,
                     })
Пример #5
0
def item_sidebar(request, obj):
    layout = post_overview(obj)

    return {
        'title':
        str(obj),
        'fixed_content':
        'Some fixed content 2',
        'content':
        'Real content <br>' * 100,
        'theme':
        'light',
        'hover':
        False,
        'actions': [{
            'label': 'Save',
            'class': 'text-success text-bold',
            'url': model_url(obj, 'dialog-edit'),
            'dialog': True,
            'dialog_options': {},
            'reload': True,
        }, {
            'label': 'Warning',
            'class': 'text-warning',
            'url': model_url(obj, 'dialog-edit'),
            'dialog': True,
            'dialog_options': {},
            'reload': True,
        }, {
            'label': 'Info',
            'class': 'text-info',
            'url': model_url(obj, 'dialog-edit'),
            'dialog': True,
            'dialog_options': {},
            'reload': True,
        }, {
            'label': 'Delete',
            'class': 'text-danger',
            'url': model_url(obj, 'dialog-edit'),
            'dialog': True,
            'dialog_options': {},
            'reload': True,
            'divider': True,
        }]
    }
Пример #6
0
def trionyx(request):
    """Add trionyx context data"""
    if not hasattr(request, 'trionyx_context'):
        locale, *_ = utils.get_current_locale().split('_')
        setattr(
            request, 'trionyx_context', {
                'DEBUG':
                settings.DEBUG,
                'TX_APP_NAME':
                tx_settings.APP_NAME,
                'TX_LOGO_NAME_START':
                tx_settings.LOGO_NAME_START,
                'TX_LOGO_NAME_END':
                tx_settings.LOGO_NAME_END,
                'TX_LOGO_NAME_SMALL_START':
                tx_settings.LOGO_NAME_SMALL_START,
                'TX_LOGO_NAME_SMALL_END':
                tx_settings.LOGO_NAME_SMALL_END,
                'TX_THEME_COLOR':
                tx_settings.THEME_COLOR,
                'tx_base64_icon':
                tx_base64_icon,
                'tx_tasks_url':
                model_url(get_class('trionyx.Task'), 'list'),
                'tx_version':
                __version__,
                'tx_show_changelog':
                (tx_settings.SHOW_CHANGELOG_NEW_VERSION
                 and request.user.is_authenticated
                 and request.user.get_attribute('trionyx_last_shown_version')
                 != utils.get_app_version()),
                'trionyx_menu_items':
                app_menu.get_menu_items(request.user),
                'trionyx_menu_collapse':
                request.COOKIES.get('menu.state') == 'collapsed',
                'tx_custom_skin_css':
                'css/skins/skin-{}.min.css'.format(tx_settings.THEME_COLOR)
                if settings.TX_THEME_COLOR != tx_settings.THEME_COLOR else '',
                'app_version':
                utils.get_app_version(),
                'datetime_input_format':
                utils.datetime_format_to_momentjs(
                    utils.get_datetime_input_format()),
                'date_input_format':
                utils.datetime_format_to_momentjs(
                    utils.get_datetime_input_format(date_only=True)),
                'current_locale':
                utils.get_current_locale(),
                'summernote_language':
                '{}-{}'.format(locale, locale.upper()),
                'summernote_language_js':
                'plugins/summernote/lang/summernote-{}-{}.min.js'.format(
                    locale, locale.upper()) if locale != 'en' and
                utils.get_current_language() != settings.LANGUAGE_CODE else '',
                **offline_context()[0]
            })
    return getattr(request, 'trionyx_context')
Пример #7
0
    def get_items(self, paginator, current_page):
        """Get list items for current page"""
        from trionyx.urls import model_url
        fields = self.get_model_config().get_list_fields()

        page = paginator.page(current_page)

        items = []
        for item in page:
            items.append({
                'id':
                item.id,
                'url':
                self.get_model_config().get_absolute_url(item),
                'edit_url':
                model_url(item, 'edit'),
                'delete_url':
                model_url(item, 'delete'),
                'row_data': [
                    fields[field]['renderer'](item, field, no_link=True)
                    for field in self.get_current_fields()
                ]
            })
        return items
Пример #8
0
    def updated(self):
        """Set onClick url based on object"""
        reload_functions = ''
        if self.dialog_reload_layout:
            reload_functions += "txUpdateLayout('{id}', '{component}');".format(
                id=self.layout_id,
                component=self.dialog_reload_layout if isinstance(
                    self.dialog_reload_layout, str) else '')
        if self.dialog_reload_tab:
            dialog_reload_tab = self.dialog_reload_tab if isinstance(
                self.dialog_reload_tab, list) else [self.dialog_reload_tab]
            reload_functions += ''.join(
                [f"trionyx_reload_tab('{tab}');" for tab in dialog_reload_tab])
        if self.dialog_reload_sidebar:
            reload_functions += "reloadSidebar();"

        if reload_functions:
            self.dialog_options['callback'] = f"""function(data, dialog){{
                        if (data.success) {{
                            dialog.close();
                            {reload_functions}
                        }}
                    }}"""

        if not self.on_click:
            from trionyx.urls import model_url
            url = model_url(
                model=self.object,
                view_name=self.model_url,
                code=self.model_code,
                params=self.model_params) if not self.url else self.url

            if not url and hasattr(self.object, 'get_absolute_url'):
                url = self.object.get_absolute_url()

            if self.dialog:
                self.attr[
                    'onClick'] = "openDialog('{}', {}); return false;".format(
                        url, self.format_dialog_options())
            elif self.sidebar:
                self.attr[
                    'onClick'] = "openSidebar('{}'); return false;".format(url)
            else:
                self.attr[
                    'onClick'] = "window.location.href='{}'; return false;".format(
                        url)
Пример #9
0
def model_url(model, view_name, code=None):
    """Short cut for generating model urls"""
    from trionyx.urls import model_url
    return model_url(model, view_name, code)
Пример #10
0
def post_overview(obj):
    return [
        Column6(
            Panel(
                "Post info",
                TableDescription(
                    'status',
                    'title',
                    'publish_date',
                    'category',
                    'tags',
                    'price',
                    {
                        'label':
                        'Update',
                        'value':
                        Button(
                            'Update',
                            url=model_url(obj, 'dialog-edit'),
                            dialog=True,
                            # dialog_options={
                            #     'callback': "function(){trionyx_reload_tab('general')}"
                            # },
                            dialog_reload_layout='table-description',
                            color=Colors.TEAL,
                        )
                    },
                    {
                        'label':
                        'Sidebar',
                        'value':
                        Button(
                            'Sidebar',
                            model_url='sidebar',
                            model_code='item',
                            sidebar=True,
                        )
                    },
                )),
            Panel(
                'Charts',
                LineChart(
                    Post.objects.order_by('-sale_date'),
                    'sale_date',
                    'price',
                ),
                LineChart(
                    Post.objects.annotate(
                        day=TruncDay('publish_date')).values('day').annotate(
                            sum_price=models.Sum('price')).values(
                                'day', 'sum_price').order_by('-day'),
                    'day',
                    {
                        'label': 'Total price per day',
                        'field': 'sum_price',
                        'renderer': price_value_renderer,
                    },
                    time_unit='day',
                ),
                LineChart(
                    'tags',
                    'name',
                    'id',
                ),
                BarChart(
                    Post.objects.annotate(
                        day=TruncDay('publish_date')).values('day').annotate(
                            sum_price=models.Sum('price'),
                            sum_id=models.Sum('id')).values(
                                'day', 'sum_price', 'sum_id').order_by('-day'),
                    'day',
                    {
                        'label': 'Total price per day',
                        'field': 'sum_price',
                        'renderer': price_value_renderer,
                    },
                    'sum_id',
                    time_unit='day',
                ),
                DoughnutChart(
                    [['Python3', 60], ['Javascript', 30], ['Sql', 10]],
                    'name',
                    'value',
                ),
                PieChart(
                    [['Python3', 60], ['Javascript', 30], ['Sql', 10]],
                    'name',
                    'value',
                ),
            )),
        Column6(
            Panel(
                'Components',
                TableDescription(
                    {
                        'label':
                        'img',
                        'value':
                        Img(
                            src=
                            'https://www.python.org/static/img/python-logo.png',
                            width='200px',
                        ),
                    }, {
                        'label': 'Input',
                        'value': Input(name='test')
                    }, {
                        'label':
                        'Badges',
                        'value':
                        Component(
                            Badge('status', color=Colors.THEME),
                            Badge('status', color=Colors.LIGHT_BLUE),
                            Badge('status', color=Colors.AQUA),
                            Badge('status', color=Colors.GREEN),
                            Badge('status', color=Colors.YELLOW),
                            Badge('status', color=Colors.RED),
                            Badge('status', color=Colors.GRAY),
                            Badge('status', color=Colors.NAVY),
                            Badge('status', color=Colors.TEAL),
                            Badge('status', color=Colors.PURPLE),
                            Badge('status', color=Colors.ORANGE),
                            Badge('status', color=Colors.MAROON),
                            Badge('status', color=Colors.BLACK),
                        )
                    }, {
                        'label':
                        'Alerts',
                        'value':
                        Component(
                            Alert('Warning with no_margin',
                                  alert=Alert.INFO,
                                  no_margin=True),
                            Alert('success', alert=Alert.SUCCESS),
                            Alert('warning', alert=Alert.WARNING),
                            Alert('danger', alert=Alert.DANGER),
                        )
                    }, {
                        'label':
                        'Thumbnail',
                        'value':
                        Thumbnail(
                            'https://www.python.org/static/img/python-logo.png',
                            url=model_url(obj, 'dialog-edit'),
                            dialog=True,
                            dialog_options={
                                'callback':
                                "function(){trionyx_reload_tab('general')}"
                            },
                        )
                    }, {
                        'label':
                        'ProgressBar',
                        'value':
                        Component(
                            ProgressBar(value=543, max_value=2400),
                            ProgressBar(value=20, size='xs'),
                            ProgressBar(
                                value=78, active=True, color=Colors.GREEN),
                        ),
                    }, {
                        'label':
                        'Lists',
                        'value':
                        UnorderedList(
                            'title', 'content', {'value': 'Fixed value'}, {
                                'label':
                                'Unordered sublist',
                                'value':
                                UnorderedList(
                                    'status', {
                                        'label': 'Another unordered sublist',
                                        'value': UnorderedList('price'),
                                    })
                            }, {
                                'label':
                                'Ordered sublist',
                                'value':
                                OrderedList(
                                    'status', {
                                        'label': 'Another ordered sublist',
                                        'value': OrderedList('price'),
                                    })
                            }, {
                                'label': 'tags',
                                'value': UnorderedList('name', objects='tags'),
                            })
                    },
                    id="table-description"),
            )),
        Column12(
            Panel(
                'Tags',
                Table(
                    [
                        ['list object'],
                        {
                            'name': 'dict object',
                        },
                        Tag(name='Tag object'),
                    ],
                    'name=width:120px',
                    'Value=value:fixed value',
                    {
                        'label':
                        'Value',
                        'value':
                        'fixed value',
                        'renderer':
                        lambda value, data_object, **options: '{}'.format(
                            data_object),
                    },
                    footer=[[
                        ['Subtotaal', '12,50'],
                        ['Totaal', '12,50'],
                    ], {
                        'colspan': 2,
                        'class': 'text-right'
                    }, 'Price'],
                    hover=True,
                ),
                collapse=True,
            ))
    ]
Пример #11
0
def item_sidebar(request, obj):
    content = Component(
        Panel(
            'Description',
            Html(obj.description),
        ),
        Panel(
            'Info',
            TableDescription(
                {
                    'field':
                    'item_type',
                    'renderer':
                    lambda value, data_object, **options: "{} {}".format(
                        data_object.get_type_icon(data_object.item_type),
                        data_object.get_item_type_display(),
                    )
                },
                {
                    'field':
                    'priority',
                    'renderer':
                    lambda value, data_object, **options: "{} {}".format(
                        data_object.get_priority_icon(data_object.priority),
                        data_object.get_priority_display(),
                    )
                },
                'created_at',
                'updated_at',
            ),
        ),
        Panel(
            'Comments',
            Button('Add comment',
                   model_url='dialog-create',
                   model_params={'item': obj.id},
                   dialog=True,
                   dialog_reload_sidebar=True,
                   css_class='btn btn-flat bg-theme btn-block',
                   object=Comment()),
            *[
                Component(
                    HtmlTemplate('trionyx_projects/project_comment.html',
                                 object=comment,
                                 lock_object=True), )
                for comment in obj.comments.order_by('-created_at')
            ]),
        Panel(
            'Worklogs',
            Button('Add worklog',
                   model_url='dialog-create',
                   model_params={'item': obj.id},
                   dialog=True,
                   dialog_reload_sidebar=True,
                   css_class='btn btn-flat bg-theme btn-block',
                   object=WorkLog()),
            Table(obj.worklogs.order_by('-date', 'id'), 'date', {
                'field': 'created_by',
                'label': 'User',
            }, 'description', {
                'field': 'worked',
                'label': 'W',
            }, {
                'field': 'billed',
                'label': 'B',
            }, {
                'label':
                'Options',
                'width':
                '60px',
                'value':
                ButtonGroup(
                    Button(
                        '<i class="fa fa-edit"></i>',
                        css_class='btn bg-theme btn-xs',
                        dialog=True,
                        model_url='dialog-edit',
                        dialog_reload_sidebar=True,
                        should_render=lambda comp: comp.object.created_by ==
                        get_current_request().user or get_current_request(
                        ).user.is_superuser,
                    ),
                    Button(
                        '<i class="fa fa-times"></i>',
                        css_class='btn bg-red btn-xs',
                        dialog=True,
                        model_url='dialog-delete',
                        dialog_reload_sidebar=True,
                        should_render=lambda comp: comp.object.created_by ==
                        get_current_request().user or get_current_request(
                        ).user.is_superuser,
                    ),
                )
            }),
        ),
    )

    content.set_object(obj)

    return {
        'title':
        f"{obj.code} - {obj.name}",
        'fixed_content':
        TableDescription(
            {
                'field': 'estimate',
                'renderer': lambda value, **options: f"{value}h"
                if value else '0h',
                'class': 'text-right'
            },
            {
                'field': 'total_worked',
                'label': 'Logged',
                'renderer': lambda value, **options: f"{value}h"
                if value else '0h',
                'class': 'text-right'
            },
            {
                'field': 'total_billed',
                'label': 'Billed',
                'renderer': lambda value, **options: f"{value}h"
                if value else '0h',
                'class': 'text-right'
            },
            css_class='no-margin',
            object=obj,
        ).render({}, request),
        'content':
        content.render({}, request),
        'actions': [{
            'label': 'Edit',
            'url': model_url(obj, 'dialog-edit'),
            'dialog': True,
            'dialog_options': {
                'callback':
                """
                        if (data.success) { 
                            trionyx_reload_tab('general');
                            reloadSidebar();
                            dialog.close();
                        };
                    """
            },
        }, {
            'label': 'Delete',
            'class': 'text-danger',
            'url': model_url(obj, 'dialog-delete'),
            'dialog': True,
            'dialog_options': {
                'callback':
                """
                        if (data.success) { 
                            trionyx_reload_tab('general');
                            closeSidebar();
                            dialog.close();
                        };
                    """
            },
            'divider': True,
        }]
    }