Editor screens opening multiple tabs

When opening an editor screen that is already open, it opens a new tab instead of directing to the already open tab. For example, opening a customer, going back to the customer list and opening the same customer editor would result in 2 tabs.

Hello!

This is a standard behavior of screens. But you can close opened screen manually, see:

Where would we put this? The issue happens across all of our screens, we are not using breadcrumbs.

Before opening an editor screen. For instance, we can subscribe to ActionPerformedEvent and close opened screen before showing a new one.

<groupTable id="ordersTable"
            ...>
    <actions>
        <action id="create" type="create"/>
        <action id="edit" type="edit"/>
        <action id="remove" type="remove"/>
    </actions>
    ...
</groupTable>
Screen controller code
@Autowired
private ScreenBuilders screenBuilders;
@Autowired
private GroupTable<Order> ordersTable;
@Autowired
private Screens screens;
@Autowired
private WindowConfig windowConfig;
@Autowired
private Metadata metadata;

@Subscribe("ordersTable.edit")
public void onOrdersTableEdit(Action.ActionPerformedEvent event) {
    MetaClass metaClass = metadata.getClass(Order.class);
    closeScreen(windowConfig.getEditorScreenId(metaClass));

    screenBuilders.editor(ordersTable)
            .withOpenMode(OpenMode.NEW_TAB)
            .show();
}

protected void closeScreen(String screenId) {
    Collection<Screens.WindowStack> windowStacks = screens.getOpenedScreens().getWorkAreaStacks();
    for (Screens.WindowStack windowStack : windowStacks) {
        Collection<Screen> screens = windowStack.getBreadcrumbs();
        for (Screen screen : screens) {
            if (screenId.equals(screen.getId())) {
                screen.close(StandardOutcome.CLOSE);
                return;
            }
        }
    }
}

To avoid duplication code in every browse screen, you can extend Create and Edit actions and close opened screen before action execution. These actions will be available in the screen descriptor. For instance, custom edit action:

Custom EditAction
@StudioAction(
        target = "io.jmix.ui.component.ListComponent",
        description = "Edits an entity instance using its editor screen",
        availableInScreenWizard = true)
@ActionType(AppEditAction.ID)
public class AppEditAction<E> extends EditAction<E> {

    public static final String ID = "app_edit";

    @Autowired
    private WindowConfig windowConfig;
    @Autowired
    private Metadata metadata;

    public AppEditAction() {
        super(ID);
    }

    public AppEditAction(String id) {
        super(id);
    }

    @Override
    public void execute() {
        if (target == null) {
            throw new IllegalStateException("EditAction target is not set");
        }

        if (!(target.getItems() instanceof EntityDataUnit)) {
            throw new IllegalStateException("EditAction target dataSource is null or does not implement EntityDataUnit");
        }

        String screenId = windowConfig.getEditorScreenId(metadata.getClass(Order.class));
        closeScreen(screenId);

        super.execute();
    }

    protected void closeScreen(String screenId) {
        Frame frame = target.getFrame();
        if (frame == null) {
            throw new IllegalStateException("Component is not attached to the frame");
        }
        Screens screens = UiControllerUtils.getScreenContext(frame.getFrameOwner()).getScreens();
        Collection<Screens.WindowStack> windowStacks = screens.getOpenedScreens().getWorkAreaStacks();

        for (Screens.WindowStack windowStack : windowStacks) {
            Collection<Screen> windowStackScreens = windowStack.getBreadcrumbs();
            for (Screen screen : windowStackScreens) {
                if (screenId.equals(screen.getId())) {
                    screen.close(StandardOutcome.CLOSE);
                    return;
                }
            }
        }
    }
}

And XML descriptor:

<groupTable id="ordersTable"
            ...>
    <actions>
        <action id="create" type="create"/>
        <action id="edit" type="app_edit">
            <properties>
                <property name="openMode" value="NEW_TAB"/>
            </properties>
        </action>
        <action id="remove" type="remove"/>
    </actions>
    ...
</groupTable>