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

mendersoftware / gui / 1315496247

03 Jun 2024 07:49AM UTC coverage: 83.437% (-16.5%) from 99.964%
1315496247

Pull #4434

gitlab-ci

mzedel
chore: aligned snapshots with updated mui version

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #4434: chore: Bump the mui group with 3 updates

4476 of 6391 branches covered (70.04%)

8488 of 10173 relevant lines covered (83.44%)

140.36 hits per line

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

75.0
/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 { ArrowRightAlt as ArrowRightAltIcon, Sort as SortIcon } from '@mui/icons-material';
18

19
import { SORTING_OPTIONS, canAccess } from '../../constants/appConstants';
20
import { DEPLOYMENT_ROUTES } from '../../constants/deploymentConstants';
21
import DeviceIdentityDisplay from '../common/deviceidentity';
22
import Loader from '../common/loader';
23
import Pagination from '../common/pagination';
24
import Time from '../common/time';
25
import EventDetailsDrawer from './eventdetailsdrawer';
26

27
export const defaultRowsPerPage = 20;
4✔
28

29
const ArtifactLink = ({ item }) => <Link to={`/releases/${item.object.artifact.name}`}>View artifact</Link>;
4✔
30
const DeploymentLink = ({ item }) => <Link to={`${DEPLOYMENT_ROUTES.finished.route}?open=true&id=${item.object.id}`}>View deployment</Link>;
11✔
31
const DeviceLink = ({ item }) => <Link to={`/devices?id=${item.object.id}`}>View device</Link>;
4✔
32
const DeviceRejectedLink = ({ item }) => <Link to={`/devices/rejected?id=${item.object.id}`}>View device</Link>;
4✔
33
const TerminalSessionLink = () => <a>View session log</a>;
11✔
34
const UserChange = ({ item: { change = '-' } }) => {
4!
35
  const formatChange = change => {
11✔
36
    const diff = change.split(/@@.*@@/);
11✔
37
    return diff.length > 1 ? diff[1].trim() : diff;
11!
38
  };
39
  return (
11✔
40
    <div className="capitalized" style={{ alignItems: 'flex-start', whiteSpace: 'pre-line' }}>
41
      {formatChange(change)}
42
    </div>
43
  );
44
};
45

46
const FallbackFormatter = props => {
4✔
47
  let result = '';
×
48
  try {
×
49
    result = JSON.stringify(props);
×
50
  } catch (error) {
51
    console.log(error);
×
52
  }
53
  return <div>{result}</div>;
×
54
};
55

56
const ArtifactFormatter = ({ artifact }) => <div>{artifact.name}</div>;
4✔
57
const DeploymentFormatter = ({ deployment }) => <div>{deployment.name}</div>;
11✔
58
const DeviceFormatter = ({ id }) => <DeviceIdentityDisplay device={{ id }} />;
11✔
59
const UserFormatter = ({ user }) => <div>{user.email}</div>;
11✔
60

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

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

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

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

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

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

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

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

202
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