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

mendersoftware / mender-server / 1501783099

18 Oct 2024 07:49AM UTC coverage: 72.799%. First build
1501783099

push

gitlab-ci

web-flow
Merge pull request #101 from mineralsfree/MEN-7568

feat: tenant list added

4408 of 6393 branches covered (68.95%)

Branch coverage included in aggregate %.

88 of 182 new or added lines in 10 files covered. (48.35%)

42624 of 58212 relevant lines covered (73.22%)

28.08 hits per line

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

0.0
/frontend/src/js/components/tenants/tenantlist.tsx
1
// Copyright 2024 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14
import React, { useCallback, useEffect } from 'react';
15
import { useDispatch, useSelector } from 'react-redux';
16

17
import { ArrowForward as ArrowForwardIcon, Check as CheckIcon } from '@mui/icons-material';
18

19
import { getDeviceLimit, getTenantsList } from '@northern.tech/store/selectors';
20
import { AppDispatch } from '@northern.tech/store/store';
21
import { getTenants, setTenantsListState } from '@northern.tech/store/thunks';
22
import dayjs from 'dayjs';
23

24
import { ColumnHeader, CommonList, ListItemComponentProps, RendererProp } from '../common/list';
25
import { ExpandedTenant } from './expanded-tenant';
26
import { Tenant } from './types';
27

NEW
28
export const defaultTextRender = (props: RendererProp<Tenant>) => {
×
NEW
29
  const { column, item } = props;
×
NEW
30
  const attributeValue = item?.[column.attribute.name];
×
NEW
31
  return typeof attributeValue === 'object' ? JSON.stringify(attributeValue) : attributeValue;
×
32
};
NEW
33
export const DeviceLimitRender = (props: RendererProp<Tenant>) => {
×
34
  //TODO: use better alternative once backend is ready (MEN-7615)
NEW
35
  const deviceLimit = useSelector(getDeviceLimit);
×
NEW
36
  const { column, item } = props;
×
NEW
37
  const attributeValue = item?.[column.attribute.name];
×
NEW
38
  return `${attributeValue}/${deviceLimit}`;
×
39
};
NEW
40
export const BoolRender = (props: RendererProp<Tenant>) => {
×
NEW
41
  const { column, item } = props;
×
NEW
42
  return <div>{item?.[column.attribute.name] ? <CheckIcon /> : <div>-</div>}</div>;
×
43
};
NEW
44
const AttributeRenderer = ({ content, textContent }) => (
×
NEW
45
  <div title={typeof textContent === 'string' ? textContent : ''}>
×
46
    <div className="text-overflow">{content}</div>
47
  </div>
48
);
NEW
49
const DateRender = (props: RendererProp<Tenant>) => {
×
NEW
50
  const { column, item } = props;
×
NEW
51
  const attributeValue = dayjs(item?.[column.attribute.name]).format('YYYY-MM-DD HH:mm');
×
NEW
52
  return <AttributeRenderer content={attributeValue} textContent={item?.[column.attribute.name]}></AttributeRenderer>;
×
53
};
NEW
54
const moreDetailsRender = () => {
×
NEW
55
  return (
×
56
    <div className="link-color">
57
      View details <ArrowForwardIcon sx={{ fontSize: 12 }} />
58
    </div>
59
  );
60
};
NEW
61
const columnHeaders: ColumnHeader<Tenant>[] = [
×
62
  {
63
    title: 'Name',
64
    attribute: {
65
      name: 'name',
66
      scope: ''
67
    },
68
    sortable: false,
69
    textRender: defaultTextRender
70
  },
71
  {
72
    title: 'Devices',
73
    attribute: {
74
      name: 'device_limit',
75
      scope: ''
76
    },
77
    sortable: false,
78
    textRender: DeviceLimitRender
79
  },
80
  {
81
    title: 'Delta updates enabled ',
82
    attribute: {
83
      name: 'binary_delta',
84
      scope: ''
85
    },
86
    sortable: false,
87
    textRender: BoolRender
88
  },
89
  {
90
    title: 'Created',
91
    attribute: {
92
      name: 'created_at',
93
      scope: ''
94
    },
95
    sortable: false,
96
    textRender: DateRender
97
  },
98
  {
99
    title: 'More details',
100
    attribute: {
101
      name: '',
102
      scope: ''
103
    },
104
    sortable: false,
105
    textRender: moreDetailsRender
106
  }
107
];
108

NEW
109
const DefaultAttributeRenderer = (props: RendererProp<Tenant>) => {
×
NEW
110
  const { column, item } = props;
×
NEW
111
  const text = column.textRender({ item, column });
×
NEW
112
  return <AttributeRenderer content={text} textContent={text} />;
×
113
};
114

NEW
115
const TenantListItem = (props: ListItemComponentProps<Tenant>) => {
×
NEW
116
  const { listItem, columnHeaders, onClick } = props;
×
NEW
117
  const handleOnClick = useCallback(() => {
×
NEW
118
    onClick(listItem);
×
119
  }, [listItem.id, onClick]);
120

NEW
121
  return (
×
122
    <div onClick={handleOnClick} className={`deviceListRow deviceListItem clickable`}>
123
      {columnHeaders.map((column: ColumnHeader<Tenant>) => {
NEW
124
        const Component = column.component ? column.component : DefaultAttributeRenderer;
×
NEW
125
        return <Component column={column} item={listItem} key={column.title} />;
×
126
      })}
127
    </div>
128
  );
129
};
NEW
130
export const TenantList = () => {
×
NEW
131
  const tenantListState = useSelector(getTenantsList);
×
NEW
132
  const { tenants, perPage, selectedTenant } = tenantListState;
×
NEW
133
  const dispatch: AppDispatch = useDispatch();
×
NEW
134
  useEffect(() => {
×
NEW
135
    dispatch(getTenants());
×
136
  }, [dispatch]);
NEW
137
  const onExpandClick = useCallback(
×
138
    (tenant: Tenant) => {
NEW
139
      return dispatch(setTenantsListState({ selectedTenant: tenant }));
×
140
    },
141
    [dispatch]
142
  );
NEW
143
  const onCloseClick = useCallback(() => {
×
NEW
144
    return dispatch(setTenantsListState({ selectedTenant: null }));
×
145
  }, [dispatch]);
NEW
146
  const onChangePagination = useCallback(
×
147
    (page, currentPerPage = perPage) => {
×
NEW
148
      dispatch(setTenantsListState({ page, perPage: currentPerPage }));
×
149
    },
150
    [dispatch, perPage]
151
  );
NEW
152
  return (
×
153
    <div>
154
      <CommonList
155
        columnHeaders={columnHeaders}
156
        listItems={tenants}
157
        listState={tenantListState}
NEW
158
        onChangeRowsPerPage={newPerPage => onChangePagination(1, newPerPage)}
×
159
        onExpandClick={onExpandClick}
160
        onPageChange={onChangePagination}
161
        onResizeColumns={false}
162
        onSelect={false}
163
        pageLoading={false}
164
        ListItemComponent={TenantListItem}
165
      ></CommonList>
166
      {selectedTenant && <ExpandedTenant onCloseClick={onCloseClick} tenantId={selectedTenant.id}></ExpandedTenant>}
×
167
    </div>
168
  );
169
};
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