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

mendersoftware / mender-server / 1568834739

02 Dec 2024 10:01AM UTC coverage: 73.562% (+0.8%) from 72.786%
1568834739

Pull #211

gitlab-ci

mineralsfree
test: added upgrade unit tests

Ticket: MEN-7469
Changelog: None

Signed-off-by: Mikita Pilinka <mikita.pilinka@northern.tech>
Pull Request #211: MEN-7469-feat: updated upgrades and add-on page

4251 of 6156 branches covered (69.05%)

Branch coverage included in aggregate %.

166 of 200 new or added lines in 18 files covered. (83.0%)

47 existing lines in 4 files now uncovered.

40029 of 54038 relevant lines covered (74.08%)

17.83 hits per line

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

62.96
/frontend/src/js/components/auditlogs/auditlogslist.js
1
// Copyright 2020 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 from 'react';
15
import { Link } from 'react-router-dom';
16

17
import { Sort as SortIcon } from '@mui/icons-material';
18

19
import DetailsIndicator from '@northern.tech/common-ui/detailsindicator';
20
import DeviceIdentityDisplay from '@northern.tech/common-ui/deviceidentity';
21
import Loader from '@northern.tech/common-ui/loader';
22
import Pagination from '@northern.tech/common-ui/pagination';
23
import Time from '@northern.tech/common-ui/time';
24
import { DEPLOYMENT_ROUTES, SORTING_OPTIONS, auditlogTypes, canAccess } from '@northern.tech/store/constants';
25

26
import EventDetailsDrawer from './eventdetailsdrawer';
27

28
export const defaultRowsPerPage = 20;
4✔
29

30
const ArtifactLink = ({ item }) => <Link to={`/releases/${item.object.artifact.name}`}>View artifact</Link>;
4✔
31
const DeploymentLink = ({ item }) => <Link to={`${DEPLOYMENT_ROUTES.finished.route}?open=true&id=${item.object.id}`}>View deployment</Link>;
11✔
32
const DeviceLink = ({ item }) => <Link to={`/devices?id=${item.object.id}`}>View device</Link>;
4✔
33
const DeviceRejectedLink = ({ item }) => <Link to={`/devices/rejected?id=${item.object.id}`}>View device</Link>;
4✔
34
const TerminalSessionLink = () => <a>View session log</a>;
11✔
35
const ChangeFallback = props => {
4✔
36
  const {
37
    item: { change = '-' }
×
38
  } = props;
11✔
39
  return <div>{change}</div>;
11✔
40
};
41

42
const FallbackFormatter = props => {
4✔
UNCOV
43
  let result = '';
×
UNCOV
44
  try {
×
UNCOV
45
    result = JSON.stringify(props);
×
46
  } catch (error) {
UNCOV
47
    console.log(error);
×
48
  }
UNCOV
49
  return <div>{result}</div>;
×
50
};
51

52
const ArtifactFormatter = ({ artifact }) => <div>{artifact.name}</div>;
4✔
53
const DeploymentFormatter = ({ deployment }) => <div>{deployment.name}</div>;
11✔
54
const DeviceFormatter = ({ id }) => <DeviceIdentityDisplay device={{ id }} />;
11✔
55
const UserFormatter = ({ user }) => <div>{user.email}</div>;
11✔
56
const TenantFormatter = ({ tenant }) => <div>{tenant.name}</div>;
4✔
57

58
const defaultAccess = canAccess;
4✔
59
const changeMap = {
4✔
60
  default: { component: 'div', actionFormatter: FallbackFormatter, title: 'defaultTitle', accessCheck: defaultAccess },
UNCOV
61
  artifact: { actionFormatter: ArtifactFormatter, component: ArtifactLink, accessCheck: ({ canReadReleases }) => canReadReleases },
×
62
  deployment: {
63
    actionFormatter: DeploymentFormatter,
64
    component: DeploymentLink,
65
    accessCheck: ({ canReadDeployments }) => canReadDeployments
11✔
66
  },
67
  deviceDecommissioned: { actionFormatter: DeviceFormatter, component: 'div', accessCheck: defaultAccess },
UNCOV
68
  deviceRejected: { actionFormatter: DeviceFormatter, component: DeviceRejectedLink, accessCheck: ({ canReadDevices }) => canReadDevices },
×
UNCOV
69
  deviceGeneral: { actionFormatter: DeviceFormatter, component: DeviceLink, accessCheck: ({ canReadDevices }) => canReadDevices },
×
70
  deviceTerminalSession: { actionFormatter: DeviceFormatter, component: TerminalSessionLink, accessCheck: defaultAccess },
71
  user: { actionFormatter: UserFormatter, component: ChangeFallback, accessCheck: defaultAccess },
72
  user_access_token: { actionFormatter: FallbackFormatter, component: ChangeFallback, accessCheck: defaultAccess },
73
  tenant: { actionFormatter: TenantFormatter, component: ChangeFallback, accessCheck: defaultAccess }
74
};
75

76
const mapChangeToContent = item => {
4✔
77
  let content = changeMap[item.object.type];
66✔
78
  if (content) {
66✔
79
    return content;
44✔
80
  } else if (item.object.type === 'device' && item.action.includes('terminal')) {
22!
81
    content = changeMap.deviceTerminalSession;
22✔
UNCOV
82
  } else if (item.object.type === 'device' && item.action.includes('reject')) {
×
UNCOV
83
    content = changeMap.deviceRejected;
×
UNCOV
84
  } else if (item.object.type === 'device' && item.action.includes('decommission')) {
×
UNCOV
85
    content = changeMap.deviceDecommissioned;
×
UNCOV
86
  } else if (item.object.type === 'device') {
×
UNCOV
87
    content = changeMap.deviceGeneral;
×
88
  } else {
UNCOV
89
    content = changeMap.default;
×
90
  }
91
  return content;
22✔
92
};
93

94
const actorMap = {
4✔
95
  user: 'email',
96
  device: 'id'
97
};
98

99
const UserDescriptor = (item, index) => <div key={`${item.time}-${index} `}>{item.actor[actorMap[item.actor.type]]}</div>;
33✔
100
const ActionDescriptor = (item, index) => (
4✔
101
  <div className="uppercased" key={`${item.time}-${index}`}>
33✔
102
    {item.action}
103
  </div>
104
);
105
const TypeDescriptor = (item, index) => (
4✔
106
  <div className="capitalized" key={`${item.time}-${index}`}>
33✔
107
    {auditlogTypes[item.object.type]?.title ?? item.object.type}
33!
108
  </div>
109
);
110
const ChangeDescriptor = (item, index) => {
4✔
111
  const FormatterComponent = mapChangeToContent(item).actionFormatter;
33✔
112
  return <FormatterComponent key={`${item.time}-${index}`} {...item.object} />;
33✔
113
};
114
const ChangeDetailsDescriptor = (item, index, userCapabilities) => {
4✔
115
  const { component: Comp, accessCheck } = mapChangeToContent(item);
33✔
116
  const key = `${item.time}-${index}`;
33✔
117
  return accessCheck(userCapabilities) ? <Comp key={key} item={item} /> : <div key={key} />;
33!
118
};
119
const TimeWrapper = (item, index) => <Time key={`${item.time}-${index}`} value={item.time} />;
33✔
120

121
const auditLogColumns = [
4✔
122
  { title: 'Performed by', sortable: false, render: UserDescriptor },
123
  { title: 'Action', sortable: false, render: ActionDescriptor },
124
  { title: 'Type', sortable: false, render: TypeDescriptor },
125
  { title: 'Changed', sortable: false, render: ChangeDescriptor },
126
  { title: 'More details', sortable: false, render: ChangeDetailsDescriptor },
127
  { title: 'Time', sortable: true, render: TimeWrapper }
128
];
129

130
export const AuditLogsList = ({
4✔
131
  eventItem,
132
  items,
133
  loading,
134
  onChangePage,
135
  onChangeRowsPerPage,
136
  onChangeSorting,
137
  selectionState,
138
  setAuditlogsState,
139
  userCapabilities
140
}) => {
141
  const { page, perPage, sort = {}, total: count } = selectionState;
11!
142

143
  const onIssueSelection = selectedIssue =>
11✔
144
    setAuditlogsState({ selectedId: selectedIssue ? btoa(`${selectedIssue.action}|${selectedIssue.time}`) : undefined });
1!
145

146
  return (
11✔
147
    !!items.length && (
22✔
148
      <div className="fadeIn deploy-table-contain auditlogs-list">
149
        <div className="auditlogs-list-item auditlogs-list-item-header muted">
150
          {auditLogColumns.map((column, index) => (
151
            <div
66✔
152
              className="columnHeader"
153
              key={`columnHeader-${index}`}
UNCOV
154
              onClick={() => (column.sortable ? onChangeSorting() : null)}
×
155
              style={column.sortable ? {} : { cursor: 'initial' }}
66✔
156
            >
157
              {column.title}
158
              {column.sortable ? <SortIcon className={`sortIcon selected ${(sort.direction === SORTING_OPTIONS.desc).toString()}`} /> : null}
66✔
159
            </div>
160
          ))}
161
          <div />
162
        </div>
163
        <div className="auditlogs-list">
164
          {items.map(item => {
165
            const allowsExpansion = !!item.change || item.action.includes('terminal') || item.action.includes('portforward');
33!
166
            return (
33✔
167
              <div
168
                className={`auditlogs-list-item ${allowsExpansion ? 'clickable' : ''}`}
33!
169
                key={`event-${item.time}`}
170
                onClick={() => onIssueSelection(allowsExpansion ? item : undefined)}
1!
171
              >
172
                {auditLogColumns.map((column, index) => column.render(item, index, userCapabilities))}
198✔
173
                {allowsExpansion ? <DetailsIndicator /> : <div />}
33!
174
              </div>
175
            );
176
          })}
177
        </div>
178
        <div className="flexbox margin-top">
179
          <Pagination
180
            className="margin-top-none"
181
            count={count}
182
            rowsPerPage={perPage}
183
            onChangeRowsPerPage={onChangeRowsPerPage}
184
            page={page}
185
            onChangePage={onChangePage}
186
          />
187
          <Loader show={loading} small />
188
        </div>
UNCOV
189
        <EventDetailsDrawer eventItem={eventItem} open={Boolean(eventItem)} onClose={() => onIssueSelection()} />
×
190
      </div>
191
    )
192
  );
193
};
194

195
export default AuditLogsList;
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