-
Notifications
You must be signed in to change notification settings - Fork 99
Issue#3828 Refatorar Mesa Diretora #3829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 3.1.x
Are you sure you want to change the base?
Changes from all commits
8ec36ad
ef96f77
3cb9bdf
745a59e
86913cd
9318943
8ae8641
0c64cad
586e3df
f6582f8
0ec9585
b89a64f
8128831
5d3b742
ef36793
c228b04
4161598
962fb4f
fd734b2
04facfb
286b2f6
024a756
7b5ac2d
d1c572e
4f0dc4e
5af98ee
38fa86a
95df206
dc2c46e
3eee457
5edbc36
08c3a69
f37706f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -183,6 +183,7 @@ small { | |
| hyphens: auto;*/ | ||
| } | ||
|
|
||
|
|
||
| @media print { | ||
| a[href]:after { | ||
| content: none !important; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| @import "~bootstrap/scss/variables"; | ||
|
|
||
| // Estilização do tab-content conectado ao nav-tabs (substitui inline style) | ||
| .nav-tabs + .tab-content { | ||
| border: 1px solid $nav-tabs-border-color; | ||
| border-top: 0; | ||
| border-radius: 0 0 $border-radius $border-radius; | ||
| } | ||
|
|
||
| @media (max-width: 992px) { | ||
| .nav-tabs { | ||
| position: relative; | ||
| flex-direction: column; | ||
| border: 1px solid $nav-tabs-border-color; | ||
| border-radius: $border-radius; // Totalmente arredondado — parece um botão/select | ||
| background-color: $white; | ||
| overflow: hidden; // Recorta filhos nas bordas arredondadas | ||
|
|
||
| // Seta indicando dropdown | ||
| &::after { | ||
| content: "▾"; | ||
| position: absolute; | ||
| right: 0.75rem; | ||
| top: 0.6rem; | ||
| font-size: 1rem; | ||
| color: $secondary; | ||
| pointer-events: none; | ||
| transition: transform 0.2s ease; | ||
| } | ||
|
|
||
| // Oculta todos os itens por padrão | ||
| .nav-item { | ||
| display: none; | ||
| width: 100%; | ||
|
|
||
| .nav-link { | ||
| border: none; | ||
| border-bottom: 1px solid $nav-tabs-border-color; | ||
| border-radius: 0; | ||
| width: 100%; | ||
| text-align: left; | ||
| padding-right: 2rem; | ||
| margin-bottom: 0; | ||
|
|
||
| &.active { | ||
| background-color: $nav-tabs-link-active-bg; | ||
| color: $nav-tabs-link-active-color; | ||
| border-color: transparent; | ||
| } | ||
|
|
||
| &:hover:not(.active) { | ||
| background-color: $light; | ||
| } | ||
| } | ||
|
|
||
| &:last-child .nav-link { | ||
| border-bottom: none; | ||
| } | ||
| } | ||
|
|
||
| // CSS nativo: exibe somente o item ativo (browsers com suporte a :has) | ||
| .nav-item:has(.nav-link.active) { | ||
| display: block; | ||
| } | ||
|
|
||
| // Estado expandido: via :focus-within (nativo) ou .nav-tabs--open (fallback JS) | ||
| &:focus-within, | ||
| &.nav-tabs--open { | ||
| border-radius: $border-radius $border-radius 0 0; // Arredonda apenas topo quando aberto | ||
| overflow: visible; | ||
| z-index: $zindex-dropdown; | ||
|
|
||
| &::after { | ||
| transform: rotate(180deg); | ||
| } | ||
|
|
||
| .nav-item { | ||
| display: block; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Em mobile, tab-content é visualmente independente do nav-tabs (que vira um select) | ||
| .nav-tabs + .tab-content { | ||
| border-top: 1px solid $nav-tabs-border-color; | ||
| border-radius: $border-radius; // Rounding completo — desconectado do nav-tabs | ||
| margin-top: 0.5rem; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| @import "./bootstrap/nav_navbar"; | ||
| @import "./bootstrap/nav_tabs"; | ||
| @import "./bootstrap/table"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Generated by Django 2.2.28 on 2026-04-13 01:48 | ||
|
|
||
| from django.db import migrations, models | ||
| import django.db.models.deletion | ||
| from datetime import date | ||
|
|
||
| def add_legislatura_to_mesa_diretora(apps, schema_editor): | ||
| schema_editor.execute(""" | ||
| UPDATE parlamentares_mesadiretora md | ||
| SET | ||
| legislatura_id = sl.legislatura_id, | ||
| data_inicio = sl.data_inicio, | ||
| data_fim = sl.data_fim | ||
| FROM | ||
| parlamentares_sessaolegislativa sl | ||
| WHERE | ||
| sl.id = md.sessao_legislativa_id | ||
| """) | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('parlamentares', '0045_auto_20251201_1531'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name='mesadiretora', | ||
| name='legislatura', | ||
| field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Legislatura', verbose_name='Legislatura'), | ||
| ), | ||
| migrations.RunPython(add_legislatura_to_mesa_diretora), | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Generated by Django 2.2.28 on 2026-04-13 01:56 | ||
|
|
||
| from django.db import migrations, models | ||
| import django.db.models.deletion | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('parlamentares', '0046_mesadiretora_legislatura'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name='mesadiretora', | ||
| name='legislatura', | ||
| field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Legislatura', verbose_name='Legislatura'), | ||
| ), | ||
| migrations.RemoveField( | ||
| model_name='mesadiretora', | ||
| name='sessao_legislativa', | ||
| ), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # Generated by Django 2.2.28 on 2026-04-13 13:49 | ||
|
|
||
| from django.db import migrations, models | ||
| import django.db.models.deletion | ||
|
|
||
| def preencher_titulo_mesa_diretora(apps, schema_editor): | ||
| schema_editor.execute(""" | ||
| UPDATE parlamentares_mesadiretora | ||
| SET titulo = 'Mesa Diretora' || | ||
| CASE WHEN EXTRACT(YEAR FROM data_fim)::integer - EXTRACT(YEAR FROM data_inicio)::integer = 1 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rótulo "Biênio" aplicado a mesas de aproximadamente um ano A heurística compara os anos das datas, então marca como biênio qualquer mesa que apenas atravesse o Réveillon. Numa base real de produção, 12 dos 64 títulos gerados saíram assim: Como o Comparar a duração real resolve: SET titulo = 'Mesa Diretora' ||
CASE WHEN data_fim - data_inicio > 400
THEN ' Biênio'
ELSE ''
END || ' ' || ...(400 dias em vez de 365 para dar folga a mesas de ~13 meses, que pelo visto são comuns em bases antigas.) |
||
| THEN ' Biênio' | ||
| ELSE '' | ||
| END || ' ' || | ||
| EXTRACT(YEAR FROM data_inicio)::integer::text || '/' || | ||
| EXTRACT(YEAR FROM data_fim)::integer::text | ||
| WHERE data_inicio IS NOT NULL AND data_fim IS NOT NULL | ||
| """) | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('parlamentares', '0047_auto_20260412_2256'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AlterModelOptions( | ||
| name='mesadiretora', | ||
| options={'ordering': ('-legislatura', '-data_inicio'), 'verbose_name': 'Mesa Diretora', 'verbose_name_plural': 'Mesas Diretoras'}, | ||
| ), | ||
| migrations.AddField( | ||
| model_name='mesadiretora', | ||
| name='titulo', | ||
| field=models.CharField(default='', max_length=100, verbose_name='Título da Mesa Diretora'), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='composicaomesa', | ||
| name='mesa_diretora', | ||
| field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='composicaomesa_set', to='parlamentares.MesaDiretora'), | ||
| ), | ||
| migrations.RunPython(preencher_titulo_mesa_diretora), | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # Generated by Django 2.2.28 on 2026-04-17 22:17 | ||
|
|
||
| from django.db import migrations, models | ||
| import django.db.models.deletion | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('parlamentares', '0048_auto_20260413_1049'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name='composicaomesa', | ||
| name='cargo', | ||
| field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='parlamentares.CargoMesa', verbose_name='Cargo'), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='composicaomesa', | ||
| name='mesa_diretora', | ||
| field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='composicaomesa_set', to='parlamentares.MesaDiretora', verbose_name='Mesa Diretora'), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='composicaomesa', | ||
| name='parlamentar', | ||
| field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Parlamentar', verbose_name='Parlamentar'), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='mesadiretora', | ||
| name='data_fim', | ||
| field=models.DateField(verbose_name='Data Fim'), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='mesadiretora', | ||
| name='data_inicio', | ||
| field=models.DateField(verbose_name='Data Início'), | ||
|
joaohortsenado marked this conversation as resolved.
|
||
| ), | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Generated by Django 2.2.28 on 2026-04-18 01:35 | ||
|
|
||
| from django.db import migrations, models | ||
| import django.db.models.deletion | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('parlamentares', '0049_auto_20260417_1917'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name='mesadiretora', | ||
| name='legislatura', | ||
| field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='mesadiretora_set', to='parlamentares.Legislatura', verbose_name='Legislatura'), | ||
| ), | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A migração pode gravar mesas fora do período da própria legislatura
O SQL está correto e rápido (as 59 migrations rodaram em 12,8s numa base real — o ponto do @edwardoliveira em
r3093425814ficou bem resolvido). O problema é que aSessaoLegislativade origem nem sempre respeita o intervalo daLegislatura, e a nova regra de contenção introduzida noclean()passa a rejeitar o resultado.Testando contra um dump de produção real, 2 das 64 mesas ficaram assim:
Somadas às 2 de borda coincidente que comentei em
models.py, são 4 de 64 mesas (6%) inválidas logo após o upgrade. A migração em si não quebra — o efeito aparece depois, quando alguém tenta editar.Não acho que a migration deva "consertar" datas silenciosamente: essa informação foi perdida pela modelagem anterior e qualquer chute pode piorar. Duas alternativas que me parecem melhores:
./manage.py verifica_mesas_diretoras) que lista os registros que não passam nofull_clean(), para a casa ajustar manualmente — junto de uma nota na documentação de upgrade.RunPythonadicional que apenas registra em log quais mesas ficaram inconsistentes, para não ser uma descoberta silenciosa em produção.(Registrando também que a preocupação que eu tinha levantado sobre
IntegrityErrorna0049não se confirmou:sessao_legislativaera FKNOT NULLe as datas da sessão também, então oUPDATEsempre popula. Já resolvi aquela thread.)