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

alkem-io / client-web / #8906

24 Sep 2024 10:02AM UTC coverage: 6.028%. First build
#8906

Pull #6938

travis-ci

Pull Request #6938: Templates release v0.72.3

200 of 10087 branches covered (1.98%)

Branch coverage included in aggregate %.

75 of 1034 new or added lines in 76 files covered. (7.25%)

1471 of 17634 relevant lines covered (8.34%)

0.2 hits per line

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

0.0
/src/domain/shared/components/SearchableList/SimpleSearchableTable.tsx
1
import {
2
  FormControl,
3
  IconButton,
4
  InputLabel,
5
  OutlinedInput,
6
  Paper,
7
  Table,
8
  TableBody,
9
  TableCell,
10
  TableContainer,
11
  TableHead,
12
  TableRow,
13
} from '@mui/material';
14
import DeleteOutline from '@mui/icons-material/DeleteOutline';
15
import React, { ReactNode, useMemo, useState } from 'react';
16
import { useTranslation } from 'react-i18next';
17
import RemoveModal from '@/core/ui/dialogs/RemoveModal';
18
import useLazyLoading from '@/domain/shared/pagination/useLazyLoading';
19
import LoadingListItem from './LoadingListItem';
20
import { times } from 'lodash';
21
import { Actions } from '@/core/ui/actions/Actions';
22
import PageContent from '@/core/ui/content/PageContent';
23
import ContributorCardHorizontal from '@/core/ui/card/ContributorCardHorizontal';
24
import { BlockTitle, CardTitle } from '@/core/ui/typography';
25
import RouterLink from '@/core/ui/link/RouterLink';
26

27
export interface SearchableListProps<Item extends SearchableListItem> {
28
  data: Item[] | undefined;
29
  active?: number | string;
30
  onDelete?: (item: Item) => void;
31
  loading: boolean;
32
  fetchMore: () => Promise<void>;
33
  pageSize: number;
34
  firstPageSize?: number;
35
  searchTerm: string;
36
  onSearchTermChange: (searchTerm: string) => void;
37
  totalCount?: number;
38
  hasMore: boolean | undefined;
39
  itemActions?: (item: Item) => ReactNode;
40
}
41

42
export interface SearchableListItem {
43
  id: string;
44
  accountId?: string;
45
  value: string;
46
  url: string;
47
  verified?: boolean;
48
  activeLicensePlanIds?: string[];
49
  avatar?: {
NEW
50
    uri: string;
×
51
  };
×
52
}
53

54
/**
55
 * @deprecated - use AdminSearchableTable instead
56
 */
×
57
const SimpleSearchableList = <Item extends SearchableListItem>({
58
  data = [],
59
  onDelete,
60
  loading,
×
61
  fetchMore,
62
  pageSize,
NEW
63
  firstPageSize = pageSize,
×
NEW
64
  searchTerm,
×
NEW
65
  onSearchTermChange,
×
66
  totalCount,
NEW
67
  hasMore = false,
×
68
  itemActions,
NEW
69
}: SearchableListProps<Item>) => {
×
NEW
70
  const { t } = useTranslation();
×
71
  const [isModalOpened, setModalOpened] = useState<boolean>(false);
72
  const [itemToRemove, setItemToRemove] = useState<SearchableListItem | null>(null);
NEW
73

×
74
  const Loader = useMemo(
75
    () =>
76
      ({ ref }) => (
77
        <>
78
          <LoadingListItem ref={ref} />
79
          {times(pageSize - 1, i => (
NEW
80
            <LoadingListItem key={`__loading_${i}`} />
×
81
          ))}
82
        </>
83
      ),
84
    [pageSize]
85
  );
NEW
86

×
NEW
87
  const loader = useLazyLoading(Loader, {
×
NEW
88
    hasMore,
×
89
    loading,
90
    fetchMore,
NEW
91
  });
×
NEW
92

×
NEW
93
  const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
×
NEW
94
    const value = e.target.value;
×
95
    onSearchTermChange(value);
96
  };
97

NEW
98
  const handleRemoveItem = async () => {
×
NEW
99
    if (onDelete && itemToRemove) {
×
NEW
100
      onDelete(itemToRemove as Item);
×
NEW
101
      closeModal();
×
102
    }
103
  };
NEW
104

×
NEW
105
  const openModal = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, item: SearchableListItem): void => {
×
NEW
106
    e.preventDefault();
×
107
    setModalOpened(true);
108
    setItemToRemove(item);
NEW
109
  };
×
110

NEW
111
  const closeModal = (): void => {
×
112
    setModalOpened(false);
113
    setItemToRemove(null);
114
  };
115

116
  const renderItemActions = typeof itemActions === 'function' ? itemActions : () => itemActions;
117

NEW
118
  return (
×
119
    <PageContent>
120
      <FormControl fullWidth size="small">
121
        <OutlinedInput
×
122
          value={searchTerm}
123
          placeholder={t('components.searchableList.placeholder')}
124
          onChange={handleSearch}
125
          sx={{ background: theme => theme.palette.primary.contrastText }}
126
        />
127
      </FormControl>
128
      {typeof totalCount === 'undefined' ? null : (
129
        <InputLabel> {t('components.searchableList.info', { count: data.length, total: totalCount })}</InputLabel>
130
      )}
131
      <TableContainer component={Paper}>
NEW
132
        <Table sx={{ minWidth: 700 }} aria-label="customized table">
×
133
          <TableHead>
134
            <TableRow
135
              sx={{
136
                width: '100%',
137
                display: 'flex',
138
                alignItems: 'flex-end',
139
                background: theme => theme.palette.primary.main,
140
              }}
141
            >
142
              <TableCell component="th" scope="row">
143
                <CardTitle color="primary.contrastText">Name</CardTitle>
144
              </TableCell>
145
              <TableCell component="th" scope="row" sx={{ flex: 1 }}>
146
                &nbsp;
147
              </TableCell>
×
NEW
148
              <TableCell component="th" scope="row">
×
149
                <CardTitle color="primary.contrastText">Actions</CardTitle>
NEW
150
              </TableCell>
×
151
            </TableRow>
152
          </TableHead>
153
          <TableBody>
×
154
            {loading && !data
155
              ? times(firstPageSize, i => <LoadingListItem key={`__loading_${i}`} />)
156
              : data.map((item, index) => (
157
                  <TableRow
158
                    key={item.id}
159
                    sx={{
160
                      backgroundColor: index % 2 === 0 ? 'inherit' : 'action.hover',
161
                      '&:last-child td, &:last-child th': { border: 0 },
162
                      display: 'flex',
163
                      alignItems: 'center',
164
                      justifyContent: 'space-between',
165
                    }}
166
                  >
167
                    <TableCell component="th" scope="row" sx={{ paddingY: 1 }}>
168
                      {item.avatar ? (
×
NEW
169
                        <ContributorCardHorizontal
×
170
                          profile={{
171
                            displayName: item.value,
172
                            url: item.url,
173
                            avatar: item.avatar,
174
                          }}
175
                          seamless
176
                        />
177
                      ) : (
178
                        <BlockTitle component={RouterLink} to={item.url}>
179
                          {item.value}
180
                        </BlockTitle>
181
                      )}
182
                    </TableCell>
183
                    <TableCell component="th" scope="row" sx={{ paddingY: 1 }}>
184
                      <Actions>
185
                        {renderItemActions(item)}
186
                        {onDelete && (
187
                          <IconButton onClick={e => openModal(e, item)} size="large" aria-label={t('buttons.delete')}>
188
                            <DeleteOutline color="error" />
189
                          </IconButton>
190
                        )}
191
                      </Actions>
192
                    </TableCell>
193
                  </TableRow>
194
                ))}
195
          </TableBody>
196
        </Table>
197
      </TableContainer>
198
      {loader}
199
      <RemoveModal
200
        show={isModalOpened}
201
        onCancel={closeModal}
202
        onConfirm={handleRemoveItem}
203
        text={`Are you sure you want to remove: ${itemToRemove?.value}`}
204
      />
205
    </PageContent>
206
  );
207
};
208

209
export default SimpleSearchableList;
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

© 2026 Coveralls, Inc