diff --git a/sigi/apps/home/admin.py b/sigi/apps/home/admin.py
new file mode 100644
index 0000000..772c4fd
--- /dev/null
+++ b/sigi/apps/home/admin.py
@@ -0,0 +1,29 @@
+from django.contrib import admin
+from sigi.apps.home.models import Cards, Dashboard
+
+
+@admin.register(Cards)
+class CardAdmin(admin.ModelAdmin):
+ list_display = ("codigo", "titulo", "categoria", "ordem", "default")
+ list_editable = ("titulo", "categoria", "ordem", "default")
+ search_fields = ("titulo", "codigo")
+
+
+@admin.register(Dashboard)
+class DashboardAdmin(admin.ModelAdmin):
+ list_display = ("card", "categoria", "ordem")
+ exclude = ("usuario",)
+ list_editable = ("categoria", "ordem")
+ autocomplete_fields = ("card",)
+
+ def save_model(self, request, obj, form, change):
+ if not change:
+ obj.usuario = request.user
+ if obj.categoria == "":
+ obj.categoria = obj.card.categoria
+ if obj.ordem == 0:
+ obj.ordem = obj.card.ordem
+ return super().save_model(request, obj, form, change)
+
+ def get_queryset(self, request):
+ return super().get_queryset(request).filter(usuario=request.user)
diff --git a/sigi/apps/home/apps.py b/sigi/apps/home/apps.py
new file mode 100644
index 0000000..a968999
--- /dev/null
+++ b/sigi/apps/home/apps.py
@@ -0,0 +1,8 @@
+from django.apps import AppConfig
+from django.utils.translation import gettext_lazy as _
+
+
+class HomeConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "sigi.apps.home"
+ verbose_name = _("Home page do SIGI")
diff --git a/sigi/apps/home/context_processors.py b/sigi/apps/home/context_processors.py
new file mode 100644
index 0000000..6129188
--- /dev/null
+++ b/sigi/apps/home/context_processors.py
@@ -0,0 +1,57 @@
+from django.urls import reverse
+from django.utils.text import slugify
+from sigi.apps.home.models import Cards, Dashboard
+
+
+def get_or_create_dash(usuario):
+ my_dash = Dashboard.objects.filter(usuario=usuario)
+ if my_dash.exists():
+ return [
+ {
+ "slug": slugify(categoria),
+ "label": categoria,
+ "cards": [d.card for d in my_dash.filter(categoria=categoria)],
+ }
+ for categoria in sorted(
+ set(my_dash.values_list("categoria", flat=True))
+ )
+ ]
+ else:
+ cards = Cards.objects.filter(default=True)
+ my_dash = [
+ {
+ "slug": slugify(categoria),
+ "label": categoria,
+ "cards": [card for card in cards.filter(categoria=categoria)],
+ }
+ for categoria in sorted(
+ set(cards.values_list("categoria", flat=True))
+ )
+ ]
+ if not usuario.is_anonymous:
+ for card in cards:
+ Dashboard(
+ usuario=usuario,
+ card=card,
+ categoria=card.categoria,
+ ordem=card.ordem,
+ ).save()
+ return my_dash
+
+
+def dashboard(request):
+ if request.path != reverse("admin:index"):
+ return {}
+ my_dash = get_or_create_dash(request.user)
+ selected = request.GET.get("dash", my_dash[0]["slug"])
+ return {
+ "sigi_dashes": my_dash,
+ "sigi_dash_selected": selected,
+ "sigi_dash_all_categories": [
+ (slugify(c), c)
+ for c in sorted(
+ set(Cards.objects.all().values_list("categoria", flat=True))
+ )
+ ],
+ "sigi_dash_all_cards": Cards.objects.all(),
+ }
diff --git a/sigi/apps/home/fixtures/cards.json b/sigi/apps/home/fixtures/cards.json
new file mode 100644
index 0000000..e85dc54
--- /dev/null
+++ b/sigi/apps/home/fixtures/cards.json
@@ -0,0 +1 @@
+[{"model": "home.cards", "pk": 1, "fields": {"codigo": "resumoseit", "tipo": "T", "nome_url": "home_resumoseit", "query_string": "", "link_acao": false, "titulo": "Serviços hospedados no Interlegis (SEIT)", "descricao": "Tabela com os serviços criados no SEIT por mês", "categoria": "Serviços", "ordem": 1, "default": true}}, {"model": "home.cards", "pk": 2, "fields": {"codigo": "chartseit", "tipo": "C", "nome_url": "home_chartseit", "query_string": "", "link_acao": true, "titulo": "Sazonalidade da hospedagem de serviços", "descricao": "Gráfico com a sazonalidade das solicitações de serviços", "categoria": "Serviços", "ordem": 2, "default": true}}, {"model": "home.cards", "pk": 3, "fields": {"codigo": "carteira", "tipo": "T", "nome_url": "casas-carteira", "query_string": "snippet=resumo&s=sim", "link_acao": false, "titulo": "Resumo da carteira de relacionamentos", "descricao": "Tabela resumindo a carteira de gerência Interlegis", "categoria": "Gerente", "ordem": 1, "default": true}}, {"model": "home.cards", "pk": 4, "fields": {"codigo": "performance", "tipo": "C", "nome_url": "home_chartperformance", "query_string": "", "link_acao": true, "titulo": "Performance da gerência de carteiras", "descricao": "Performance da gerência de carteiras", "categoria": "Gerente", "ordem": 2, "default": true}}, {"model": "home.cards", "pk": 5, "fields": {"codigo": "chartcarteira", "tipo": "C", "nome_url": "home_chartcarteira", "query_string": "", "link_acao": false, "titulo": "Distribuição de Casas por Gerente", "descricao": "Distribuição de Casas por Gerente", "categoria": "Gerente", "ordem": 3, "default": true}}, {"model": "home.cards", "pk": 6, "fields": {"codigo": "resumoconvenios", "tipo": "T", "nome_url": "home_resumoconvenios", "query_string": "", "link_acao": false, "titulo": "Resumo de informações", "descricao": "Resumo de informações", "categoria": "Geral", "ordem": 1, "default": true}}]
\ No newline at end of file
diff --git a/sigi/apps/home/migrations/0001_initial.py b/sigi/apps/home/migrations/0001_initial.py
new file mode 100644
index 0000000..2717e49
--- /dev/null
+++ b/sigi/apps/home/migrations/0001_initial.py
@@ -0,0 +1,53 @@
+# Generated by Django 4.0.4 on 2022-05-11 14:41
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Cards',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('codigo', models.CharField(max_length=20, verbose_name='código')),
+ ('tipo', models.CharField(choices=[('T', 'Tabela de dados'), ('C', 'Gráfico')], max_length=1, verbose_name='tipo')),
+ ('nome_url', models.CharField(max_length=30, verbose_name='nome da URL de dados')),
+ ('query_string', models.CharField(blank=True, max_length=100, verbose_name='query string')),
+ ('link_acao', models.BooleanField(default=False, verbose_name='possui link de ação')),
+ ('titulo', models.CharField(max_length=100, verbose_name='título')),
+ ('descricao', models.TextField(verbose_name='descrição')),
+ ('categoria', models.CharField(default='Geral', max_length=40, verbose_name='categoria')),
+ ('ordem', models.PositiveSmallIntegerField(default=0, verbose_name='posição na categoria')),
+ ('default', models.BooleanField(default=False, help_text='Indica se este card deve ser mostrado para usuários anônimos ou que não personalizaram seu dashboard', verbose_name='card padrão')),
+ ],
+ options={
+ 'verbose_name': 'card',
+ 'verbose_name_plural': 'cards',
+ 'ordering': ('categoria', 'ordem', 'titulo'),
+ },
+ ),
+ migrations.CreateModel(
+ name='Dashboard',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('categoria', models.CharField(blank=True, help_text='Deixando em branco será utilizada a categoria padrão do card', max_length=40, verbose_name='categoria personalizada')),
+ ('ordem', models.PositiveSmallIntegerField(default=0, verbose_name='posição na categoria')),
+ ('card', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.cards')),
+ ('usuario', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'verbose_name': 'dashboard',
+ 'verbose_name_plural': 'dashboards',
+ 'ordering': ('usuario', 'categoria', 'ordem'),
+ },
+ ),
+ ]
diff --git a/sigi/apps/home/migrations/__init__.py b/sigi/apps/home/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sigi/apps/home/models.py b/sigi/apps/home/models.py
new file mode 100644
index 0000000..19fc30a
--- /dev/null
+++ b/sigi/apps/home/models.py
@@ -0,0 +1,69 @@
+from django.db import models
+from django.conf import settings
+from django.utils.translation import gettext as _
+
+
+class Cards(models.Model):
+ TIPO_CHOICES = (
+ ("T", _("Tabela de dados")),
+ ("C", _("Gráfico")),
+ )
+ codigo = models.CharField(_("código"), max_length=20)
+ tipo = models.CharField(_("tipo"), max_length=1, choices=TIPO_CHOICES)
+ nome_url = models.CharField(_("nome da URL de dados"), max_length=30)
+ query_string = models.CharField(
+ _("query string"),
+ max_length=100,
+ blank=True,
+ )
+ link_acao = models.BooleanField(_("possui link de ação"), default=False)
+ titulo = models.CharField(_("título"), max_length=100)
+ descricao = models.TextField(_("descrição"))
+ categoria = models.CharField(
+ _("categoria"), max_length=40, default=_("Geral")
+ )
+ ordem = models.PositiveSmallIntegerField(
+ _("posição na categoria"), default=0
+ )
+ default = models.BooleanField(
+ _("card padrão"),
+ default=False,
+ help_text=_(
+ "Indica se este card deve ser mostrado para usuários anônimos ou "
+ "que não personalizaram seu dashboard"
+ ),
+ )
+
+ class Meta:
+ ordering = ("categoria", "ordem", "titulo")
+ verbose_name = _("card")
+ verbose_name_plural = _("cards")
+
+ def __str__(self):
+ return _(f"{self.titulo} ({self.categoria})")
+
+
+class Dashboard(models.Model):
+ usuario = models.ForeignKey(
+ settings.AUTH_USER_MODEL, on_delete=models.CASCADE
+ )
+ card = models.ForeignKey(Cards, on_delete=models.CASCADE)
+ categoria = models.CharField(
+ _("categoria personalizada"),
+ max_length=40,
+ blank=True,
+ help_text=_(
+ "Deixando em branco será utilizada a categoria padrão do card"
+ ),
+ )
+ ordem = models.PositiveSmallIntegerField(
+ _("posição na categoria"), default=0
+ )
+
+ class Meta:
+ ordering = ("usuario", "categoria", "ordem")
+ verbose_name = _("dashboard")
+ verbose_name_plural = _("dashboards")
+
+ def __str__(self):
+ return _(f"{self.usuario.get_full_name()} - {self.card}")
diff --git a/sigi/apps/home/templates/home/dashboard/card.html b/sigi/apps/home/templates/home/dashboard/card.html
new file mode 100644
index 0000000..699554a
--- /dev/null
+++ b/sigi/apps/home/templates/home/dashboard/card.html
@@ -0,0 +1,44 @@
+{% load i18n static material %}
+{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %}
+
+
+ {{ card.titulo }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% include 'sigi/snippets/dashboard.html' %}
+
+
+
+
+
diff --git a/sigi/apps/home/tests.py b/sigi/apps/home/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/sigi/apps/home/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/sigi/apps/home/urls.py b/sigi/apps/home/urls.py
index c1fb0c3..ae624e3 100644
--- a/sigi/apps/home/urls.py
+++ b/sigi/apps/home/urls.py
@@ -28,6 +28,32 @@ urlpatterns = [
views.report_sem_convenio,
name="home_reportsemconvenio",
),
+ path(
+ "home/dashboard/card//",
+ views.card_snippet,
+ name="home_cardsnippet",
+ ),
+ path(
+ "home/dashboard/addtab//",
+ views.card_add_tab,
+ name="home_card_add_tab",
+ ),
+ path(
+ "home/dashboard/changetab/",
+ views.card_rename_tab,
+ name="home_card_rename_tab",
+ ),
+ path(
+ "home/dashboard/reorder/",
+ views.card_reorder,
+ name="home_card_reorder",
+ ),
+ path(
+ "home/dashboard/remove///",
+ views.card_remove,
+ name="home_card_remove",
+ ),
+ path("home/dashboard/addcard/", views.card_add, name="home_add_card"),
]
# from django.conf.urls import patterns, url
diff --git a/sigi/apps/home/views.py b/sigi/apps/home/views.py
index dad1c4e..c05f8d4 100644
--- a/sigi/apps/home/views.py
+++ b/sigi/apps/home/views.py
@@ -2,19 +2,28 @@ import calendar
import csv
import datetime
from itertools import cycle
+from django.contrib import messages
from django.contrib.admin.sites import site
from django.contrib.auth.decorators import login_required
+from django.core.exceptions import PermissionDenied
from django.db import models
from django.db.models import Q, Count
-from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
+from django.http import (
+ HttpResponse,
+ HttpResponseForbidden,
+ HttpResponseRedirect,
+ JsonResponse,
+)
from django.shortcuts import render, get_object_or_404
from django.template.loader import render_to_string
+from django.utils.text import slugify
from django.utils.translation import gettext as _
from django.views.decorators.cache import never_cache
from django_weasyprint.views import WeasyTemplateResponse
from sigi.apps.casas.models import TipoOrgao, Orgao
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.convenios.models import Convenio, Projeto
+from sigi.apps.home.models import Cards, Dashboard
from sigi.apps.servicos.models import TipoServico
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils import to_ascii
@@ -227,6 +236,91 @@ def openmapsearch(request):
return JsonResponse(list(dados), safe=False)
+def card_snippet(request, card_code):
+ card = get_object_or_404(Cards, codigo=card_code)
+ if not card.default:
+ raise PermissionDenied()
+ return render(request, "home/dashboard/card.html", {"dash_cards": [card]})
+
+
+@login_required
+def card_add_tab(request, tab_slug):
+ for card in Cards.objects.all():
+ if slugify(card.categoria) == tab_slug:
+ Dashboard(
+ usuario=request.user,
+ card=card,
+ categoria=card.categoria,
+ ordem=card.ordem,
+ ).save()
+ return HttpResponseRedirect(reverse("admin:index"))
+
+
+@login_required
+def card_rename_tab(request):
+ dados = request.POST.copy()
+ dados.pop("csrfmiddlewaretoken")
+ categoria_atual = dados.pop("categoria_atual")[0]
+ categoria_nova = dados.pop("categoria_nova")[0]
+ if categoria_nova != "" and categoria_nova != categoria_atual:
+ Dashboard.objects.filter(
+ usuario=request.user, categoria=categoria_atual
+ ).update(categoria=categoria_nova)
+ messages.success(request, _("Tab renomeada com sucesso"))
+ else:
+ messages.warning(request, _("Não foi possível renomear a tab"))
+ return HttpResponseRedirect(reverse("admin:index"))
+
+
+@login_required
+def card_reorder(request):
+ dados = request.GET.copy()
+ categoria = dados.pop("categoria")[0]
+ for codigo, nova_ordem in dados.items():
+ Dashboard.objects.filter(
+ usuario=request.user, card__codigo=codigo, categoria=categoria
+ ).update(ordem=nova_ordem)
+ return JsonResponse({"result": "Done"})
+
+
+@login_required
+def card_remove(request, categoria, codigo):
+ dash = get_object_or_404(
+ Dashboard, categoria=categoria, card__codigo=codigo
+ )
+ dash.delete()
+ messages.success(request, _("Card removido"))
+ return HttpResponseRedirect(reverse("admin:index"))
+
+
+@login_required
+def card_add(request):
+ categoria = request.POST.get("categoria", None)
+ codigos = request.POST.getlist("card_id", None)
+
+ if categoria is None or codigos is None:
+ messages.error(request, _("Nenhum card adicionado!"))
+ else:
+ criados = 0
+ for codigo in codigos:
+ card = get_object_or_404(Cards, codigo=codigo)
+ dash, created = Dashboard.objects.get_or_create(
+ {"ordem": card.ordem},
+ usuario=request.user,
+ card=card,
+ categoria=categoria,
+ )
+ if created:
+ criados += 1
+ if criados > 0:
+ messages.success(
+ request, _(f"{criados} card(s) adicionado(s) na aba")
+ )
+ else:
+ messages.info(request, _("Estes cards já estão na aba"))
+ return HttpResponseRedirect(reverse("admin:index"))
+
+
# @never_cache
# @login_required
# def index(request):
diff --git a/sigi/settings.py b/sigi/settings.py
index ae9759f..8277aae 100644
--- a/sigi/settings.py
+++ b/sigi/settings.py
@@ -110,6 +110,7 @@ TEMPLATES = [
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"django.template.context_processors.media",
+ "sigi.apps.home.context_processors.dashboard",
],
},
},
diff --git a/sigi/static/css/dashboard.css b/sigi/static/css/dashboard.css
index b418f52..b9dc7c7 100644
--- a/sigi/static/css/dashboard.css
+++ b/sigi/static/css/dashboard.css
@@ -5,6 +5,7 @@ table.servicos {
table.numeros>tbody>tr>td {
text-align: right;
}
+
.app>.card>.card-content>.card-title {
font-size: 16px;
font-weight: bolder;
@@ -13,7 +14,7 @@ table.numeros>tbody>tr>td {
.full-preloader {
width: 100%;
height: 100%;
- background-color: rgb(255,255,255,0.8);
+ background-color: rgb(255, 255, 255, 0.8);
position: absolute;
z-index: 2;
display: flex;
@@ -34,4 +35,91 @@ table.numeros>tbody>tr>td {
.card-links {
padding: 0 24px;
+}
+
+.tab-edit,
+.tab-control {
+ display: inline-block;
+ text-align: center;
+ line-height: 48px;
+ height: 48px;
+ padding: 0;
+ margin: 0;
+ text-transform: uppercase;
+}
+
+.tab-edit a,
+.tab-control a {
+ display: block;
+ width: 100%;
+ height: 100%;
+ padding: 0 24px;
+ font-size: 14px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ transition: color .28s ease, background-color .28s ease;
+}
+
+.dashbar {
+ background: var(--main-hover-color);
+ opacity: .8;
+ color: #fff;
+ padding: 10px;
+ border: none;
+ text-align: left;
+}
+
+.dashtabs {
+ position: relative;
+ overflow-x: auto;
+ overflow-y: hidden;
+ height: 48px;
+ width: 100%;
+ background-color: #fff;
+ margin: 0 auto;
+ white-space: nowrap;
+ list-style-type: none;
+ display: block;
+ margin-block-start: 1em;
+ margin-block-end: 1em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ padding-inline-start: 40px;
+}
+
+.dashtabs .tabitem {
+ display: inline-block;
+ font-weight: normal;
+ height: 48px;
+ line-height: 48px;
+ margin: 0;
+ padding: 0;
+ text-transform: uppercase;
+ text-align: center;
+}
+
+.dashtabs .tabitem .active {
+ font-weight: bolder;
+}
+
+.dashtabs .tabitem a,
+.dashtabs .tabitem p {
+ display: block;
+ width: 100%;
+ height: 100%;
+ padding: 0 24px;
+ font-size: 14px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.dashtabs .tabitem i {
+ line-height: unset;
+ color: var(--primary);
+}
+
+.dash-modal-header {
+ font-size: 1.2em;
+ display: block;
+ text-transform: uppercase;
}
\ No newline at end of file
diff --git a/sigi/static/js/dashboard.js b/sigi/static/js/dashboard.js
index 793f664..9dc9d2f 100644
--- a/sigi/static/js/dashboard.js
+++ b/sigi/static/js/dashboard.js
@@ -1,12 +1,35 @@
$(document).ready(function () {
+ M.Tabs.init($('.tabs'), {});
+ $(".dash-control").hide();
+ $(".tab-edit a").off("click").on("click", function (e) {
+ e.preventDefault();
+ $(".dash-control").toggle();
+ if ($(".dash-control").is(':visible')) {
+ $(".sortable").sortable({
+ update: function (e, ui) {
+ var parent = ui.item.parent();
+ var url = parent.attr("data-target-url");
+ var dados = { 'categoria': parent.attr("data-tab-name") };
+ parent.children().each(function (pos) {
+ dados[$(this).attr("data-card-id")] = pos + 1;
+ })
+ $.get(url, dados, function () {
+ M.toast({ html: 'Ordem alterada' })
+ });
+ }
+ });
+ } else {
+ $(".sortable").sortable("disable");
+ }
+ })
Chart.defaults.plugins.legend.labels.usePointStyle = true;
setlinks();
- $("div[data-source]").each(function(index, container) {
+ $("div[data-source]").each(function (index, container) {
var container = $(container);
var url = container.attr('data-source');
get_content(container, url);
});
- $("canvas[data-source]").each(function(index, canvas) {
+ $("canvas[data-source]").each(function (index, canvas) {
var canvas = $(canvas)
var url = canvas.attr("data-source");
plot_chart(canvas, url);
@@ -14,13 +37,17 @@ $(document).ready(function () {
});
function setlinks() {
- $('.modal').modal();
- $('.dropdown-trigger').dropdown();
- $('.collapsible').collapsible();
- $("a.dashlink[data-target]").off('click').on('click', function(e) {
+ try {
+ M.Modal.init($('.modal'), {});
+ M.Dropdown.init($('.dropdown-trigger'), {});
+ M.Collapsible.init($('.collapsible'), {});
+ } catch (e) {
+ console.log("A exception has ocurred", e)
+ }
+ $("a.dashlink[data-target]").off('click').on('click', function (e) {
e.preventDefault();
var $this = $(this);
- var target = $("#"+$this.attr('data-target'));
+ var target = $("#" + $this.attr('data-target'));
var url = $this.attr('href');
if (target.is("canvas")) {
plot_chart(target, url);
@@ -32,18 +59,18 @@ function setlinks() {
function get_content(container, url) {
container.closest('.card').find('.full-preloader').removeClass('hide');
- $.get(url, function(data) {
+ $.get(url, function (data) {
container.html(data);
container.closest('.card').find('.full-preloader').addClass('hide');
setlinks();
- }).fail(function() {
+ }).fail(function () {
container.closest('.card').find('.full-preloader').html("Ocorreu um erro. Tente recarregar a página");
});
}
function plot_chart(canvas, url) {
canvas.closest('.card').find('.full-preloader').removeClass('hide');
- $.get(url, function(data) {
+ $.get(url, function (data) {
var chart_name = canvas.attr("data-chart-name");
var has_action_links = canvas.attr("data-has-action-links");
@@ -66,7 +93,7 @@ function plot_chart(canvas, url) {
}
setlinks();
canvas.closest('.card').find('.full-preloader').addClass('hide');
- }).fail(function() {
+ }).fail(function () {
canvas.closest('.card').find('.full-preloader').html("Ocorreu um erro. Tente recarregar a página");
});
}
\ No newline at end of file
diff --git a/sigi/templates/material/admin/index.html b/sigi/templates/material/admin/index.html
index 468fb13..1591526 100644
--- a/sigi/templates/material/admin/index.html
+++ b/sigi/templates/material/admin/index.html
@@ -11,8 +11,46 @@
{{ block.super }}
{% endblock %}
+{% block breadcrumbs %}
+
+{% endblock %}
+
{% block content %}
- {% include 'sigi/snippets/dashboard.html' %}
+
+
+
Adicionar nova tab
+
{% trans "Selecione a categoria a ser adicionada" %}
+
+ {% for slug, label in sigi_dash_all_categories %}
+
+ {% endfor %}
+
+
+
+
+ {% for dash in sigi_dashes %}
+
+ {% include 'sigi/snippets/dashboard.html' %}
+
+ {% endfor %}
{% endblock %}
{% block footer %}
diff --git a/sigi/templates/sigi/snippets/base_card.html b/sigi/templates/sigi/snippets/base_card.html
index ec2743c..41ea39a 100644
--- a/sigi/templates/sigi/snippets/base_card.html
+++ b/sigi/templates/sigi/snippets/base_card.html
@@ -18,7 +18,11 @@
-
{% block card-title %}{% translate card_title|default:"" %}{% endblock %}
+
+
drag_handle
+ {% block card-title %}{% translate card_title|default:"" %}{% endblock %}
+
close
+
{% block card-content %}{% endblock card-content %}
diff --git a/sigi/templates/sigi/snippets/dashboard.html b/sigi/templates/sigi/snippets/dashboard.html
index 0a3646a..62e6e16 100644
--- a/sigi/templates/sigi/snippets/dashboard.html
+++ b/sigi/templates/sigi/snippets/dashboard.html
@@ -1,23 +1,55 @@
{% load i18n %}
-
- {% url "home_resumoseit" as source_url %}
- {% include "sigi/snippets/base_card_text.html" with card_title="Serviços hospedados no Interlegis (SEIT)" data_source=source_url card_name="resumoseit" %}
-
- {% url "home_chartseit" as source_url %}
- {% include "sigi/snippets/base_card_chart.html" with card_title="Sazonalidade da hospedagem de serviços" data_source=source_url chart_name="evolucao-servicos" has_action_links="1" %}
-
- {% url "casas-carteira" as source_url %}
- {% include "sigi/snippets/base_card_text.html" with card_title="Resumo da carteira de relacionamentos" data_source=source_url|add:"?snippet=resumo&s=sim" card_name="carteira" %}
-
- {% url "home_chartperformance" as source_url %}
- {% include "sigi/snippets/base_card_chart.html" with card_title="Performance da gerência de carteiras" data_source=source_url chart_name="performance" has_action_links="1" %}
-
- {% url "home_chartcarteira" as source_url %}
- {% include "sigi/snippets/base_card_chart.html" with card_title="Distribuição de Casas por Gerente" data_source=source_url chart_name="carteira" %}
-
- {% url "home_resumoconvenios" as source_url %}
- {% include "sigi/snippets/base_card_text.html" with card_title="Resumo de informações" data_source=source_url card_name="resumo-convenios" %}
+
+
+ {% for card in dash.cards %}
+
+ {% url card.nome_url as source_url %}
+ {% if card.tipo == 'C' %}
+ {% include "sigi/snippets/base_card_chart.html" with card_title=card.titulo data_source=source_url|add:"?"|add:card.query_string chart_name=card.codigo has_action_links=card.link_acao %}
+ {% else %}
+ {% include "sigi/snippets/base_card_text.html" with card_title=card.titulo data_source=source_url|add:"?"|add:card.query_string card_name=card.codigo %}
+ {% endif %}
+
+ {% endfor %}
+
+