Skip to content

Commit

Permalink
Lazy render OperatorSelect options to improve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
elsmr committed Dec 11, 2023
1 parent c494411 commit a08dea9
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const emit = defineEmits<{
(event: 'remove'): void;
}>();
const i18n = useI18n();
const condition = ref<FilterConditionValue>(props.condition);
const operatorId = computed<FilterOperatorId>(() => {
Expand Down Expand Up @@ -125,7 +127,7 @@ const rightParameter = computed<INodeProperties>(() => ({
placeholder:
operator.value.type === 'dateTime'
? now.value
: i18n.baseText(i18n.baseText('filter.condition.placeholderRight')),
: i18n.baseText('filter.condition.placeholderRight'),
type: operatorTypeToNodePropType(operator.value.rightType ?? operator.value.type),
}));
Expand All @@ -138,6 +140,8 @@ const onRightValueChange = (update: IUpdateInformation): void => {
};
const convertToType = (value: unknown, type: FilterOperatorType): unknown => {
if (type === 'any') return value;
return (
validateFieldType('filter', condition.value.leftValue, type, { parseStrings: true }).newValue ??
value
Expand Down Expand Up @@ -175,8 +179,6 @@ const onRemove = (): void => {
const onBlur = (): void => {
emit('update', condition.value);
};
const i18n = useI18n();
</script>

<template>
Expand Down
103 changes: 56 additions & 47 deletions packages/editor-ui/src/components/FilterConditions/OperatorSelect.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useI18n } from '@/composables/useI18n';
import { OPERATOR_GROUPS } from './constants';
import { OPERATORS_BY_ID, OPERATOR_GROUPS } from './constants';
import { computed, ref } from 'vue';
import type { FilterOperator } from './types';
Expand All @@ -12,6 +12,7 @@ const props = defineProps<Props>();
const selected = ref(props.selected);
const menuOpen = ref(false);
const shouldRenderItems = ref(false);
const submenu = ref('none');
const emit = defineEmits<{
Expand All @@ -22,15 +23,17 @@ const i18n = useI18n();
const groups = OPERATOR_GROUPS;
const selectedGroupIcon = computed(
() => groups.find((group) => group.id === selected.value.split(':')[0])?.icon,
);
const selectedOperator = computed(() => OPERATORS_BY_ID[selected.value] as FilterOperator);
const onOperatorChange = (operator: string): void => {
selected.value = operator;
emit('operatorChange', operator);
};
const selectedGroupIcon = computed(
() => groups.find((group) => group.id === selected.value.split(':')[0])?.icon,
);
const getOperatorId = (operator: FilterOperator): string =>
`${operator.type}:${operator.operation}`;
Expand All @@ -49,55 +52,61 @@ function onGroupSelect(group: string) {
</script>

<template>
<div>
<n8n-select
data-test-id="filter-operator-select"
size="small"
:key="selectedGroupIcon"
:modelValue="selected"
@update:modelValue="onOperatorChange"
@visible-change="onSelectVisibleChange"
>
<template v-if="selectedGroupIcon" #prefix>
<n8n-icon
:class="$style.selectedGroupIcon"
:icon="selectedGroupIcon"
color="text-light"
size="small"
/>
</template>
<div :class="$style.groups">
<div :key="group.name" v-for="group of groups">
<n8n-popover
:visible="submenu === group.id"
placement="right-start"
:show-arrow="false"
:offset="2"
:popper-style="{ padding: 'var(--spacing-3xs) 0' }"
width="auto"
>
<template #reference>
<div
v-if="group.children.length > 0"
@mouseenter="() => onGroupSelect(group.id)"
@click="() => onGroupSelect(group.id)"
:class="$style.groupTitle"
>
<n8n-icon v-if="group.icon" :icon="group.icon" color="text-light" size="small" />
<span>{{ i18n.baseText(group.name) }}</span>
</div>
</template>
<n8n-select
data-test-id="filter-operator-select"
size="small"
:key="selectedGroupIcon"
:modelValue="selected"
@update:modelValue="onOperatorChange"
@visible-change="onSelectVisibleChange"
@mouseenter="shouldRenderItems = true"
>
<template v-if="selectedGroupIcon" #prefix>
<n8n-icon
:class="$style.selectedGroupIcon"
:icon="selectedGroupIcon"
color="text-light"
size="small"
/>
</template>
<div :class="$style.groups" v-if="shouldRenderItems">
<div :key="group.name" v-for="group of groups">
<n8n-popover
:visible="submenu === group.id"
placement="right-start"
:show-arrow="false"
:offset="2"
:popper-style="{ padding: 'var(--spacing-3xs) 0' }"
width="auto"
>
<template #reference>
<div
@mouseenter="() => onGroupSelect(group.id)"
@click="() => onGroupSelect(group.id)"
:class="$style.groupTitle"
>
<n8n-icon v-if="group.icon" :icon="group.icon" color="text-light" size="small" />
<span>{{ i18n.baseText(group.name) }}</span>
</div>
</template>
<div>
<n8n-option
v-for="operator in group.children"
:key="getOperatorId(operator)"
:value="getOperatorId(operator)"
:label="i18n.baseText(operator.name)"
/>
</n8n-popover>
</div>
</div>
</n8n-popover>
</div>
</n8n-select>
</div>
</div>
<n8n-option
v-else
:key="selected"
:value="selected"
:label="i18n.baseText(selectedOperator.name)"
/>
</n8n-select>
</template>

<style lang="scss" module>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,6 @@ export const DEFAULT_OPERATOR_VALUE: FilterConditionValue['operator'] =
OPERATORS_BY_ID['string:equals'];

export const OPERATOR_GROUPS: FilterOperatorGroup[] = [
{
id: 'any',
name: 'filter.operatorGroup.basic',
children: OPERATORS.filter((operator) => operator.type === 'any'),
},
{
id: 'string',
name: 'filter.operatorGroup.string',
Expand Down

0 comments on commit a08dea9

Please sign in to comment.