mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Fix not being able to close groups (#11437)
* fix not being able to close groups * search top most level checkboxes * Fix casing of file name Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
56
app/src/components/v-checkbox-tree/use-visible-children.ts
Normal file
56
app/src/components/v-checkbox-tree/use-visible-children.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { computed, Ref } from 'vue';
|
||||
|
||||
export function useVisibleChildren(
|
||||
search: Ref<string>,
|
||||
modelValue: Ref<(string | number)[]>,
|
||||
children: Ref<Record<string, any>[]>,
|
||||
showSelectionOnly: Ref<boolean>,
|
||||
itemText: Ref<string>,
|
||||
itemValue: Ref<string>,
|
||||
itemChildren: Ref<string>,
|
||||
parentValue: Ref<string | number>,
|
||||
value: Ref<string | number>
|
||||
) {
|
||||
const visibleChildrenValues = computed(() => {
|
||||
let options = children.value || [];
|
||||
|
||||
if (search.value) {
|
||||
options = options.filter(
|
||||
(child) =>
|
||||
child[itemText.value].toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
childrenHaveSearchMatch(child[itemChildren.value])
|
||||
);
|
||||
}
|
||||
|
||||
if (showSelectionOnly.value) {
|
||||
options = options.filter(
|
||||
(child) =>
|
||||
modelValue.value.includes(child[itemValue.value]) ||
|
||||
childrenHaveValueMatch(child[itemChildren.value]) ||
|
||||
modelValue.value.includes(parentValue.value) ||
|
||||
modelValue.value.includes(value.value)
|
||||
);
|
||||
}
|
||||
|
||||
return options.map((child) => child[itemValue.value]);
|
||||
|
||||
function childrenHaveSearchMatch(children: Record<string, any>[] | undefined): boolean {
|
||||
if (!children) return false;
|
||||
return children.some(
|
||||
(child) =>
|
||||
child[itemText.value].toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
childrenHaveSearchMatch(child[itemChildren.value])
|
||||
);
|
||||
}
|
||||
|
||||
function childrenHaveValueMatch(children: Record<string, any>[] | undefined): boolean {
|
||||
if (!children) return false;
|
||||
return children.some(
|
||||
(child) =>
|
||||
modelValue.value.includes(child[itemValue.value]) || childrenHaveValueMatch(child[itemChildren.value])
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return { visibleChildrenValues };
|
||||
}
|
||||
@@ -41,8 +41,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, PropType } from 'vue';
|
||||
import { defineComponent, computed, PropType, toRefs } from 'vue';
|
||||
import { difference } from 'lodash';
|
||||
import { useVisibleChildren } from './use-visible-children';
|
||||
|
||||
type Delta = {
|
||||
added?: (number | string)[];
|
||||
@@ -111,46 +112,20 @@ export default defineComponent({
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const visibleChildrenValues = computed(() => {
|
||||
let options = props.children || [];
|
||||
const { search, modelValue, children, showSelectionOnly, itemText, itemValue, itemChildren, parentValue, value } =
|
||||
toRefs(props);
|
||||
|
||||
if (props.search) {
|
||||
options = options.filter(
|
||||
(child) =>
|
||||
child[props.itemText].toLowerCase().includes(props.search.toLowerCase()) ||
|
||||
childrenHaveSearchMatch(child[props.itemChildren])
|
||||
);
|
||||
}
|
||||
|
||||
if (props.showSelectionOnly) {
|
||||
options = options.filter(
|
||||
(child) =>
|
||||
props.modelValue.includes(child[props.itemValue]) ||
|
||||
childrenHaveValueMatch(child[props.itemChildren]) ||
|
||||
props.modelValue.includes(props.parentValue) ||
|
||||
props.modelValue.includes(props.value)
|
||||
);
|
||||
}
|
||||
|
||||
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()) ||
|
||||
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 { visibleChildrenValues } = useVisibleChildren(
|
||||
search,
|
||||
modelValue,
|
||||
children,
|
||||
showSelectionOnly,
|
||||
itemText,
|
||||
itemValue,
|
||||
itemChildren,
|
||||
parentValue,
|
||||
value
|
||||
);
|
||||
|
||||
const groupShown = computed(() => {
|
||||
if (props.showSelectionOnly === true && props.modelValue.includes(props.value)) {
|
||||
@@ -165,7 +140,7 @@ export default defineComponent({
|
||||
return visibleChildrenValues.value.length > 0;
|
||||
}
|
||||
|
||||
return typeof props.search === 'string' && props.search.length > 0;
|
||||
return false;
|
||||
});
|
||||
|
||||
const childrenValues = computed(() => props.children?.map((child) => child[props.itemValue]) || []);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
:item-value="itemValue"
|
||||
:item-children="itemChildren"
|
||||
:text="choice[itemText]"
|
||||
:hidden="visibleChildrenValues.includes(choice[itemValue]) === false"
|
||||
:value="choice[itemValue]"
|
||||
:children="choice[itemChildren]"
|
||||
:disabled="disabled"
|
||||
@@ -19,7 +20,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, ref, defineComponent, PropType } from 'vue';
|
||||
import { computed, ref, defineComponent, PropType, watch, toRefs } from 'vue';
|
||||
import { useVisibleChildren } from './use-visible-children';
|
||||
import VCheckboxTreeCheckbox from './v-checkbox-tree-checkbox.vue';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -74,9 +76,54 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
const fakeValue = ref('');
|
||||
const fakeParentValue = ref('');
|
||||
|
||||
const { search, modelValue, showSelectionOnly, itemText, itemValue, itemChildren, choices } = toRefs(props);
|
||||
|
||||
const { visibleChildrenValues } = useVisibleChildren(
|
||||
search,
|
||||
modelValue,
|
||||
choices,
|
||||
showSelectionOnly,
|
||||
itemText,
|
||||
itemValue,
|
||||
itemChildren,
|
||||
fakeParentValue,
|
||||
fakeValue
|
||||
);
|
||||
|
||||
const openSelection = ref<(string | number)[]>([]);
|
||||
|
||||
return { value, openSelection };
|
||||
watch(
|
||||
() => props.search,
|
||||
(newValue) => {
|
||||
if (!newValue) return;
|
||||
|
||||
const selection = new Set([...openSelection.value, ...searchChoices(newValue, props.choices)]);
|
||||
|
||||
openSelection.value = [...selection];
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function searchChoices(text: string, target: Record<string, any>[]) {
|
||||
const selection: string[] = [];
|
||||
|
||||
for (const item of target) {
|
||||
if (item[props.itemText].toLowerCase().includes(text.toLowerCase())) {
|
||||
selection.push(item[props.itemValue]);
|
||||
}
|
||||
|
||||
if (item[props.itemChildren]) {
|
||||
selection.push(...searchChoices(text, item[props.itemChildren]));
|
||||
}
|
||||
}
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
return { value, openSelection, visibleChildrenValues };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user