Expose default option in SingleItemSelector
- Tweak flow framework so that single item selector can be configured with a default item which is then "exposed" automatically so that user can just hit enter. - Fixes #414
This commit is contained in:
@@ -41,6 +41,7 @@ public abstract class BaseSingleItemSelector extends BaseInput<SingleItemSelecto
|
||||
private String resultValue;
|
||||
private ResultMode resultMode;
|
||||
private Map<String, String> selectItems = new HashMap<>();
|
||||
private String defaultSelect;
|
||||
private Comparator<SelectorItem<String>> comparator;
|
||||
private Function<SingleItemSelectorContext<String, SelectorItem<String>>, List<AttributedString>> renderer;
|
||||
private Integer maxItems;
|
||||
@@ -84,6 +85,12 @@ public abstract class BaseSingleItemSelector extends BaseInput<SingleItemSelecto
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleItemSelectorSpec defaultSelect(String name) {
|
||||
this.defaultSelect = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingleItemSelectorSpec sort(Comparator<SelectorItem<String>> comparator) {
|
||||
this.comparator = comparator;
|
||||
@@ -160,6 +167,10 @@ public abstract class BaseSingleItemSelector extends BaseInput<SingleItemSelecto
|
||||
return selectItems;
|
||||
}
|
||||
|
||||
public String getDefaultSelect() {
|
||||
return defaultSelect;
|
||||
}
|
||||
|
||||
public Comparator<SelectorItem<String>> getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@@ -555,8 +555,20 @@ public interface ComponentFlow {
|
||||
List<SelectorItem<String>> selectorItems = input.getSelectItems().entrySet().stream()
|
||||
.map(e -> SelectorItem.of(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// setup possible item for initial expose
|
||||
String defaultSelect = input.getDefaultSelect();
|
||||
Stream<SelectorItem<String>> defaultCheckStream = StringUtils.hasText(defaultSelect)
|
||||
? selectorItems.stream()
|
||||
: Stream.empty();
|
||||
SelectorItem<String> defaultExpose = defaultCheckStream
|
||||
.filter(si -> ObjectUtils.nullSafeEquals(defaultSelect, si.getName()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
SingleItemSelector<String, SelectorItem<String>> selector = new SingleItemSelector<>(terminal,
|
||||
selectorItems, input.getName(), input.getComparator());
|
||||
selector.setDefaultExpose(defaultExpose);
|
||||
Function<ComponentContext<?>, ComponentContext<?>> operation = (context) -> {
|
||||
if (input.getResultMode() == ResultMode.ACCEPT && input.isStoreResult()
|
||||
&& StringUtils.hasText(input.getResultValue())) {
|
||||
|
||||
@@ -76,6 +76,14 @@ public interface SingleItemSelectorSpec extends BaseInputSpec<SingleItemSelector
|
||||
*/
|
||||
SingleItemSelectorSpec selectItems(Map<String, String> selectItems);
|
||||
|
||||
/**
|
||||
* Automatically selects and exposes a given item.
|
||||
*
|
||||
* @param name the name
|
||||
* @return a builder
|
||||
*/
|
||||
SingleItemSelectorSpec defaultSelect(String name);
|
||||
|
||||
/**
|
||||
* Sets a {@link Comparator} for sorting items.
|
||||
*
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.shell.component.context.BaseComponentContext;
|
||||
import org.springframework.shell.component.context.ComponentContext;
|
||||
import org.springframework.shell.component.support.AbstractSelectorComponent.SelectorComponentContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.jline.keymap.KeyMap.ctrl;
|
||||
@@ -54,6 +55,8 @@ public abstract class AbstractSelectorComponent<T, C extends SelectorComponentCo
|
||||
private boolean stale = false;
|
||||
private AtomicInteger start = new AtomicInteger(0);
|
||||
private AtomicInteger pos = new AtomicInteger(0);
|
||||
private I defaultExpose;
|
||||
private boolean expose = false;
|
||||
|
||||
public AbstractSelectorComponent(Terminal terminal, String name, List<I> items, boolean exitSelects,
|
||||
Comparator<I> comparator) {
|
||||
@@ -95,6 +98,18 @@ public abstract class AbstractSelectorComponent<T, C extends SelectorComponentCo
|
||||
return itemMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default expose item when component start.
|
||||
*
|
||||
* @param defaultExpose the default item
|
||||
*/
|
||||
public void setDefaultExpose(I defaultExpose) {
|
||||
this.defaultExpose = defaultExpose;
|
||||
if (defaultExpose != null) {
|
||||
expose = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets items.
|
||||
*
|
||||
@@ -120,6 +135,7 @@ public abstract class AbstractSelectorComponent<T, C extends SelectorComponentCo
|
||||
@Override
|
||||
protected C runInternal(C context) {
|
||||
C thisContext = getThisContext(context);
|
||||
initialExpose(thisContext);
|
||||
ItemStateViewProjection buildItemStateView = buildItemStateView(start.get(), thisContext);
|
||||
List<ItemState<I>> itemStateView = buildItemStateView.items;
|
||||
thisContext.setItemStateView(itemStateView);
|
||||
@@ -224,6 +240,33 @@ public abstract class AbstractSelectorComponent<T, C extends SelectorComponentCo
|
||||
return false;
|
||||
}
|
||||
|
||||
private void initialExpose(C context) {
|
||||
if (!expose) {
|
||||
return;
|
||||
}
|
||||
expose = false;
|
||||
List<ItemState<I>> itemStates = context.getItemStates();
|
||||
if (itemStates == null) {
|
||||
AtomicInteger index = new AtomicInteger(0);
|
||||
itemStates = context.getItems().stream()
|
||||
.sorted(comparator)
|
||||
.map(item -> ItemState.of(item, item.getName(), index.getAndIncrement(), item.isEnabled()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
for (int i = 0; i < itemStates.size(); i++) {
|
||||
if (ObjectUtils.nullSafeEquals(itemStates.get(i).getName(), defaultExpose.getName())) {
|
||||
if (i < maxItems) {
|
||||
this.pos.set(i);
|
||||
}
|
||||
else {
|
||||
this.pos.set(maxItems - 1);
|
||||
this.start.set(i - maxItems + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStateViewProjection buildItemStateView(int skip, SelectorComponentContext<T, I, ?> context) {
|
||||
List<ItemState<I>> itemStates = context.getItemStates();
|
||||
if (itemStates == null) {
|
||||
|
||||
Reference in New Issue
Block a user