blob: 4beb29254c93942281fb5b076ad5c2d449709d06 [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';
22
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020023function ActivityLogSortableCellHeader({ isHeader, data, isDes, onSort }) {
24 //TODO check icon sdc-ui
25 if (isHeader) {
26 return (
27 <span className="date-header" onClick={onSort}>
28 <span>{data}</span>
29 <span
30 className={`header-sort-arrow ${isDes ? 'up' : 'down'}`}
31 />
32 </span>
33 );
34 }
35 return (
36 <span className="date-cell">
37 <span>
38 {i18n.dateNormal(data, {
39 year: 'numeric',
40 month: 'numeric',
41 day: 'numeric'
42 })}
43 </span>
44 <span>
45 {i18n.dateNormal(data, {
46 hour: 'numeric',
47 minute: 'numeric',
48 hour12: true
49 })}
50 </span>
51 </span>
52 );
AviZi280f8012017-06-09 02:39:56 +030053}
54
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020055function ActivityLogStatus({ status, isHeader }) {
56 if (isHeader) {
57 return <span>{status}</span>;
58 }
59 let { message, success } = status;
60 return (
61 <span>
62 <span className={`status-icon ${success}`}>{`${
63 success ? i18n('Success') : i18n('Failure')
64 }`}</span>
65 {success && <SVGIcon name="checkCircle" color="positive" />}
66 {!success && (
67 <OverlayTrigger
68 placement="bottom"
69 overlay={
70 <Tooltip
71 className="activity-log-message-tooltip"
72 id={'activity-log-message-tooltip'}>
73 <div className="message-block">{message}</div>
74 </Tooltip>
75 }>
76 <span className="message-further-info-icon">{'?'}</span>
77 </OverlayTrigger>
78 )}
79 </span>
80 );
AviZi280f8012017-06-09 02:39:56 +030081}
82
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020083export function ActivityListItem({ activity, isHeader, isDes, onSort }) {
84 let { type, timestamp, comment, user, status } = activity;
85 return (
86 <li
87 className={`activity-list-item ${isHeader ? 'header' : ''}`}
88 data-test-id="activity-list-item">
89 <div
90 className="table-cell activity-date"
91 data-test-id="activity-date">
92 <ActivityLogSortableCellHeader
93 isHeader={isHeader}
94 data={timestamp}
95 isDes={isDes}
96 onSort={onSort}
97 />
98 </div>
99 <div
100 className="table-cell activity-action"
101 data-test-id="activity-action">
102 {i18n(type)}
103 </div>
104 <div
105 className="table-cell activity-comment"
106 title={isHeader ? '' : comment}
107 data-test-id="activity-comment">
108 <span>{i18n(comment)}</span>
109 </div>
110 <div
111 className="table-cell activity-username"
112 data-test-id="activity-username">
113 {isHeader
114 ? i18n(activity.user)
115 : `${i18n(user.name)} (${user.id})`}
116 </div>
117 <div
118 className="table-cell activity-status"
119 data-test-id="activity-status">
120 <ActivityLogStatus isHeader={isHeader} status={status} />
121 </div>
122 </li>
123 );
AviZi280f8012017-06-09 02:39:56 +0300124}
125
126class ActivityLogView extends Component {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200127 state = {
128 localFilter: '',
129 sortDescending: true
130 };
AviZi280f8012017-06-09 02:39:56 +0300131
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200132 render() {
133 return (
134 <div className="activity-log-view">
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200135 <ListEditorView
136 title={i18n('Activity Log')}
137 filterValue={this.state.localFilter}
138 onFilter={filter => this.setState({ localFilter: filter })}>
139 <ActivityListItem
140 activity={{
141 timestamp: 'Date',
142 type: 'Action',
143 comment: 'Comment',
144 user: 'Username',
145 status: 'Status'
146 }}
147 isDes={this.state.sortDescending}
148 onSort={() =>
149 this.setState({
150 sortDescending: !this.state.sortDescending
151 })
152 }
153 isHeader
154 />
155 {this.sortActivities(
156 this.filterActivities(),
157 this.state.sortDescending
158 ).map(activity => (
159 <ActivityListItem
160 key={activity.id}
161 activity={activity}
162 />
163 ))}
164 </ListEditorView>
165 </div>
166 );
167 }
AviZi280f8012017-06-09 02:39:56 +0300168
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200169 filterActivities() {
170 let { activities } = this.props;
171 let { localFilter } = this.state;
172 if (localFilter.trim()) {
173 const filter = new RegExp(escape(localFilter), 'i');
174 return activities.filter(
175 ({ user = { id: '', name: '' }, comment = '', type = '' }) =>
176 escape(user.id).match(filter) ||
177 escape(user.name).match(filter) ||
178 escape(comment).match(filter) ||
179 escape(type).match(filter)
180 );
181 } else {
182 return activities;
183 }
184 }
AviZi280f8012017-06-09 02:39:56 +0300185
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200186 sortActivities(activities) {
187 if (this.state.sortDescending) {
188 return activities.sort((a, b) => a.timestamp - b.timestamp);
189 } else {
190 return activities.reverse();
191 }
192 }
AviZi280f8012017-06-09 02:39:56 +0300193}
194
195export default ActivityLogView;