asclass G22CRUDAndDetailPanel { transient settable G22Utils g22utils; transient SimpleCRUD_v2 crud; transient SingleComponentPanel scpDetail; abstract SimpleCRUD_v2 makeCRUD(); abstract JComponent makeDetailView(@NotNull A a); cachedVisualize { crud = makeCRUD(); scpDetail = singleComponentPanel(); var crudVis = crud.visualize(); crud.onSelectionChanged(-> { var selected = crud.selected(); if (selected == null) scpDetail.set(emptyDetailView()); else { var view = makeDetailView(selected); // TODO: change section title when concept changes scpDetail.set(jCenteredRaisedSection(str(selected), view)); } }); ret jvsplit( jCenteredSection(crud.entityNamePlural(), crudVis), scpDetail); } JComponent emptyDetailView() { ret jGazelleLogo(); } void updateCount { crud.update(); } void edit(A A) { crud.setSelected(A); } void setSelected(A A) { crud.setSelected(A); } void selectAfterUpdate(A A) { crud.selectAfterUpdate(A); } }