mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Add show all/selected toggle to tree-select (#7161)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-list-group
|
||||
v-if="children"
|
||||
v-show="visibleChildrenValues.length > 0"
|
||||
v-show="groupShown"
|
||||
:value="value"
|
||||
:open="typeof search === 'string' && search.length > 0"
|
||||
arrow-placement="before"
|
||||
@@ -32,10 +32,11 @@
|
||||
:value="choice[itemValue]"
|
||||
:children="choice[itemChildren]"
|
||||
:disabled="disabled"
|
||||
:show-selection-only="showSelectionOnly"
|
||||
/>
|
||||
</v-list-group>
|
||||
|
||||
<v-list-item v-else-if="!children && !hidden" class="item">
|
||||
<v-list-item v-else-if="!children" v-show="!hidden" class="item">
|
||||
<v-checkbox v-model="treeValue" :disabled="disabled" :checked="checked" :label="text" :value="value" />
|
||||
</v-list-item>
|
||||
</template>
|
||||
@@ -100,28 +101,57 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showSelectionOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const visibleChildrenValues = computed(() => {
|
||||
if (!props.search) return props.children?.map((child) => child[props.itemValue]);
|
||||
let options = props.children || [];
|
||||
|
||||
return props.children
|
||||
?.filter(
|
||||
if (props.search) {
|
||||
options = options.filter(
|
||||
(child) =>
|
||||
child[props.itemText].toLowerCase().includes(props.search.toLowerCase()) ||
|
||||
childrenHaveMatch(child.children)
|
||||
)
|
||||
?.map((child) => child[props.itemValue]);
|
||||
childrenHaveSearchMatch(child[props.itemChildren])
|
||||
);
|
||||
}
|
||||
|
||||
function childrenHaveMatch(children: Record<string, any>[] | undefined): boolean {
|
||||
if (props.showSelectionOnly) {
|
||||
options = options.filter(
|
||||
(child) =>
|
||||
props.modelValue.includes(child[props.itemValue]) || childrenHaveValueMatch(child[props.itemChildren])
|
||||
);
|
||||
}
|
||||
|
||||
return options.map((child) => child[props.itemValue]);
|
||||
|
||||
function childrenHaveSearchMatch(children: Record<string, any>[] | undefined): boolean {
|
||||
if (!children) return false;
|
||||
return children.some(
|
||||
(child) =>
|
||||
child[props.itemText].toLowerCase().includes(props.search.toLowerCase()) ||
|
||||
childrenHaveMatch(child[props.itemChildren])
|
||||
childrenHaveSearchMatch(child[props.itemChildren])
|
||||
);
|
||||
}
|
||||
|
||||
function childrenHaveValueMatch(children: Record<string, any>[] | undefined): boolean {
|
||||
if (!children) return false;
|
||||
return children.some(
|
||||
(child) =>
|
||||
props.modelValue.includes(child[props.itemValue]) || childrenHaveValueMatch(child[props.itemChildren])
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const groupShown = computed(() => {
|
||||
if (props.showSelectionOnly === true && props.modelValue.includes(props.value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return visibleChildrenValues.value.length > 0;
|
||||
});
|
||||
|
||||
const childrenValues = computed(() => props.children?.map((child) => child[props.itemValue]) || []);
|
||||
@@ -216,6 +246,7 @@ export default defineComponent({
|
||||
treeValue,
|
||||
groupIndeterminateState,
|
||||
visibleChildrenValues,
|
||||
groupShown,
|
||||
};
|
||||
|
||||
function emitAll(rawValue: (string | number)[], { added, removed }: Delta) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
:value="choice[itemValue]"
|
||||
:children="choice[itemChildren]"
|
||||
:disabled="disabled"
|
||||
:show-selection-only="showSelectionOnly"
|
||||
/>
|
||||
</v-list>
|
||||
</template>
|
||||
@@ -57,6 +58,10 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showSelectionOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
|
||||
@@ -18,8 +18,19 @@
|
||||
:disabled="disabled"
|
||||
:choices="choices"
|
||||
:value-combining="valueCombining"
|
||||
:show-selection-only="showSelectionOnly"
|
||||
@update:model-value="$emit('input', $event)"
|
||||
/>
|
||||
|
||||
<div class="footer">
|
||||
<span :class="{ active: showSelectionOnly === false }" @click="showSelectionOnly = false">
|
||||
{{ t('interfaces.select-multiple-checkbox-tree.show_all') }}
|
||||
</span>
|
||||
/
|
||||
<span :class="{ active: showSelectionOnly === true }" @click="showSelectionOnly = true">
|
||||
{{ t('interfaces.select-multiple-checkbox-tree.show_selected') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -58,6 +69,8 @@ export default defineComponent({
|
||||
const { t } = useI18n();
|
||||
const search = ref('');
|
||||
|
||||
const showSelectionOnly = ref(false);
|
||||
|
||||
const setSearchDebounced = debounce((val: string) => {
|
||||
searchDebounced.value = val;
|
||||
}, 250);
|
||||
@@ -66,7 +79,7 @@ export default defineComponent({
|
||||
|
||||
const searchDebounced = ref('');
|
||||
|
||||
return { search, t, searchDebounced };
|
||||
return { search, t, searchDebounced, showSelectionOnly };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -90,4 +103,31 @@ export default defineComponent({
|
||||
.search .v-input {
|
||||
box-shadow: 0 0 4px 4px var(--background-page);
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
float: right;
|
||||
width: max-content;
|
||||
padding: 4px 8px;
|
||||
text-align: right;
|
||||
background-color: var(--background-page);
|
||||
border-top-left-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.footer > span {
|
||||
color: var(--foreground-subdued);
|
||||
cursor: pointer;
|
||||
transition: color var(--fast) var(--transition);
|
||||
}
|
||||
|
||||
.footer > span:hover {
|
||||
color: var(--foreground-normal);
|
||||
}
|
||||
|
||||
.footer > span.active {
|
||||
color: var(--primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -938,6 +938,8 @@ interfaces:
|
||||
description: Choose between multiple options via nested checkboxes
|
||||
value_combining: Value Combining
|
||||
value_combining_note: Controls what value is stored when nested selections are made.
|
||||
show_all: Show All
|
||||
show_selected: Show Selected
|
||||
input-code:
|
||||
code: Code
|
||||
description: Write or share code snippets
|
||||
|
||||
Reference in New Issue
Block a user