• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

teableio / teable / 8387093605

22 Mar 2024 07:48AM CUT coverage: 28.027% (-0.2%) from 28.222%
8387093605

Pull #484

github

web-flow
Merge 174ef76f7 into a06c6afb1
Pull Request #484: feat: support increment import

2099 of 3218 branches covered (65.23%)

24 of 703 new or added lines in 18 files covered. (3.41%)

49 existing lines in 6 files now uncovered.

25815 of 92109 relevant lines covered (28.03%)

5.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.45
/packages/sdk/src/components/filter/component/base/BaseSingleSelect.tsx
1
import {
1✔
2
  Button,
1✔
3
  Command,
1✔
4
  CommandEmpty,
1✔
5
  CommandInput,
1✔
6
  CommandItem,
1✔
7
  Popover,
1✔
8
  PopoverContent,
1✔
9
  PopoverTrigger,
1✔
10
  CommandList,
1✔
11
} from '@teable/ui-lib';
1✔
12
import classNames from 'classnames';
1✔
13
import { Check, ChevronsUpDown } from 'lucide-react';
1✔
14
import { useState, useMemo, useEffect, useCallback } from 'react';
1✔
15
import { useTranslation } from '../../../../context/app/i18n';
1✔
16
import type { IOption, IBaseSelect } from './types';
1✔
17

1✔
18
function BaseSingleSelect<V extends string, O extends IOption<V> = IOption<V>>(
14✔
19
  props: IBaseSelect<V, O>
14✔
20
) {
14✔
21
  const { t } = useTranslation();
14✔
22
  const {
14✔
23
    onSelect,
14✔
24
    value,
14✔
25
    options,
14✔
26
    className,
14✔
27
    popoverClassName,
14✔
28
    disabled = false,
14✔
29
    optionRender,
14✔
30
    notFoundText = t('common.search.empty'),
14✔
31
    displayRender,
14✔
32
    search = true,
14✔
33
    placeholder = t('common.search.placeholder'),
14✔
34
  } = props;
14✔
35
  const [open, setOpen] = useState(false);
14✔
36

14✔
37
  const label = useMemo(() => {
14✔
38
    return options.find((option) => option.value === value)?.label || t('common.untitled');
7✔
39
  }, [options, t, value]);
14✔
40

14✔
41
  useEffect(() => {
14✔
42
    // other type value comes, adapter or reset
7✔
43
    const isNull = value === null;
7✔
44
    const isSameType = typeof value === 'string';
7✔
45
    const isInOption = options.findIndex((option) => option.value === value) > -1;
7✔
46
    if ((!isNull && !isSameType) || (!isInOption && options.length && !isNull)) {
7✔
UNCOV
47
      onSelect?.(null);
×
UNCOV
48
    }
×
49
  }, [onSelect, value, options]);
14✔
50

14✔
51
  const selectedValue = useMemo(() => {
14✔
52
    return options.find((option) => option.value === value);
7✔
53
  }, [options, value]);
14✔
54

14✔
55
  const optionMap = useMemo(() => {
14✔
56
    const map: Record<string, string> = {};
6✔
57
    options.forEach((option) => {
6✔
58
      const key = option.value;
12✔
59
      const value = option.label;
12✔
60
      map[key] = value;
12✔
61
    });
12✔
62
    return map;
6✔
63
  }, [options]);
14✔
64

14✔
65
  const commandFilter = useCallback(
14✔
66
    (id: string, searchValue: string) => {
14✔
67
      console.log('optionMap[id]', optionMap[id]);
12✔
68
      const name = optionMap[id]?.toLowerCase() || t('common.untitled');
12!
69
      const containWord = name.indexOf(searchValue?.toLowerCase()) > -1;
12✔
70
      return Number(containWord);
12✔
71
    },
12✔
72
    [optionMap, t]
14✔
73
  );
14✔
74

14✔
75
  return (
14✔
76
    <Popover open={open} onOpenChange={setOpen} modal={true}>
14✔
77
      <PopoverTrigger asChild>
14✔
78
        <Button
14✔
79
          variant="outline"
14✔
80
          role="combobox"
14✔
81
          aria-expanded={open}
14✔
82
          disabled={disabled}
14✔
83
          size="sm"
14✔
84
          className={classNames('justify-between m-1 truncate overflow-hidden', className)}
14✔
85
        >
14✔
86
          {value
14✔
87
            ? (selectedValue && displayRender?.(selectedValue)) ?? (
2!
88
                <span className="truncate">{label}</span>
2✔
89
              )
2✔
90
            : 'Select'}
2✔
91
          <ChevronsUpDown className="ml-2 size-4 shrink-0 opacity-50" />
14✔
92
        </Button>
14✔
93
      </PopoverTrigger>
14✔
94
      <PopoverContent className={classNames('p-1', popoverClassName)}>
14✔
95
        <Command filter={commandFilter}>
14✔
96
          {search ? (
14✔
97
            <CommandInput placeholder={placeholder} className="placeholder:text-[13px]" />
14✔
98
          ) : null}
14!
99
          <CommandEmpty>{notFoundText}</CommandEmpty>
14✔
100
          <CommandList>
14✔
101
            {options?.map((option) => (
14✔
102
              <CommandItem
14✔
103
                key={option.value}
14✔
104
                value={option.value}
14✔
105
                onSelect={() => {
14✔
106
                  onSelect(option.value);
2✔
107
                  setOpen(false);
2✔
108
                }}
2✔
109
                className="truncate text-[13px]"
14✔
110
              >
14✔
111
                <Check
14✔
112
                  className={classNames(
14✔
113
                    'mr-2 h-4 w-4 shrink-0',
14✔
114
                    value === option.value ? 'opacity-100' : 'opacity-0'
14✔
115
                  )}
14✔
116
                />
14✔
117
                {optionRender?.(option) ?? option.label ?? t('common.untitled')}
14!
118
              </CommandItem>
14✔
119
            ))}
14✔
120
          </CommandList>
14✔
121
        </Command>
14✔
122
      </PopoverContent>
14✔
123
    </Popover>
14✔
124
  );
14✔
125
}
14✔
126

1✔
127
BaseSingleSelect.displayName = 'BaseSingleSelect';
1✔
128

1✔
129
export { BaseSingleSelect };
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc