mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-28 08:49:38 +02:00
feat(cli): enforce required database selection and improve tree-picker UX (#86)
* feat(cli): enforce required database selection and improve tree-picker UX - Require at least one database driver via prompt `required: true` instead of looping on empty selection; remove the now-dead retry/back-on-empty branch. - Surface the recommended option with a "(recommended)" hint in the depth and query-history prompts. - Tree picker: add `◧` partial glyph for parents whose descendants are checked, and make `a` toggle select-all-visible / select-none. * fix(cli): drop unused export from tree-picker toggleSelectAllVisible Knip flagged the export as unused; the function is only consumed by the internal reducer via the 'toggle-select-all-visible' command, so demote it to a module-local helper to keep CI's dead-code check green. * test(cli): drop empty-selection warning assertion from setup test The empty-selection retry/warning loop in `chooseDrivers` was removed in favor of `multiselect`'s `required: true`, so the legacy warning string is unreachable. Update the test to assert the simpler back-from-selection return-to-embeddings flow.
This commit is contained in:
parent
e28b10454a
commit
6c4623f2ff
8 changed files with 146 additions and 60 deletions
|
|
@ -44,6 +44,7 @@ export type PickerCommand =
|
|||
| 'collapse-all'
|
||||
| 'toggle-check'
|
||||
| 'select-all-visible'
|
||||
| 'toggle-select-all-visible'
|
||||
| 'select-none'
|
||||
| 'clear-transient-hint'
|
||||
| 'search-start'
|
||||
|
|
@ -228,6 +229,17 @@ export function isAncestorChecked(nodeId: string, checked: Set<string>, byId: Ma
|
|||
return ancestorsOf(nodeId, byId).some((ancestorId) => checked.has(ancestorId));
|
||||
}
|
||||
|
||||
export function hasPartialChildren(
|
||||
nodeId: string,
|
||||
checked: Set<string>,
|
||||
byId: Map<string, TreePickerNode>,
|
||||
): boolean {
|
||||
if (checked.has(nodeId) || isAncestorChecked(nodeId, checked, byId)) {
|
||||
return false;
|
||||
}
|
||||
return descendantsOf(nodeId, byId).some((descendantId) => checked.has(descendantId));
|
||||
}
|
||||
|
||||
function checkedAncestor(nodeId: string, state: PickerState): TreePickerNode | null {
|
||||
for (const ancestorId of ancestorsOf(nodeId, state.byId)) {
|
||||
if (state.checked.has(ancestorId)) {
|
||||
|
|
@ -350,6 +362,16 @@ export function selectNone(state: PickerState): PickerState {
|
|||
return cloneState(state, { checked: new Set(), transientHint: null });
|
||||
}
|
||||
|
||||
function toggleSelectAllVisible(state: PickerState): PickerState {
|
||||
const next = selectAllVisible(state);
|
||||
const unchanged =
|
||||
next.checked.size === state.checked.size && [...next.checked].every((id) => state.checked.has(id));
|
||||
if (unchanged && state.checked.size > 0) {
|
||||
return selectNone(state);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
function setExpanded(state: PickerState, nodeId: string, value: boolean | 'toggle'): PickerState {
|
||||
const expanded = new Set(state.expanded);
|
||||
const nextValue = value === 'toggle' ? !expanded.has(nodeId) : value;
|
||||
|
|
@ -487,6 +509,8 @@ export function reducer(state: PickerState, cmd: PickerCommand, now = Date.now()
|
|||
return { next: toggleChecked(state, state.cursorId, now), effect: null };
|
||||
case 'select-all-visible':
|
||||
return { next: selectAllVisible(state), effect: null };
|
||||
case 'toggle-select-all-visible':
|
||||
return { next: toggleSelectAllVisible(state), effect: null };
|
||||
case 'select-none':
|
||||
return { next: selectNone(state), effect: null };
|
||||
case 'clear-transient-hint':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue