blob: d65e667163c40411194d9620bec08b383d8d378d [file] [log] [blame]
AviZi280f8012017-06-09 02:39:56 +03001/*!
2 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing
14 * permissions and limitations under the License.
15 */
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020016import React, { Component } from 'react';
AviZi280f8012017-06-09 02:39:56 +030017import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
18import Tooltip from 'react-bootstrap/lib/Tooltip.js';
19import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
Avi Zivb8e2faf2017-07-18 19:45:38 +030020import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
AviZi280f8012017-06-09 02:39:56 +030021import i18n from 'nfvo-utils/i18n/i18n.js';
Avi Zivb8e2faf2017-07-18 19:45:38 +030022import LogDetails from './LogixUtil.jsx';
AviZi280f8012017-06-09 02:39:56 +030023
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020024function ActivityLogSortableCellHeader({ isHeader, data, isDes, onSort }) {
25 //TODO check icon sdc-ui
26 if (isHeader) {
27 return (
28 <span className="date-header" onClick={onSort}>
29 <span>{data}</span>
30 <span
31 className={`header-sort-arrow ${isDes ? 'up' : 'down'}`}
32 />
33 </span>
34 );
35 }
36 return (
37 <span className="date-cell">
38 <span>
39 {i18n.dateNormal(data, {
40 year: 'numeric',
41 month: 'numeric',
42 day: 'numeric'
43 })}
44 </span>
45 <span>
46 {i18n.dateNormal(data, {
47 hour: 'numeric',
48 minute: 'numeric',
49 hour12: true
50 })}
51 </span>
52 </span>
53 );
AviZi280f8012017-06-09 02:39:56 +030054}
55
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020056function ActivityLogStatus({ status, isHeader }) {
57 if (isHeader) {
58 return <span>{status}</span>;
59 }
60 let { message, success } = status;
61 return (
62 <span>
63 <span className={`status-icon ${success}`}>{`${
64 success ? i18n('Success') : i18n('Failure')
65 }`}</span>
66 {success && <SVGIcon name="checkCircle" color="positive" />}
67 {!success && (
68 <OverlayTrigger
69 placement="bottom"
70 overlay={
71 <Tooltip
72 className="activity-log-message-tooltip"
73 id={'activity-log-message-tooltip'}>
74 <div className="message-block">{message}</div>
75 </Tooltip>
76 }>
77 <span className="message-further-info-icon">{'?'}</span>
78 </OverlayTrigger>
79 )}
80 </span>
81 );
AviZi280f8012017-06-09 02:39:56 +030082}
83
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020084export function ActivityListItem({ activity, isHeader, isDes, onSort }) {
85 let { type, timestamp, comment, user, status } = activity;
86 return (
87 <li
88 className={`activity-list-item ${isHeader ? 'header' : ''}`}
89 data-test-id="activity-list-item">
90 <div
91 className="table-cell activity-date"
92 data-test-id="activity-date">
93 <ActivityLogSortableCellHeader
94 isHeader={isHeader}
95 data={timestamp}
96 isDes={isDes}
97 onSort={onSort}
98 />
99 </div>
100 <div
101 className="table-cell activity-action"
102 data-test-id="activity-action">
103 {i18n(type)}
104 </div>
105 <div
106 className="table-cell activity-comment"
107 title={isHeader ? '' : comment}
108 data-test-id="activity-comment">
109 <span>{i18n(comment)}</span>
110 </div>
111 <div
112 className="table-cell activity-username"
113 data-test-id="activity-username">
114 {isHeader
115 ? i18n(activity.user)
116 : `${i18n(user.name)} (${user.id})`}
117 </div>
118 <div
119 className="table-cell activity-status"
120 data-test-id="activity-status">
121 <ActivityLogStatus isHeader={isHeader} status={status} />
122 </div>
123 </li>
124 );
AviZi280f8012017-06-09 02:39:56 +0300125}
126
127class ActivityLogView extends Component {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200128 state = {
129 localFilter: '',
130 sortDescending: true
131 };
AviZi280f8012017-06-09 02:39:56 +0300132
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200133 render() {
134 return (
135 <div className="activity-log-view">
136 <LogDetails display={this.state.localFilter} />
137 <ListEditorView
138 title={i18n('Activity Log')}
139 filterValue={this.state.localFilter}
140 onFilter={filter => this.setState({ localFilter: filter })}>
141 <ActivityListItem
142 activity={{
143 timestamp: 'Date',
144 type: 'Action',
145 comment: 'Comment',
146 user: 'Username',
147 status: 'Status'
148 }}
149 isDes={this.state.sortDescending}
150 onSort={() =>
151 this.setState({
152 sortDescending: !this.state.sortDescending
153 })
154 }
155 isHeader
156 />
157 {this.sortActivities(
158 this.filterActivities(),
159 this.state.sortDescending
160 ).map(activity => (
161 <ActivityListItem
162 key={activity.id}
163 activity={activity}
164 />
165 ))}
166 </ListEditorView>
167 </div>
168 );
169 }
AviZi280f8012017-06-09 02:39:56 +0300170
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200171 filterActivities() {
172 let { activities } = this.props;
173 let { localFilter } = this.state;
174 if (localFilter.trim()) {
175 const filter = new RegExp(escape(localFilter), 'i');
176 return activities.filter(
177 ({ user = { id: '', name: '' }, comment = '', type = '' }) =>
178 escape(user.id).match(filter) ||
179 escape(user.name).match(filter) ||
180 escape(comment).match(filter) ||
181 escape(type).match(filter)
182 );
183 } else {
184 return activities;
185 }
186 }
AviZi280f8012017-06-09 02:39:56 +0300187
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200188 sortActivities(activities) {
189 if (this.state.sortDescending) {
190 return activities.sort((a, b) => a.timestamp - b.timestamp);
191 } else {
192 return activities.reverse();
193 }
194 }
AviZi280f8012017-06-09 02:39:56 +0300195}
196
197export default ActivityLogView;