fix(ui): reemplaza panel-debajo-del-listado por DetailPopup de tamaño fijo
El detalle de un item de listado (actividad, departamento, usuario, proyecto nuevo, catalogo) ya no se apila debajo ni al costado del listado: ahora abre en un popup que cubre la ventana, deja el listado inactivo detras, nunca se cierra con clic afuera (solo con el boton Cerrar o una accion explicita del formulario) y mantiene un alto FIJO por instancia para que cambiar de pestaña interna (Info/Subtareas/Dependencias/Comentarios/ Documentos) no reajuste su tamaño. De paso corrige un bug real de stacking: ContentDialog no usaba portal a document.body, así que un dialogo de confirmacion abierto desde dentro de un DetailPopup quedaba oculto detras de este. Ahora ambos son portales con una jerarquia de z-index explicita (Flyout 100 < DetailPopup 200 < ContentDialog 250 < Toast 300). En el detalle de actividad, Subtareas y Dependencias pasan de estar apiladas dentro de la pestaña Info a ser cada una su propia pestaña. Regla documentada en project-md-templates/UI-UX-WINDOWS.md (componente DetailPopup) para que aplique a futuros proyectos de escritorio Windows del grupo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,7 @@ function toForm(a) {
|
||||
};
|
||||
}
|
||||
|
||||
export default function ActivityDetailPanel({ activity, projectId, siblingActivities, onChanged, onClose }) {
|
||||
export default function ActivityDetailPanel({ activity, projectId, siblingActivities, onChanged }) {
|
||||
const { t, pushToast } = useUi();
|
||||
const runAction = useAction();
|
||||
const { data: priorities } = useAsync(() => listCatalog('priorities'), []);
|
||||
@@ -84,15 +84,12 @@ export default function ActivityDetailPanel({ activity, projectId, siblingActivi
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="panel-card">
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
|
||||
<h3 style={{ margin: 0 }}>{activity.code} — {activity.name}</h3>
|
||||
<Button variant="subtle" icon={X} onClick={onClose}>{t('common_close')}</Button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Tabs
|
||||
tabs={[
|
||||
{ key: 'detail', label: t('tab_info') },
|
||||
{ key: 'subtasks', label: t('subtasks_title') },
|
||||
{ key: 'dependencies', label: t('activity_dependencies') },
|
||||
{ key: 'comments', label: t('tab_comments') },
|
||||
{ key: 'documents', label: t('tab_documents') },
|
||||
]}
|
||||
@@ -128,7 +125,6 @@ export default function ActivityDetailPanel({ activity, projectId, siblingActivi
|
||||
</FieldRow>
|
||||
<Field label={t('activity_progress')}>
|
||||
<ProgressBar value={Number(activity.progress_pct)} />
|
||||
{hasSubtasks && <span className="text-muted" style={{ fontSize: '.68rem' }}>{t('subtasks_title')}</span>}
|
||||
</Field>
|
||||
</div>
|
||||
) : (
|
||||
@@ -179,38 +175,41 @@ export default function ActivityDetailPanel({ activity, projectId, siblingActivi
|
||||
</FieldRow>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<h4>{t('subtasks_title')}</h4>
|
||||
{(subtasks || []).map((s) => (
|
||||
<div key={s.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0' }}>
|
||||
<input type="checkbox" checked={!!s.is_done} onChange={() => toggleSubtask(s)} />
|
||||
<span style={{ flex: 1, fontSize: '.8rem', textDecoration: s.is_done ? 'line-through' : 'none', opacity: s.is_done ? .6 : 1 }}>{s.name}</span>
|
||||
<button className="icon-btn" onClick={() => removeSubtaskItem(s)}><Trash2 size={15} /></button>
|
||||
</div>
|
||||
))}
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<input className="input" value={newSubtask} placeholder={t('subtask_new')} onChange={(e) => setNewSubtask(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && addSubtaskItem()} />
|
||||
<Button variant="standard" icon={Plus} onClick={addSubtaskItem}>{t('common_new')}</Button>
|
||||
{tab === 'subtasks' && (
|
||||
<div>
|
||||
{(subtasks || []).map((s) => (
|
||||
<div key={s.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0' }}>
|
||||
<input type="checkbox" checked={!!s.is_done} onChange={() => toggleSubtask(s)} />
|
||||
<span style={{ flex: 1, fontSize: '.8rem', textDecoration: s.is_done ? 'line-through' : 'none', opacity: s.is_done ? .6 : 1 }}>{s.name}</span>
|
||||
<button className="icon-btn" onClick={() => removeSubtaskItem(s)}><Trash2 size={15} /></button>
|
||||
</div>
|
||||
))}
|
||||
{(!subtasks || subtasks.length === 0) && <div className="text-muted" style={{ fontSize: '.78rem' }}>{t('common_empty')}</div>}
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<input className="input" value={newSubtask} placeholder={t('subtask_new')} onChange={(e) => setNewSubtask(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && addSubtaskItem()} />
|
||||
<Button variant="standard" icon={Plus} onClick={addSubtaskItem}>{t('common_new')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<h4>{t('activity_dependencies')}</h4>
|
||||
{(activity.dependencies || []).length === 0 && <div className="text-muted" style={{ fontSize: '.78rem' }}>{t('common_empty')}</div>}
|
||||
{(activity.dependencies || []).map((d) => (
|
||||
<div key={d.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0' }}>
|
||||
<Link2 size={14} style={{ opacity: .6 }} />
|
||||
<span style={{ flex: 1, fontSize: '.8rem' }}>{d.code} — {d.name}</span>
|
||||
<button className="icon-btn" onClick={() => removeDep(d.id)}><Trash2 size={15} /></button>
|
||||
</div>
|
||||
))}
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<ComboBox options={depOptions} value={addingDep} onChange={setAddingDep} placeholder={t('activity_depends_on')} />
|
||||
</div>
|
||||
<Button variant="standard" icon={Plus} onClick={addDep}>{t('activity_add_dependency')}</Button>
|
||||
{tab === 'dependencies' && (
|
||||
<div>
|
||||
{(activity.dependencies || []).length === 0 && <div className="text-muted" style={{ fontSize: '.78rem' }}>{t('common_empty')}</div>}
|
||||
{(activity.dependencies || []).map((d) => (
|
||||
<div key={d.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0' }}>
|
||||
<Link2 size={14} style={{ opacity: .6 }} />
|
||||
<span style={{ flex: 1, fontSize: '.8rem' }}>{d.code} — {d.name}</span>
|
||||
<button className="icon-btn" onClick={() => removeDep(d.id)}><Trash2 size={15} /></button>
|
||||
</div>
|
||||
))}
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<ComboBox options={depOptions} value={addingDep} onChange={setAddingDep} placeholder={t('activity_depends_on')} />
|
||||
</div>
|
||||
<Button variant="standard" icon={Plus} onClick={addDep}>{t('activity_add_dependency')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user