wagtail-enap-designsystem 1.2.1.143__py3-none-any.whl → 1.2.1.145__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wagtail-enap-designsystem might be problematic. Click here for more details.
- enap_designsystem/blocks/content_blocks.py +2 -1
- enap_designsystem/blocks/form.py +1 -6
- enap_designsystem/blocks/html_blocks.py +82 -77
- enap_designsystem/blocks/layout_blocks.py +26 -0
- enap_designsystem/blocks/semana_blocks.py +30 -19
- enap_designsystem/migrations/0415_showcasecomponentesdireto_debug_mode_and_more.py +77346 -0
- enap_designsystem/migrations/0416_alter_showcasecomponentesdireto_debug_mode_and_more.py +33 -0
- enap_designsystem/migrations/0417_alter_showcasecomponentesdireto_options_and_more.py +53 -0
- enap_designsystem/models.py +729 -146
- enap_designsystem/static/enap_designsystem/blocks/accordions.css +1 -0
- enap_designsystem/static/enap_designsystem/blocks/semana.css +6 -5
- enap_designsystem/templates/enap_designsystem/blocks/apresentacao_block.html +8 -16
- enap_designsystem/templates/enap_designsystem/blocks/apresentacao_simple_block.html +11 -12
- enap_designsystem/templates/enap_designsystem/blocks/cards_titles.html +23 -31
- enap_designsystem/templates/enap_designsystem/blocks/formulario_dinamico.html +4 -4
- enap_designsystem/templates/enap_designsystem/blocks/logos_simple_block.html +1 -22
- enap_designsystem/templates/enap_designsystem/blocks/numeros_block.html +1 -1
- enap_designsystem/templates/enap_designsystem/blocks/section_block.html +2 -2
- enap_designsystem/templates/enap_designsystem/blocks/video_hero_banner.html +3 -8
- enap_designsystem/templates/enap_designsystem/pages/showcase_components.html +867 -464
- enap_designsystem/templates/enap_designsystem/semana_inovacao/blocks_menu_navigation.html +10 -0
- {wagtail_enap_designsystem-1.2.1.143.dist-info → wagtail_enap_designsystem-1.2.1.145.dist-info}/METADATA +1 -1
- {wagtail_enap_designsystem-1.2.1.143.dist-info → wagtail_enap_designsystem-1.2.1.145.dist-info}/RECORD +26 -23
- {wagtail_enap_designsystem-1.2.1.143.dist-info → wagtail_enap_designsystem-1.2.1.145.dist-info}/WHEEL +0 -0
- {wagtail_enap_designsystem-1.2.1.143.dist-info → wagtail_enap_designsystem-1.2.1.145.dist-info}/licenses/LICENSE +0 -0
- {wagtail_enap_designsystem-1.2.1.143.dist-info → wagtail_enap_designsystem-1.2.1.145.dist-info}/top_level.txt +0 -0
enap_designsystem/models.py
CHANGED
|
@@ -5028,231 +5028,814 @@ class SistemaVotacaoPage(Page):
|
|
|
5028
5028
|
|
|
5029
5029
|
|
|
5030
5030
|
|
|
5031
|
-
from wagtail.models import Page
|
|
5032
|
-
from wagtail.fields import RichTextField, StreamField
|
|
5033
|
-
from wagtail.admin.panels import FieldPanel
|
|
5034
5031
|
|
|
5035
|
-
|
|
5032
|
+
|
|
5033
|
+
|
|
5034
|
+
|
|
5035
|
+
|
|
5036
|
+
import logging
|
|
5037
|
+
import traceback
|
|
5038
|
+
from wagtail.blocks import StreamBlock, StructBlock, ListBlock
|
|
5039
|
+
|
|
5040
|
+
logger = logging.getLogger(__name__)
|
|
5036
5041
|
|
|
5037
5042
|
class ShowcaseComponentesDireto(Page):
|
|
5038
5043
|
"""
|
|
5039
|
-
Showcase que renderiza componentes
|
|
5040
|
-
usando valores padrão dos componentes
|
|
5044
|
+
Showcase que renderiza componentes COMPLETOS visualmente
|
|
5041
5045
|
"""
|
|
5042
5046
|
|
|
5043
5047
|
description = RichTextField(
|
|
5044
5048
|
verbose_name="Descrição",
|
|
5045
5049
|
help_text="Descrição da biblioteca de componentes",
|
|
5046
5050
|
blank=True,
|
|
5047
|
-
default="Showcase
|
|
5051
|
+
default="Showcase visual dos componentes completos"
|
|
5052
|
+
)
|
|
5053
|
+
|
|
5054
|
+
debug_mode = models.BooleanField(
|
|
5055
|
+
default=False, # False por padrão para foco na estética
|
|
5056
|
+
verbose_name="Modo Debug",
|
|
5057
|
+
help_text="Ativar para ver informações técnicas"
|
|
5058
|
+
)
|
|
5059
|
+
|
|
5060
|
+
show_errors_only = models.BooleanField(
|
|
5061
|
+
default=False,
|
|
5062
|
+
verbose_name="Mostrar Apenas Erros",
|
|
5063
|
+
help_text="Mostrar apenas componentes que falharam na renderização"
|
|
5064
|
+
)
|
|
5065
|
+
|
|
5066
|
+
filter_category = models.CharField(
|
|
5067
|
+
max_length=100,
|
|
5068
|
+
blank=True,
|
|
5069
|
+
verbose_name="Filtrar Categoria",
|
|
5070
|
+
help_text="banners, galerias, carousels, dashboards, formularios, cursos, eventos, navegacao, botoes, conteudo, secoes, cards, interativos, midia, especialidades"
|
|
5048
5071
|
)
|
|
5049
5072
|
|
|
5050
5073
|
content_panels = Page.content_panels + [
|
|
5051
5074
|
FieldPanel('description'),
|
|
5075
|
+
FieldPanel('filter_category'),
|
|
5076
|
+
FieldPanel('show_errors_only'),
|
|
5077
|
+
FieldPanel('debug_mode'),
|
|
5052
5078
|
]
|
|
5053
5079
|
|
|
5054
5080
|
template = 'enap_designsystem/pages/showcase_components.html'
|
|
5055
5081
|
|
|
5056
5082
|
class Meta:
|
|
5057
|
-
verbose_name = "Showcase
|
|
5058
|
-
verbose_name_plural = "Showcases
|
|
5083
|
+
verbose_name = "Showcase Visual de Componentes"
|
|
5084
|
+
verbose_name_plural = "Showcases Visuais de Componentes"
|
|
5059
5085
|
|
|
5060
5086
|
def get_context(self, request):
|
|
5061
5087
|
context = super().get_context(request)
|
|
5088
|
+
debug_log = []
|
|
5062
5089
|
|
|
5063
5090
|
try:
|
|
5064
|
-
#
|
|
5065
|
-
|
|
5091
|
+
# Importar LAYOUT_STREAMBLOCKS
|
|
5092
|
+
debug_log.append("Importando LAYOUT_STREAMBLOCKS...")
|
|
5093
|
+
|
|
5094
|
+
try:
|
|
5095
|
+
from .blocks import LAYOUT_STREAMBLOCKS
|
|
5096
|
+
debug_log.append(f"✅ Importado: {len(LAYOUT_STREAMBLOCKS)} categorias")
|
|
5097
|
+
except Exception as e:
|
|
5098
|
+
debug_log.append(f"❌ Erro de import: {str(e)}")
|
|
5099
|
+
raise Exception(f"Erro ao importar LAYOUT_STREAMBLOCKS: {str(e)}")
|
|
5100
|
+
|
|
5101
|
+
# Descobrir e renderizar componentes COMPLETOS
|
|
5102
|
+
categories_with_components = self.discover_and_render_complete_components(LAYOUT_STREAMBLOCKS, debug_log)
|
|
5103
|
+
|
|
5104
|
+
# Aplicar filtros
|
|
5105
|
+
if self.filter_category:
|
|
5106
|
+
categories_with_components = {
|
|
5107
|
+
k: v for k, v in categories_with_components.items()
|
|
5108
|
+
if k == self.filter_category
|
|
5109
|
+
}
|
|
5110
|
+
debug_log.append(f"Filtro aplicado: {self.filter_category}")
|
|
5111
|
+
|
|
5112
|
+
if self.show_errors_only:
|
|
5113
|
+
filtered_categories = {}
|
|
5114
|
+
for cat_name, cat_data in categories_with_components.items():
|
|
5115
|
+
error_components = [c for c in cat_data['rendered_components'] if c.get('has_error', False)]
|
|
5116
|
+
if error_components:
|
|
5117
|
+
cat_data_copy = cat_data.copy()
|
|
5118
|
+
cat_data_copy['rendered_components'] = error_components
|
|
5119
|
+
filtered_categories[cat_name] = cat_data_copy
|
|
5120
|
+
categories_with_components = filtered_categories
|
|
5121
|
+
debug_log.append("Filtro de erros aplicado")
|
|
5122
|
+
|
|
5123
|
+
# Calcular estatísticas
|
|
5124
|
+
total_components = sum(len(cat['rendered_components']) for cat in categories_with_components.values())
|
|
5125
|
+
components_ok = sum(
|
|
5126
|
+
len([c for c in cat['rendered_components'] if not c.get('has_error', False)])
|
|
5127
|
+
for cat in categories_with_components.values()
|
|
5128
|
+
)
|
|
5129
|
+
components_error = total_components - components_ok
|
|
5066
5130
|
|
|
5067
5131
|
context.update({
|
|
5068
5132
|
'categories_with_components': categories_with_components,
|
|
5069
|
-
'total_components':
|
|
5133
|
+
'total_components': total_components,
|
|
5134
|
+
'components_ok': components_ok,
|
|
5135
|
+
'components_error': components_error,
|
|
5070
5136
|
'total_categories': len(categories_with_components),
|
|
5071
|
-
'page_title': 'Showcase
|
|
5072
|
-
'page_description': 'Visualização
|
|
5137
|
+
'page_title': 'Showcase Visual - Componentes ENAP',
|
|
5138
|
+
'page_description': 'Visualização estética dos componentes do Design System',
|
|
5139
|
+
'debug_log': debug_log if self.debug_mode else [],
|
|
5140
|
+
'debug_mode': self.debug_mode,
|
|
5141
|
+
'available_categories': [name for name, _ in LAYOUT_STREAMBLOCKS],
|
|
5073
5142
|
})
|
|
5143
|
+
|
|
5074
5144
|
except Exception as e:
|
|
5145
|
+
debug_log.append(f"❌ ERRO GERAL: {str(e)}")
|
|
5146
|
+
debug_log.append(f"Traceback: {traceback.format_exc()}")
|
|
5147
|
+
logger.error(f"Erro no showcase: {e}", exc_info=True)
|
|
5148
|
+
|
|
5075
5149
|
context.update({
|
|
5076
5150
|
'error_message': f'Erro ao carregar componentes: {str(e)}',
|
|
5077
5151
|
'categories_with_components': {},
|
|
5078
5152
|
'total_components': 0,
|
|
5153
|
+
'components_ok': 0,
|
|
5154
|
+
'components_error': 0,
|
|
5079
5155
|
'total_categories': 0,
|
|
5156
|
+
'debug_log': debug_log,
|
|
5157
|
+
'debug_mode': self.debug_mode,
|
|
5158
|
+
'available_categories': [],
|
|
5080
5159
|
})
|
|
5081
5160
|
|
|
5082
5161
|
return context
|
|
5083
5162
|
|
|
5084
|
-
def
|
|
5085
|
-
"""
|
|
5163
|
+
def discover_and_render_complete_components(self, layout_streamblocks, debug_log):
|
|
5164
|
+
"""Descobre e renderiza componentes COMPLETOS, não os campos individuais"""
|
|
5086
5165
|
categories = {}
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
# Mapeamento de ícones
|
|
5090
|
-
category_icons = {
|
|
5091
|
-
'banners': 'image',
|
|
5092
|
-
'galerias': 'images',
|
|
5093
|
-
'carousels': 'arrows-up-down',
|
|
5094
|
-
'dashboards': 'bar-chart',
|
|
5095
|
-
'formularios': 'form',
|
|
5096
|
-
'cursos': 'graduation-cap',
|
|
5097
|
-
'eventos': 'calendar',
|
|
5098
|
-
'navegacao': 'bars',
|
|
5099
|
-
'menus': 'list-ul',
|
|
5100
|
-
'botoes': 'mouse-pointer',
|
|
5101
|
-
'conteudo': 'file-text',
|
|
5102
|
-
'secoes': 'th-large',
|
|
5103
|
-
'cards': 'clone',
|
|
5104
|
-
'interativos': 'cogs',
|
|
5105
|
-
'midia': 'play-circle',
|
|
5106
|
-
'especialidades': 'puzzle-piece',
|
|
5107
|
-
}
|
|
5108
|
-
|
|
5109
|
-
# Descrições das categorias
|
|
5110
|
-
category_descriptions = {
|
|
5111
|
-
'banners': 'Componentes para banners, heroes e seções de destaque visual',
|
|
5112
|
-
'galerias': 'Componentes para exibição de imagens, galerias e portfolios',
|
|
5113
|
-
'carousels': 'Componentes de carrosséis, sliders e apresentações rotativas',
|
|
5114
|
-
'dashboards': 'Componentes para dashboards, KPIs, métricas e visualização de dados',
|
|
5115
|
-
'formularios': 'Componentes de formulários, campos de entrada e interação',
|
|
5116
|
-
'cursos': 'Componentes específicos para cursos, educação e capacitação',
|
|
5117
|
-
'eventos': 'Componentes para eventos, cronogramas, timelines e agenda',
|
|
5118
|
-
'navegacao': 'Componentes de navegação, menus e estrutura de site',
|
|
5119
|
-
'menus': 'Componentes de menu e navegação',
|
|
5120
|
-
'botoes': 'Componentes de botões, call-to-actions e elementos clicáveis',
|
|
5121
|
-
'conteudo': 'Componentes de conteúdo, texto rico, citações e mídia',
|
|
5122
|
-
'secoes': 'Componentes de seções, containers e estruturas de layout',
|
|
5123
|
-
'cards': 'Componentes de cards, grids e elementos organizacionais',
|
|
5124
|
-
'interativos': 'Componentes interativos, acordeões, modais e elementos dinâmicos',
|
|
5125
|
-
'midia': 'Componentes de vídeo, áudio, podcasts e conteúdo multimídia',
|
|
5126
|
-
'especialidades': 'Componentes especializados e funcionalidades específicas da ENAP',
|
|
5127
|
-
}
|
|
5166
|
+
debug_log.append("\n=== DESCOBRINDO COMPONENTES COMPLETOS ===")
|
|
5128
5167
|
|
|
5129
5168
|
for stream_name, stream_block in layout_streamblocks:
|
|
5130
|
-
|
|
5131
|
-
if stream_name in ['enap_section', 'recaptcha']:
|
|
5132
|
-
continue
|
|
5169
|
+
debug_log.append(f"\nProcessando categoria: {stream_name}")
|
|
5133
5170
|
|
|
5134
|
-
|
|
5171
|
+
# Pular categorias que são muito complexas ou não visuais
|
|
5172
|
+
if self.should_skip_category(stream_name):
|
|
5173
|
+
debug_log.append(f" ⏭️ Pulando categoria complexa: {stream_name}")
|
|
5135
5174
|
continue
|
|
5136
|
-
|
|
5175
|
+
|
|
5176
|
+
# Criar categoria
|
|
5137
5177
|
category_info = {
|
|
5138
5178
|
'name': stream_name,
|
|
5139
|
-
'display_name': self.
|
|
5140
|
-
'icon':
|
|
5141
|
-
'description':
|
|
5179
|
+
'display_name': self.format_category_name(stream_name),
|
|
5180
|
+
'icon': self.get_category_icon(stream_name),
|
|
5181
|
+
'description': self.get_category_description(stream_name),
|
|
5142
5182
|
'rendered_components': []
|
|
5143
5183
|
}
|
|
5144
5184
|
|
|
5145
|
-
#
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5185
|
+
# Extrair componentes da categoria
|
|
5186
|
+
if hasattr(stream_block, 'child_blocks') and stream_block.child_blocks:
|
|
5187
|
+
debug_log.append(f" 📦 Categoria com {len(stream_block.child_blocks)} componentes")
|
|
5188
|
+
|
|
5189
|
+
for comp_name, comp_block in stream_block.child_blocks.items():
|
|
5190
|
+
debug_log.append(f" 🔧 Renderizando: {comp_name}")
|
|
5191
|
+
|
|
5192
|
+
# Renderizar o componente COMPLETO
|
|
5193
|
+
rendered_comp = self.render_complete_component(
|
|
5194
|
+
comp_name, comp_block, stream_name, debug_log
|
|
5195
|
+
)
|
|
5196
|
+
|
|
5197
|
+
if rendered_comp:
|
|
5198
|
+
category_info['rendered_components'].append(rendered_comp)
|
|
5199
|
+
status = "❌" if rendered_comp.get('has_error') else "✅"
|
|
5200
|
+
debug_log.append(f" {status} Adicionado")
|
|
5201
|
+
else:
|
|
5202
|
+
debug_log.append(f" ❌ Falhou completamente")
|
|
5203
|
+
|
|
5204
|
+
elif self.is_single_renderable_component(stream_block):
|
|
5205
|
+
# Se a categoria é um componente único
|
|
5206
|
+
debug_log.append(f" 🎯 Categoria é componente único")
|
|
5207
|
+
rendered_comp = self.render_complete_component(
|
|
5208
|
+
stream_name, stream_block, stream_name, debug_log
|
|
5149
5209
|
)
|
|
5150
|
-
if
|
|
5151
|
-
category_info['rendered_components'].append(
|
|
5210
|
+
if rendered_comp:
|
|
5211
|
+
category_info['rendered_components'].append(rendered_comp)
|
|
5152
5212
|
|
|
5153
|
-
|
|
5213
|
+
else:
|
|
5214
|
+
debug_log.append(f" ⚠️ Categoria não processável: {stream_block.__class__.__name__}")
|
|
5215
|
+
|
|
5216
|
+
# Adicionar categoria se tiver componentes
|
|
5154
5217
|
if category_info['rendered_components']:
|
|
5155
5218
|
categories[stream_name] = category_info
|
|
5219
|
+
debug_log.append(f" ✅ Categoria adicionada com {len(category_info['rendered_components'])} componentes")
|
|
5220
|
+
else:
|
|
5221
|
+
debug_log.append(f" ❌ Categoria ignorada (sem componentes)")
|
|
5156
5222
|
|
|
5223
|
+
debug_log.append(f"\n📊 TOTAL: {len(categories)} categorias processadas")
|
|
5157
5224
|
return categories
|
|
5158
5225
|
|
|
5159
|
-
def
|
|
5160
|
-
"""
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5226
|
+
def should_skip_category(self, stream_name):
|
|
5227
|
+
"""Determina se deve pular uma categoria"""
|
|
5228
|
+
skip_list = [
|
|
5229
|
+
'enap_section', # Muito complexa
|
|
5230
|
+
'recaptcha', # Não visual
|
|
5231
|
+
]
|
|
5232
|
+
return stream_name in skip_list
|
|
5233
|
+
|
|
5234
|
+
def is_single_renderable_component(self, block):
|
|
5235
|
+
"""Verifica se o bloco é um componente único renderizável"""
|
|
5236
|
+
class_name = block.__class__.__name__
|
|
5167
5237
|
|
|
5168
|
-
|
|
5238
|
+
# Se termina com Block e tem método render, é renderizável
|
|
5239
|
+
if class_name.endswith('Block') and hasattr(block, 'render'):
|
|
5240
|
+
return True
|
|
5241
|
+
|
|
5242
|
+
return False
|
|
5169
5243
|
|
|
5170
|
-
def
|
|
5171
|
-
"""Renderiza um componente
|
|
5244
|
+
def render_complete_component(self, comp_name, comp_block, category_name, debug_log):
|
|
5245
|
+
"""Renderiza um componente COMPLETO com dados realistas"""
|
|
5172
5246
|
try:
|
|
5173
|
-
|
|
5174
|
-
|
|
5247
|
+
debug_log.append(f" 🎨 Tipo: {comp_block.__class__.__name__}")
|
|
5248
|
+
|
|
5249
|
+
# Gerar dados COMPLETOS para o componente
|
|
5250
|
+
component_data = self.generate_realistic_component_data(comp_name, comp_block, debug_log)
|
|
5175
5251
|
|
|
5176
5252
|
# Tentar renderizar
|
|
5253
|
+
rendered_html = None
|
|
5254
|
+
render_error = None
|
|
5255
|
+
|
|
5177
5256
|
try:
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5257
|
+
debug_log.append(f" 🎯 Tentando renderizar componente completo...")
|
|
5258
|
+
rendered_html = comp_block.render(component_data)
|
|
5259
|
+
debug_log.append(f" ✅ Renderizado com sucesso ({len(rendered_html)} chars)")
|
|
5260
|
+
has_error = False
|
|
5261
|
+
except Exception as e:
|
|
5262
|
+
debug_log.append(f" ❌ Erro na renderização: {str(e)}")
|
|
5263
|
+
render_error = str(e)
|
|
5264
|
+
|
|
5265
|
+
# Tentar com dados mínimos
|
|
5181
5266
|
try:
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5267
|
+
debug_log.append(f" 🔄 Tentando com dados mínimos...")
|
|
5268
|
+
minimal_data = self.generate_minimal_component_data(comp_block)
|
|
5269
|
+
rendered_html = comp_block.render(minimal_data)
|
|
5270
|
+
debug_log.append(f" ✅ Renderizado com dados mínimos")
|
|
5271
|
+
has_error = False
|
|
5272
|
+
except Exception as e2:
|
|
5273
|
+
debug_log.append(f" ❌ Falhou também com dados mínimos: {str(e2)}")
|
|
5274
|
+
rendered_html = self.create_visual_placeholder(comp_name, category_name, str(e))
|
|
5275
|
+
has_error = True
|
|
5186
5276
|
|
|
5187
5277
|
return {
|
|
5188
|
-
'name':
|
|
5189
|
-
'display_name': self.get_component_display_name(
|
|
5190
|
-
'class_name':
|
|
5278
|
+
'name': comp_name,
|
|
5279
|
+
'display_name': self.get_component_display_name(comp_block, comp_name),
|
|
5280
|
+
'class_name': comp_block.__class__.__name__,
|
|
5191
5281
|
'rendered_html': rendered_html,
|
|
5192
5282
|
'category_name': category_name,
|
|
5193
|
-
'has_error':
|
|
5194
|
-
'
|
|
5283
|
+
'has_error': has_error,
|
|
5284
|
+
'error_message': render_error if has_error else None,
|
|
5285
|
+
'data_used': component_data if self.debug_mode else {},
|
|
5195
5286
|
}
|
|
5196
5287
|
|
|
5197
5288
|
except Exception as e:
|
|
5198
|
-
|
|
5289
|
+
debug_log.append(f" 💥 ERRO GERAL: {str(e)}")
|
|
5199
5290
|
return None
|
|
5200
5291
|
|
|
5201
|
-
def
|
|
5202
|
-
"""
|
|
5203
|
-
if hasattr(
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5292
|
+
def generate_realistic_component_data(self, comp_name, comp_block, debug_log):
|
|
5293
|
+
"""Gera dados realistas para renderização visual completa"""
|
|
5294
|
+
if not hasattr(comp_block, 'child_blocks'):
|
|
5295
|
+
return {}
|
|
5296
|
+
|
|
5297
|
+
data = {}
|
|
5298
|
+
debug_log.append(f" 📝 Gerando dados para {len(comp_block.child_blocks)} campos")
|
|
5299
|
+
|
|
5300
|
+
for field_name, field_block in comp_block.child_blocks.items():
|
|
5301
|
+
value = self.generate_realistic_field_value(field_name, field_block, comp_name)
|
|
5302
|
+
data[field_name] = value
|
|
5303
|
+
|
|
5304
|
+
if self.debug_mode:
|
|
5305
|
+
debug_log.append(f" {field_name}: {str(value)[:50]}...")
|
|
5306
|
+
|
|
5307
|
+
return data
|
|
5308
|
+
|
|
5309
|
+
def generate_realistic_field_value(self, field_name, field_block, comp_name):
|
|
5310
|
+
"""Gera valores realistas baseados no contexto ENAP com defaults específicos por tipo"""
|
|
5311
|
+
field_type = field_block.__class__.__name__
|
|
5312
|
+
field_lower = field_name.lower()
|
|
5313
|
+
|
|
5314
|
+
# Usar default se existir
|
|
5315
|
+
if hasattr(field_block, 'default') and field_block.default is not None:
|
|
5316
|
+
return field_block.default
|
|
5211
5317
|
|
|
5212
|
-
|
|
5318
|
+
# DEFAULTS ESPECÍFICOS POR TIPO DE CAMPO
|
|
5319
|
+
|
|
5320
|
+
# === IMAGENS ===
|
|
5321
|
+
if field_type in ['ImageChooserBlock', 'ImageBlock']:
|
|
5322
|
+
return self.get_default_image_value(field_name)
|
|
5323
|
+
|
|
5324
|
+
# === DOCUMENTOS ===
|
|
5325
|
+
elif field_type in ['DocumentChooserBlock', 'DocumentBlock']:
|
|
5326
|
+
return self.get_default_document_value(field_name)
|
|
5327
|
+
|
|
5328
|
+
# === PÁGINAS ===
|
|
5329
|
+
elif field_type in ['PageChooserBlock', 'PageBlock']:
|
|
5330
|
+
return self.get_default_page_value(field_name)
|
|
5331
|
+
|
|
5332
|
+
# === SNIPPETS ===
|
|
5333
|
+
elif field_type in ['SnippetChooserBlock']:
|
|
5334
|
+
return None # Snippets são mais complexos, deixar vazio
|
|
5335
|
+
|
|
5336
|
+
# === BLOCOS ESTRUTURADOS ===
|
|
5337
|
+
elif field_type == 'StructBlock':
|
|
5338
|
+
return {} # Será processado recursivamente
|
|
5339
|
+
|
|
5340
|
+
elif field_type == 'ListBlock':
|
|
5341
|
+
return [] # Lista vazia por padrão
|
|
5342
|
+
|
|
5343
|
+
elif field_type == 'StreamBlock':
|
|
5344
|
+
return [] # Stream vazio por padrão
|
|
5345
|
+
|
|
5346
|
+
# === CAMPOS DE ESCOLHA ===
|
|
5347
|
+
elif field_type == 'ChoiceBlock':
|
|
5348
|
+
return self.get_choice_default_value(field_block, field_name)
|
|
5349
|
+
|
|
5350
|
+
# === CAMPOS BÁSICOS ===
|
|
5351
|
+
elif field_type == 'BooleanBlock':
|
|
5352
|
+
return self.get_boolean_default_value(field_name)
|
|
5353
|
+
|
|
5354
|
+
elif field_type in ['IntegerBlock', 'FloatBlock', 'DecimalBlock']:
|
|
5355
|
+
return self.get_numeric_default_value(field_name, field_type)
|
|
5356
|
+
|
|
5357
|
+
elif field_type in ['DateBlock', 'TimeBlock', 'DateTimeBlock']:
|
|
5358
|
+
return self.get_datetime_default_value(field_type)
|
|
5359
|
+
|
|
5360
|
+
elif field_type == 'RichTextBlock':
|
|
5361
|
+
return self.get_richtext_default_value(field_name)
|
|
5362
|
+
|
|
5363
|
+
elif field_type in ['URLBlock']:
|
|
5364
|
+
return self.get_url_default_value(field_name)
|
|
5365
|
+
|
|
5366
|
+
elif field_type == 'EmailBlock':
|
|
5367
|
+
return self.get_email_default_value(field_name)
|
|
5368
|
+
|
|
5369
|
+
elif field_type in ['TextBlock', 'CharBlock']:
|
|
5370
|
+
return self.get_text_default_value(field_name, field_lower)
|
|
5371
|
+
|
|
5372
|
+
elif field_type == 'RegexBlock':
|
|
5373
|
+
return 'ABC123' # Valor que geralmente passa em regex básicas
|
|
5374
|
+
|
|
5375
|
+
elif field_type == 'RawHTMLBlock':
|
|
5376
|
+
return '<div class="exemplo">Conteúdo HTML de exemplo</div>'
|
|
5377
|
+
|
|
5378
|
+
# === BLOCOS CUSTOMIZADOS ===
|
|
5379
|
+
elif 'Color' in field_type:
|
|
5380
|
+
return '#3B82F6' # Azul padrão
|
|
5381
|
+
|
|
5382
|
+
elif 'Icon' in field_type:
|
|
5383
|
+
return 'fas fa-star' # Ícone padrão
|
|
5384
|
+
|
|
5385
|
+
# Valor padrão genérico
|
|
5386
|
+
return f'Exemplo ENAP - {field_name}'
|
|
5213
5387
|
|
|
5214
|
-
def
|
|
5215
|
-
"""Gera
|
|
5216
|
-
|
|
5388
|
+
def get_default_image_value(self, field_name):
|
|
5389
|
+
"""Gera valor padrão para campos de imagem"""
|
|
5390
|
+
from wagtail.images.models import Image
|
|
5217
5391
|
|
|
5218
|
-
|
|
5219
|
-
|
|
5392
|
+
# Tentar encontrar uma imagem existente no sistema
|
|
5393
|
+
try:
|
|
5394
|
+
# Buscar por imagens que possam ser usadas como placeholder
|
|
5395
|
+
placeholder_images = Image.objects.filter(
|
|
5396
|
+
title__icontains='placeholder'
|
|
5397
|
+
).first()
|
|
5220
5398
|
|
|
5221
|
-
|
|
5222
|
-
|
|
5399
|
+
if placeholder_images:
|
|
5400
|
+
return placeholder_images
|
|
5223
5401
|
|
|
5224
|
-
#
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5402
|
+
# Buscar por imagens com nomes genéricos
|
|
5403
|
+
generic_names = ['exemplo', 'sample', 'test', 'demo', 'enap', 'logo']
|
|
5404
|
+
for name in generic_names:
|
|
5405
|
+
image = Image.objects.filter(title__icontains=name).first()
|
|
5406
|
+
if image:
|
|
5407
|
+
return image
|
|
5228
5408
|
|
|
5229
|
-
#
|
|
5230
|
-
|
|
5409
|
+
# Se não encontrar, usar qualquer imagem
|
|
5410
|
+
any_image = Image.objects.first()
|
|
5411
|
+
if any_image:
|
|
5412
|
+
return any_image
|
|
5413
|
+
|
|
5414
|
+
except Exception:
|
|
5415
|
+
pass
|
|
5416
|
+
|
|
5417
|
+
# Se não houver imagens, criar uma imagem placeholder via código
|
|
5418
|
+
return self.create_placeholder_image_object(field_name)
|
|
5419
|
+
|
|
5420
|
+
def create_placeholder_image_object(self, field_name):
|
|
5421
|
+
"""Cria um objeto placeholder para representar uma imagem"""
|
|
5422
|
+
# Como não podemos criar imagens reais sem arquivos,
|
|
5423
|
+
# retornamos None e deixamos o template lidar com isso
|
|
5424
|
+
# O template deve mostrar um placeholder visual
|
|
5425
|
+
return None
|
|
5426
|
+
|
|
5427
|
+
def get_default_document_value(self, field_name):
|
|
5428
|
+
"""Gera valor padrão para campos de documento"""
|
|
5429
|
+
from wagtail.documents.models import Document
|
|
5430
|
+
|
|
5431
|
+
try:
|
|
5432
|
+
# Buscar documento de exemplo
|
|
5433
|
+
example_doc = Document.objects.filter(
|
|
5434
|
+
title__icontains='exemplo'
|
|
5435
|
+
).first()
|
|
5436
|
+
|
|
5437
|
+
if example_doc:
|
|
5438
|
+
return example_doc
|
|
5439
|
+
|
|
5440
|
+
# Qualquer documento
|
|
5441
|
+
any_doc = Document.objects.first()
|
|
5442
|
+
if any_doc:
|
|
5443
|
+
return any_doc
|
|
5444
|
+
|
|
5445
|
+
except Exception:
|
|
5446
|
+
pass
|
|
5447
|
+
|
|
5448
|
+
return None
|
|
5449
|
+
|
|
5450
|
+
def get_default_page_value(self, field_name):
|
|
5451
|
+
"""Gera valor padrão para campos de página"""
|
|
5452
|
+
from wagtail.models import Page
|
|
5453
|
+
|
|
5454
|
+
try:
|
|
5455
|
+
# Buscar página home ou root
|
|
5456
|
+
home_page = Page.objects.filter(
|
|
5457
|
+
slug__in=['home', 'inicio', 'root']
|
|
5458
|
+
).first()
|
|
5459
|
+
|
|
5460
|
+
if home_page:
|
|
5461
|
+
return home_page
|
|
5462
|
+
|
|
5463
|
+
# Qualquer página que não seja root
|
|
5464
|
+
any_page = Page.objects.filter(depth__gt=1).first()
|
|
5465
|
+
if any_page:
|
|
5466
|
+
return any_page
|
|
5467
|
+
|
|
5468
|
+
except Exception:
|
|
5469
|
+
pass
|
|
5470
|
+
|
|
5471
|
+
return None
|
|
5472
|
+
|
|
5473
|
+
def get_choice_default_value(self, field_block, field_name):
|
|
5474
|
+
"""Gera valor padrão para campos de escolha"""
|
|
5475
|
+
try:
|
|
5476
|
+
if hasattr(field_block, 'choices') and field_block.choices:
|
|
5477
|
+
# Retornar a primeira opção
|
|
5478
|
+
return field_block.choices[0][0]
|
|
5479
|
+
except Exception:
|
|
5480
|
+
pass
|
|
5481
|
+
|
|
5482
|
+
return 'opcao1'
|
|
5483
|
+
|
|
5484
|
+
def get_boolean_default_value(self, field_name):
|
|
5485
|
+
"""Gera valor padrão para campos boolean"""
|
|
5486
|
+
field_lower = field_name.lower()
|
|
5487
|
+
|
|
5488
|
+
# Campos que geralmente são False por padrão
|
|
5489
|
+
false_defaults = [
|
|
5490
|
+
'disable', 'hidden', 'private', 'draft', 'inactive',
|
|
5491
|
+
'closed', 'locked', 'disabled', 'hide'
|
|
5492
|
+
]
|
|
5493
|
+
|
|
5494
|
+
for false_word in false_defaults:
|
|
5495
|
+
if false_word in field_lower:
|
|
5496
|
+
return False
|
|
5497
|
+
|
|
5498
|
+
# Maioria dos booleans são True para melhor visualização
|
|
5499
|
+
return True
|
|
5500
|
+
|
|
5501
|
+
def get_numeric_default_value(self, field_name, field_type):
|
|
5502
|
+
"""Gera valor padrão para campos numéricos"""
|
|
5503
|
+
field_lower = field_name.lower()
|
|
5504
|
+
|
|
5505
|
+
# Valores específicos baseados no nome
|
|
5506
|
+
if 'price' in field_lower or 'preco' in field_lower:
|
|
5507
|
+
return 299.90 if field_type == 'FloatBlock' else 299
|
|
5508
|
+
elif 'year' in field_lower or 'ano' in field_lower:
|
|
5509
|
+
return 2024
|
|
5510
|
+
elif 'month' in field_lower or 'mes' in field_lower:
|
|
5511
|
+
return 6
|
|
5512
|
+
elif 'day' in field_lower or 'dia' in field_lower:
|
|
5513
|
+
return 15
|
|
5514
|
+
elif 'hour' in field_lower or 'hora' in field_lower:
|
|
5515
|
+
return 14
|
|
5516
|
+
elif 'minute' in field_lower or 'minuto' in field_lower:
|
|
5517
|
+
return 30
|
|
5518
|
+
elif 'percent' in field_lower or 'porcentagem' in field_lower:
|
|
5519
|
+
return 85.5 if field_type == 'FloatBlock' else 85
|
|
5520
|
+
elif 'count' in field_lower or 'total' in field_lower:
|
|
5521
|
+
return 42
|
|
5522
|
+
elif 'order' in field_lower or 'ordem' in field_lower:
|
|
5523
|
+
return 1
|
|
5524
|
+
|
|
5525
|
+
# Valor padrão genérico
|
|
5526
|
+
return 100.0 if field_type == 'FloatBlock' else 100
|
|
5527
|
+
|
|
5528
|
+
def get_datetime_default_value(self, field_type):
|
|
5529
|
+
"""Gera valor padrão para campos de data/hora"""
|
|
5530
|
+
if field_type == 'DateBlock':
|
|
5531
|
+
return '2024-06-15'
|
|
5532
|
+
elif field_type == 'TimeBlock':
|
|
5533
|
+
return '14:30:00'
|
|
5534
|
+
elif field_type == 'DateTimeBlock':
|
|
5535
|
+
return '2024-06-15T14:30:00'
|
|
5536
|
+
|
|
5537
|
+
return '2024-06-15'
|
|
5538
|
+
|
|
5539
|
+
def get_richtext_default_value(self, field_name):
|
|
5540
|
+
"""Gera valor padrão para campos de texto rico"""
|
|
5541
|
+
field_lower = field_name.lower()
|
|
5542
|
+
|
|
5543
|
+
# Conteúdos específicos baseados no nome do campo
|
|
5544
|
+
if 'about' in field_lower or 'sobre' in field_lower:
|
|
5545
|
+
return '''
|
|
5546
|
+
<h3>Sobre a ENAP</h3>
|
|
5547
|
+
<p>A <strong>Escola Nacional de Administração Pública</strong> é responsável pela capacitação e desenvolvimento de servidores públicos federais.</p>
|
|
5548
|
+
<ul>
|
|
5549
|
+
<li>Cursos presenciais e à distância</li>
|
|
5550
|
+
<li>Eventos e seminários</li>
|
|
5551
|
+
<li>Pesquisas em gestão pública</li>
|
|
5552
|
+
</ul>
|
|
5553
|
+
'''
|
|
5554
|
+
elif 'content' in field_lower or 'conteudo' in field_lower:
|
|
5555
|
+
return '''
|
|
5556
|
+
<h2>Modernização da Gestão Pública</h2>
|
|
5557
|
+
<p>A ENAP promove a <em>excelência na administração pública</em> através de:</p>
|
|
5558
|
+
<ol>
|
|
5559
|
+
<li><strong>Capacitação continuada</strong> de servidores</li>
|
|
5560
|
+
<li><strong>Pesquisa aplicada</strong> em gestão pública</li>
|
|
5561
|
+
<li><strong>Inovação</strong> em processos governamentais</li>
|
|
5562
|
+
</ol>
|
|
5563
|
+
<blockquote>
|
|
5564
|
+
<p>"Transformando a administração pública através do conhecimento"</p>
|
|
5565
|
+
</blockquote>
|
|
5566
|
+
'''
|
|
5567
|
+
elif 'description' in field_lower or 'descricao' in field_lower:
|
|
5568
|
+
return '''
|
|
5569
|
+
<p>Desenvolvemos <strong>competências e habilidades</strong> dos servidores para uma gestão pública moderna, eficiente e orientada ao cidadão.</p>
|
|
5570
|
+
<p>Nossa missão é contribuir para a modernização do Estado através da capacitação de seus servidores.</p>
|
|
5571
|
+
'''
|
|
5572
|
+
|
|
5573
|
+
# Conteúdo padrão genérico
|
|
5574
|
+
return '''
|
|
5575
|
+
<h3>Título de Exemplo</h3>
|
|
5576
|
+
<p>Este é um conteúdo de <strong>exemplo</strong> em texto rico para demonstrar a funcionalidade do componente.</p>
|
|
5577
|
+
<p>Inclui <em>formatação básica</em> e <a href="https://www.enap.gov.br">links externos</a>.</p>
|
|
5578
|
+
'''
|
|
5579
|
+
|
|
5580
|
+
def get_url_default_value(self, field_name):
|
|
5581
|
+
"""Gera valor padrão para campos de URL"""
|
|
5582
|
+
field_lower = field_name.lower()
|
|
5583
|
+
|
|
5584
|
+
# URLs específicas baseadas no nome do campo
|
|
5585
|
+
url_mapping = {
|
|
5586
|
+
'site': 'https://www.enap.gov.br',
|
|
5587
|
+
'home': 'https://www.enap.gov.br',
|
|
5588
|
+
'curso': 'https://www.enap.gov.br/cursos',
|
|
5589
|
+
'course': 'https://www.enap.gov.br/cursos',
|
|
5590
|
+
'event': 'https://www.enap.gov.br/eventos',
|
|
5591
|
+
'evento': 'https://www.enap.gov.br/eventos',
|
|
5592
|
+
'news': 'https://www.enap.gov.br/noticias',
|
|
5593
|
+
'noticia': 'https://www.enap.gov.br/noticias',
|
|
5594
|
+
'contact': 'https://www.enap.gov.br/contato',
|
|
5595
|
+
'contato': 'https://www.enap.gov.br/contato',
|
|
5596
|
+
'blog': 'https://www.enap.gov.br/blog',
|
|
5597
|
+
'video': 'https://www.youtube.com/watch?v=example',
|
|
5598
|
+
'youtube': 'https://www.youtube.com/watch?v=example',
|
|
5599
|
+
'social': 'https://www.linkedin.com/company/enap',
|
|
5600
|
+
'linkedin': 'https://www.linkedin.com/company/enap',
|
|
5601
|
+
'facebook': 'https://www.facebook.com/enap.oficial',
|
|
5602
|
+
'twitter': 'https://twitter.com/enap_oficial',
|
|
5603
|
+
'instagram': 'https://instagram.com/enap_oficial',
|
|
5604
|
+
}
|
|
5605
|
+
|
|
5606
|
+
for key, url in url_mapping.items():
|
|
5607
|
+
if key in field_lower:
|
|
5608
|
+
return url
|
|
5609
|
+
|
|
5610
|
+
# URL padrão
|
|
5611
|
+
return 'https://www.enap.gov.br'
|
|
5612
|
+
|
|
5613
|
+
def get_email_default_value(self, field_name):
|
|
5614
|
+
"""Gera valor padrão para campos de email"""
|
|
5615
|
+
field_lower = field_name.lower()
|
|
5616
|
+
|
|
5617
|
+
# Emails específicos baseados no nome do campo
|
|
5618
|
+
email_mapping = {
|
|
5619
|
+
'contact': 'contato@enap.gov.br',
|
|
5620
|
+
'contato': 'contato@enap.gov.br',
|
|
5621
|
+
'support': 'suporte@enap.gov.br',
|
|
5622
|
+
'suporte': 'suporte@enap.gov.br',
|
|
5623
|
+
'admin': 'admin@enap.gov.br',
|
|
5624
|
+
'curso': 'cursos@enap.gov.br',
|
|
5625
|
+
'course': 'cursos@enap.gov.br',
|
|
5626
|
+
'event': 'eventos@enap.gov.br',
|
|
5627
|
+
'evento': 'eventos@enap.gov.br',
|
|
5628
|
+
'news': 'noticias@enap.gov.br',
|
|
5629
|
+
'noticia': 'noticias@enap.gov.br',
|
|
5630
|
+
'inscricao': 'inscricoes@enap.gov.br',
|
|
5631
|
+
'registration': 'inscricoes@enap.gov.br',
|
|
5632
|
+
}
|
|
5633
|
+
|
|
5634
|
+
for key, email in email_mapping.items():
|
|
5635
|
+
if key in field_lower:
|
|
5636
|
+
return email
|
|
5637
|
+
|
|
5638
|
+
# Email padrão
|
|
5639
|
+
return 'contato@enap.gov.br'
|
|
5640
|
+
|
|
5641
|
+
def get_text_default_value(self, field_name, field_lower):
|
|
5642
|
+
"""Gera valor padrão para campos de texto"""
|
|
5643
|
+
# Conteúdos específicos da ENAP baseados no nome do campo
|
|
5644
|
+
|
|
5645
|
+
if 'title' in field_lower or 'titulo' in field_lower:
|
|
5646
|
+
titles = [
|
|
5647
|
+
'Escola Nacional de Administração Pública',
|
|
5648
|
+
'Capacitação para o Serviço Público',
|
|
5649
|
+
'Inovação na Gestão Pública',
|
|
5650
|
+
'Transformação Digital do Governo',
|
|
5651
|
+
'Excelência em Administração Pública'
|
|
5652
|
+
]
|
|
5653
|
+
import random
|
|
5654
|
+
return random.choice(titles)
|
|
5655
|
+
|
|
5656
|
+
elif 'subtitle' in field_lower or 'subtitulo' in field_lower:
|
|
5657
|
+
return 'Excelência em capacitação para o serviço público'
|
|
5231
5658
|
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5659
|
+
elif 'description' in field_lower or 'descricao' in field_lower:
|
|
5660
|
+
descriptions = [
|
|
5661
|
+
'A ENAP é a escola de governo do Poder Executivo federal, responsável pela formação e capacitação de servidores públicos.',
|
|
5662
|
+
'Desenvolvemos competências e habilidades dos servidores para uma gestão pública moderna, eficiente e orientada ao cidadão.',
|
|
5663
|
+
'Nossa missão é contribuir para a modernização do Estado através da capacitação de seus servidores.',
|
|
5664
|
+
'Promovemos a inovação e a transformação digital na administração pública federal.'
|
|
5665
|
+
]
|
|
5666
|
+
import random
|
|
5667
|
+
return random.choice(descriptions)
|
|
5668
|
+
|
|
5669
|
+
elif 'button' in field_lower or 'botao' in field_lower or 'cta' in field_lower:
|
|
5670
|
+
buttons = ['Saiba Mais', 'Inscreva-se', 'Conheça', 'Participe', 'Acesse', 'Baixar', 'Ver Mais']
|
|
5671
|
+
import random
|
|
5672
|
+
return random.choice(buttons)
|
|
5673
|
+
|
|
5674
|
+
elif 'name' in field_lower or 'nome' in field_lower:
|
|
5675
|
+
return 'ENAP - Escola Nacional de Administração Pública'
|
|
5676
|
+
|
|
5677
|
+
elif 'author' in field_lower or 'autor' in field_lower:
|
|
5678
|
+
return 'Equipe ENAP'
|
|
5679
|
+
|
|
5680
|
+
elif 'phone' in field_lower or 'telefone' in field_lower:
|
|
5681
|
+
return '(61) 2020-3000'
|
|
5682
|
+
|
|
5683
|
+
elif 'address' in field_lower or 'endereco' in field_lower:
|
|
5684
|
+
return 'SAIS - Área 2-A - Brasília/DF - CEP: 70610-900'
|
|
5685
|
+
|
|
5686
|
+
elif 'city' in field_lower or 'cidade' in field_lower:
|
|
5687
|
+
return 'Brasília'
|
|
5688
|
+
|
|
5689
|
+
elif 'state' in field_lower or 'estado' in field_lower:
|
|
5690
|
+
return 'Distrito Federal'
|
|
5691
|
+
|
|
5692
|
+
elif 'country' in field_lower or 'pais' in field_lower:
|
|
5693
|
+
return 'Brasil'
|
|
5694
|
+
|
|
5695
|
+
elif 'price' in field_lower or 'preco' in field_lower:
|
|
5696
|
+
return 'Gratuito'
|
|
5697
|
+
|
|
5698
|
+
elif 'duration' in field_lower or 'duracao' in field_lower:
|
|
5699
|
+
return '40 horas'
|
|
5700
|
+
|
|
5701
|
+
elif 'level' in field_lower or 'nivel' in field_lower:
|
|
5702
|
+
return 'Intermediário'
|
|
5703
|
+
|
|
5704
|
+
elif 'category' in field_lower or 'categoria' in field_lower:
|
|
5705
|
+
return 'Gestão Pública'
|
|
5706
|
+
|
|
5707
|
+
elif 'tag' in field_lower:
|
|
5708
|
+
return 'capacitacao'
|
|
5709
|
+
|
|
5710
|
+
elif 'slug' in field_lower:
|
|
5711
|
+
return 'exemplo-componente-enap'
|
|
5712
|
+
|
|
5713
|
+
# Valor padrão baseado no nome do campo
|
|
5714
|
+
return f'Exemplo ENAP - {field_name.replace("_", " ").title()}'
|
|
5715
|
+
|
|
5716
|
+
def generate_minimal_component_data(self, comp_block):
|
|
5717
|
+
"""Gera dados mínimos para fallback"""
|
|
5718
|
+
if not hasattr(comp_block, 'child_blocks'):
|
|
5719
|
+
return {}
|
|
5720
|
+
|
|
5721
|
+
minimal = {}
|
|
5722
|
+
for field_name, field_block in comp_block.child_blocks.items():
|
|
5723
|
+
field_type = field_block.__class__.__name__
|
|
5724
|
+
|
|
5725
|
+
if 'title' in field_name.lower():
|
|
5726
|
+
minimal[field_name] = 'ENAP'
|
|
5246
5727
|
elif field_type == 'BooleanBlock':
|
|
5247
|
-
|
|
5728
|
+
minimal[field_name] = True
|
|
5248
5729
|
elif field_type in ['IntegerBlock', 'FloatBlock']:
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5730
|
+
minimal[field_name] = 1
|
|
5731
|
+
|
|
5732
|
+
return minimal
|
|
5733
|
+
|
|
5734
|
+
def create_visual_placeholder(self, comp_name, category_name, error_msg):
|
|
5735
|
+
"""Cria um placeholder visual para componentes com erro"""
|
|
5736
|
+
return f'''
|
|
5737
|
+
<div style="
|
|
5738
|
+
padding: 2rem;
|
|
5739
|
+
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
|
|
5740
|
+
border: 2px dashed #dc2626;
|
|
5741
|
+
border-radius: 12px;
|
|
5742
|
+
text-align: center;
|
|
5743
|
+
color: #7f1d1d;
|
|
5744
|
+
margin: 1rem 0;
|
|
5745
|
+
box-shadow: 0 4px 8px rgba(220, 38, 38, 0.1);
|
|
5746
|
+
">
|
|
5747
|
+
<div style="font-size: 2rem; margin-bottom: 0.5rem;">⚠️</div>
|
|
5748
|
+
<h3 style="margin: 0 0 0.5rem 0; color: #dc2626; font-size: 1.25rem;">{comp_name}</h3>
|
|
5749
|
+
<p style="margin: 0 0 0.5rem 0; font-size: 0.875rem;">Componente não pôde ser renderizado</p>
|
|
5750
|
+
<small style="color: #991b1b; display: block;">Categoria: {category_name}</small>
|
|
5751
|
+
{f'<details style="margin-top: 1rem;"><summary style="cursor: pointer;">Ver erro técnico</summary><div style="margin-top: 0.5rem; font-family: monospace; font-size: 0.75rem; text-align: left; background: rgba(0,0,0,0.1); padding: 0.5rem; border-radius: 4px;">{error_msg}</div></details>' if self.debug_mode else ''}
|
|
5752
|
+
</div>
|
|
5753
|
+
'''
|
|
5754
|
+
|
|
5755
|
+
def get_component_display_name(self, block, comp_name):
|
|
5756
|
+
"""Nome de exibição limpo do componente"""
|
|
5757
|
+
if hasattr(block, 'label') and block.label:
|
|
5758
|
+
label = block.label
|
|
5759
|
+
# Remove emojis do início
|
|
5760
|
+
emoji_prefixes = ['🎯', '🎨', '🏢', '🚀', '🔍', '📑', '🖼️', '⭐', '🎬', '📋', '⚡', '📞', '👂']
|
|
5761
|
+
for emoji in emoji_prefixes:
|
|
5762
|
+
if label.startswith(emoji):
|
|
5763
|
+
parts = label.split(' ', 1)
|
|
5764
|
+
if len(parts) > 1:
|
|
5765
|
+
return parts[1]
|
|
5766
|
+
break
|
|
5767
|
+
return label
|
|
5768
|
+
|
|
5769
|
+
# Formatar nome da classe
|
|
5770
|
+
class_name = block.__class__.__name__
|
|
5771
|
+
if class_name.endswith('Block'):
|
|
5772
|
+
class_name = class_name[:-5]
|
|
5257
5773
|
|
|
5258
|
-
return
|
|
5774
|
+
return class_name.replace('_', ' ').title()
|
|
5775
|
+
|
|
5776
|
+
def format_category_name(self, category_name):
|
|
5777
|
+
"""Formata nome da categoria"""
|
|
5778
|
+
category_names = {
|
|
5779
|
+
'banners': 'Banners e Heroes',
|
|
5780
|
+
'galerias': 'Galerias e Imagens',
|
|
5781
|
+
'carousels': 'Carrosséis',
|
|
5782
|
+
'dashboards': 'Dashboards e Métricas',
|
|
5783
|
+
'formularios': 'Formulários',
|
|
5784
|
+
'cursos': 'Cursos e Educação',
|
|
5785
|
+
'eventos': 'Eventos',
|
|
5786
|
+
'navegacao': 'Navegação',
|
|
5787
|
+
'menus': 'Menus',
|
|
5788
|
+
'botoes': 'Botões e CTAs',
|
|
5789
|
+
'conteudo': 'Conteúdo e Texto',
|
|
5790
|
+
'secoes': 'Seções e Containers',
|
|
5791
|
+
'cards': 'Cards',
|
|
5792
|
+
'interativos': 'Componentes Interativos',
|
|
5793
|
+
'midia': 'Mídia e Vídeos',
|
|
5794
|
+
'especialidades': 'Componentes Especializados',
|
|
5795
|
+
}
|
|
5796
|
+
|
|
5797
|
+
return category_names.get(category_name, category_name.replace('_', ' ').title())
|
|
5798
|
+
|
|
5799
|
+
def get_category_icon(self, category_name):
|
|
5800
|
+
"""Ícone da categoria"""
|
|
5801
|
+
icons = {
|
|
5802
|
+
'banners': 'image',
|
|
5803
|
+
'galerias': 'images',
|
|
5804
|
+
'carousels': 'arrows-up-down',
|
|
5805
|
+
'dashboards': 'chart-bar',
|
|
5806
|
+
'formularios': 'edit',
|
|
5807
|
+
'cursos': 'graduation-cap',
|
|
5808
|
+
'eventos': 'calendar',
|
|
5809
|
+
'navegacao': 'bars',
|
|
5810
|
+
'menus': 'list',
|
|
5811
|
+
'botoes': 'mouse-pointer',
|
|
5812
|
+
'conteudo': 'file-text',
|
|
5813
|
+
'secoes': 'th-large',
|
|
5814
|
+
'cards': 'clone',
|
|
5815
|
+
'interativos': 'cogs',
|
|
5816
|
+
'midia': 'play-circle',
|
|
5817
|
+
'especialidades': 'puzzle-piece',
|
|
5818
|
+
}
|
|
5819
|
+
return icons.get(category_name, 'cube')
|
|
5820
|
+
|
|
5821
|
+
def get_category_description(self, category_name):
|
|
5822
|
+
"""Descrição da categoria"""
|
|
5823
|
+
descriptions = {
|
|
5824
|
+
'banners': 'Componentes para seções de destaque, heroes e banners promocionais',
|
|
5825
|
+
'galerias': 'Componentes para exibição de imagens, galerias e portfolios visuais',
|
|
5826
|
+
'carousels': 'Componentes de carrosséis, sliders e apresentações rotativas',
|
|
5827
|
+
'dashboards': 'Componentes para dashboards, KPIs, gráficos e visualização de dados',
|
|
5828
|
+
'formularios': 'Componentes de formulários, campos de entrada e validação',
|
|
5829
|
+
'cursos': 'Componentes específicos para cursos, educação e capacitação online',
|
|
5830
|
+
'eventos': 'Componentes para eventos, cronogramas e calendários',
|
|
5831
|
+
'navegacao': 'Componentes de navegação, menus e estruturas de site',
|
|
5832
|
+
'menus': 'Componentes específicos de menu e navegação secundária',
|
|
5833
|
+
'botoes': 'Componentes de botões, call-to-actions e elementos clicáveis',
|
|
5834
|
+
'conteudo': 'Componentes de conteúdo, texto rico, citações e artigos',
|
|
5835
|
+
'secoes': 'Componentes de seções, containers e estruturas de layout',
|
|
5836
|
+
'cards': 'Componentes de cards, grids e elementos organizacionais',
|
|
5837
|
+
'interativos': 'Componentes interativos, acordeões, modais e elementos dinâmicos',
|
|
5838
|
+
'midia': 'Componentes de vídeo, áudio, podcasts e conteúdo multimídia',
|
|
5839
|
+
'especialidades': 'Componentes especializados e funcionalidades específicas da ENAP',
|
|
5840
|
+
}
|
|
5841
|
+
return descriptions.get(category_name, f'Componentes da categoria {category_name}')
|