dce-reactkit 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +662 -771
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/Pagination.d.ts +13 -0
- package/dist/cjs/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
- package/dist/cjs/types/helpers/cloneDeep.d.ts +8 -0
- package/dist/cjs/types/index.d.ts +4 -1
- package/dist/cjs/types/types/LogReviewerFilterState/ActionErrorFilterState.d.ts +17 -0
- package/dist/cjs/types/types/LogReviewerFilterState/AdvancedFilterState.d.ts +21 -0
- package/dist/cjs/types/types/LogReviewerFilterState/ContextFilterState.d.ts +10 -0
- package/dist/cjs/types/types/LogReviewerFilterState/DateFilterState.d.ts +17 -0
- package/dist/cjs/types/types/LogReviewerFilterState/TagFilterState.d.ts +8 -0
- package/dist/cjs/types/types/LogReviewerFilterState/index.d.ts +17 -0
- package/dist/esm/index.js +661 -773
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/Pagination.d.ts +13 -0
- package/dist/esm/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
- package/dist/esm/types/helpers/cloneDeep.d.ts +8 -0
- package/dist/esm/types/index.d.ts +4 -1
- package/dist/esm/types/types/LogReviewerFilterState/ActionErrorFilterState.d.ts +17 -0
- package/dist/esm/types/types/LogReviewerFilterState/AdvancedFilterState.d.ts +21 -0
- package/dist/esm/types/types/LogReviewerFilterState/ContextFilterState.d.ts +10 -0
- package/dist/esm/types/types/LogReviewerFilterState/DateFilterState.d.ts +17 -0
- package/dist/esm/types/types/LogReviewerFilterState/TagFilterState.d.ts +8 -0
- package/dist/esm/types/types/LogReviewerFilterState/index.d.ts +17 -0
- package/dist/index.d.ts +98 -1
- package/package.json +2 -1
- package/src/components/LogReviewer.tsx +1133 -1307
- package/src/components/Pagination.tsx +172 -0
- package/src/constants/LOG_REVIEW_GET_LOGS_ROUTE.ts +9 -0
- package/src/helpers/cloneDeep.ts +11 -0
- package/src/index.ts +6 -0
- package/src/types/LogReviewerFilterState/ActionErrorFilterState.ts +24 -0
- package/src/types/LogReviewerFilterState/AdvancedFilterState.ts +36 -0
- package/src/types/LogReviewerFilterState/ContextFilterState.ts +16 -0
- package/src/types/LogReviewerFilterState/DateFilterState.ts +26 -0
- package/src/types/LogReviewerFilterState/TagFilterState.ts +9 -0
- package/src/types/LogReviewerFilterState/index.ts +24 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Import React
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
// Import FontAwesome
|
|
5
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
6
|
+
import { faArrowLeft, faArrowRight } from '@fortawesome/free-solid-svg-icons';
|
|
7
|
+
|
|
8
|
+
/*------------------------------------------------------------------------*/
|
|
9
|
+
/* -------------------------------- Types ------------------------------- */
|
|
10
|
+
/*------------------------------------------------------------------------*/
|
|
11
|
+
|
|
12
|
+
// Props
|
|
13
|
+
type Props = {
|
|
14
|
+
// Current page number (1-indexed)
|
|
15
|
+
currentPage: number,
|
|
16
|
+
// Total number of pages
|
|
17
|
+
numPages: number,
|
|
18
|
+
// True if a page change is in progress (to disable buttons)
|
|
19
|
+
loading?: boolean,
|
|
20
|
+
/**
|
|
21
|
+
* Handler for when page is changed
|
|
22
|
+
* @param page - the new page number
|
|
23
|
+
*/
|
|
24
|
+
onPageChanged: (page: number) => void,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/*------------------------------------------------------------------------*/
|
|
28
|
+
/* ------------------------------ Component ----------------------------- */
|
|
29
|
+
/*------------------------------------------------------------------------*/
|
|
30
|
+
|
|
31
|
+
const Pagination: React.FC<Props> = (props: Props) => {
|
|
32
|
+
/*------------------------------------------------------------------------*/
|
|
33
|
+
/* -------------------------------- Setup ------------------------------- */
|
|
34
|
+
/*------------------------------------------------------------------------*/
|
|
35
|
+
|
|
36
|
+
/* -------------- Props ------------- */
|
|
37
|
+
|
|
38
|
+
// Destructure props
|
|
39
|
+
const {
|
|
40
|
+
currentPage,
|
|
41
|
+
numPages,
|
|
42
|
+
loading = false,
|
|
43
|
+
onPageChanged,
|
|
44
|
+
} = props;
|
|
45
|
+
|
|
46
|
+
/*------------------------------------------------------------------------*/
|
|
47
|
+
/* ------------------------------- Render ------------------------------- */
|
|
48
|
+
/*------------------------------------------------------------------------*/
|
|
49
|
+
|
|
50
|
+
// Compute pages to display
|
|
51
|
+
const pages: number[] = [];
|
|
52
|
+
const delta = 2; // how many pages to show on either side of current
|
|
53
|
+
let start = Math.max(1, currentPage - delta);
|
|
54
|
+
let end = Math.min(numPages, currentPage + delta);
|
|
55
|
+
|
|
56
|
+
// If we are too close to the beginning or end, shift the window.
|
|
57
|
+
if (currentPage - delta < 1) {
|
|
58
|
+
end = Math.min(numPages, end + (1 - (currentPage - delta)));
|
|
59
|
+
}
|
|
60
|
+
if (currentPage + delta > numPages) {
|
|
61
|
+
start = Math.max(1, start - ((currentPage + delta) - numPages));
|
|
62
|
+
}
|
|
63
|
+
for (let i = start; i <= end; i++) {
|
|
64
|
+
pages.push(i);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Render
|
|
68
|
+
return (
|
|
69
|
+
<nav
|
|
70
|
+
aria-label="Page navigation for logs"
|
|
71
|
+
className="mt-3"
|
|
72
|
+
>
|
|
73
|
+
<ul className="pagination justify-content-center">
|
|
74
|
+
{/* Previous Button */}
|
|
75
|
+
<li className={`page-item ${(currentPage <= 1 || loading) ? 'disabled' : ''}`}>
|
|
76
|
+
<button
|
|
77
|
+
type="button"
|
|
78
|
+
className="page-link"
|
|
79
|
+
onClick={() => { return onPageChanged(currentPage - 1); }}
|
|
80
|
+
disabled={currentPage <= 1 || loading}
|
|
81
|
+
aria-label="Go to previous page"
|
|
82
|
+
>
|
|
83
|
+
<FontAwesomeIcon icon={faArrowLeft} />
|
|
84
|
+
{' '}
|
|
85
|
+
Prev
|
|
86
|
+
</button>
|
|
87
|
+
</li>
|
|
88
|
+
|
|
89
|
+
{/* First page (if needed) */}
|
|
90
|
+
{(currentPage > 3 && pages[0] !== 1) && (
|
|
91
|
+
<li className="page-item">
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
className="page-link"
|
|
95
|
+
onClick={() => { return onPageChanged(1); }}
|
|
96
|
+
disabled={loading}
|
|
97
|
+
aria-label="Go to page 1"
|
|
98
|
+
>
|
|
99
|
+
1
|
|
100
|
+
</button>
|
|
101
|
+
</li>
|
|
102
|
+
)}
|
|
103
|
+
|
|
104
|
+
{/* Ellipsis if gap between first page and start of window */}
|
|
105
|
+
{currentPage > 4 && (
|
|
106
|
+
<li className="page-item disabled">
|
|
107
|
+
<span className="page-link">...</span>
|
|
108
|
+
</li>
|
|
109
|
+
)}
|
|
110
|
+
|
|
111
|
+
{/* Page numbers */}
|
|
112
|
+
{pages.map((pageNum) => {
|
|
113
|
+
return (
|
|
114
|
+
<li key={pageNum} className={`page-item ${pageNum === currentPage ? 'active' : ''}`}>
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
className="page-link"
|
|
118
|
+
onClick={() => { return onPageChanged(pageNum); }}
|
|
119
|
+
disabled={loading}
|
|
120
|
+
aria-label={`Go to page ${pageNum}`}
|
|
121
|
+
>
|
|
122
|
+
{pageNum}
|
|
123
|
+
</button>
|
|
124
|
+
</li>
|
|
125
|
+
);
|
|
126
|
+
})}
|
|
127
|
+
|
|
128
|
+
{/* Ellipsis if gap between end of window and last page */}
|
|
129
|
+
{currentPage < numPages - 3 && (
|
|
130
|
+
<li className="page-item disabled">
|
|
131
|
+
<span className="page-link">...</span>
|
|
132
|
+
</li>
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
{/* Last page (if needed) */}
|
|
136
|
+
{(
|
|
137
|
+
currentPage < numPages - 2
|
|
138
|
+
&& pages[pages.length - 1] !== numPages
|
|
139
|
+
) && (
|
|
140
|
+
<li className="page-item">
|
|
141
|
+
<button
|
|
142
|
+
type="button"
|
|
143
|
+
className="page-link"
|
|
144
|
+
onClick={() => { return onPageChanged(numPages); }}
|
|
145
|
+
disabled={loading}
|
|
146
|
+
aria-label="Go to last page"
|
|
147
|
+
>
|
|
148
|
+
{numPages}
|
|
149
|
+
</button>
|
|
150
|
+
</li>
|
|
151
|
+
)}
|
|
152
|
+
|
|
153
|
+
{/* Next Button */}
|
|
154
|
+
<li className={`page-item ${(currentPage >= numPages || loading) ? 'disabled' : ''}`}>
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
className="page-link"
|
|
158
|
+
onClick={() => { return onPageChanged(currentPage + 1); }}
|
|
159
|
+
disabled={currentPage >= numPages || loading}
|
|
160
|
+
aria-label="Go to next page"
|
|
161
|
+
>
|
|
162
|
+
Next
|
|
163
|
+
{' '}
|
|
164
|
+
<FontAwesomeIcon icon={faArrowRight} />
|
|
165
|
+
</button>
|
|
166
|
+
</li>
|
|
167
|
+
</ul>
|
|
168
|
+
</nav>
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export default Pagination;
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,7 @@ import DAY_IN_MS from './constants/DAY_IN_MS';
|
|
|
42
42
|
import LOG_REVIEW_ROUTE_PATH_PREFIX from './constants/LOG_REVIEW_ROUTE_PATH_PREFIX';
|
|
43
43
|
import LOG_ROUTE_PATH from './constants/LOG_ROUTE_PATH';
|
|
44
44
|
import LOG_REVIEW_STATUS_ROUTE from './constants/LOG_REVIEW_STATUS_ROUTE';
|
|
45
|
+
import LOG_REVIEW_GET_LOGS_ROUTE from './constants/LOG_REVIEW_GET_LOGS_ROUTE';
|
|
45
46
|
|
|
46
47
|
// Import dynamic constants
|
|
47
48
|
import DynamicWord from './dynamicConstants/DynamicWord';
|
|
@@ -93,6 +94,7 @@ import someAsync from './helpers/asyncArrayFunctions/someAsync';
|
|
|
93
94
|
import capitalize from './helpers/capitalize';
|
|
94
95
|
import shuffleArray from './helpers/shuffleArray';
|
|
95
96
|
import getWordCount from './helpers/getWordCount';
|
|
97
|
+
import cloneDeep from './helpers/cloneDeep';
|
|
96
98
|
|
|
97
99
|
// Import types
|
|
98
100
|
import ParamType from './types/ParamType';
|
|
@@ -115,6 +117,7 @@ import LogLevel from './types/LogLevel';
|
|
|
115
117
|
import IntelliTableColumn from './types/IntelliTableColumn';
|
|
116
118
|
import DropdownItemType from './types/DropdownItemType';
|
|
117
119
|
import ReactKitErrorCode from './types/ReactKitErrorCode';
|
|
120
|
+
import LogReviewerFilterState from './types/LogReviewerFilterState';
|
|
118
121
|
|
|
119
122
|
// Component-specific-types
|
|
120
123
|
import PickableItem from './components/ItemPicker/types/PickableItem';
|
|
@@ -164,6 +167,7 @@ export {
|
|
|
164
167
|
LOG_REVIEW_ROUTE_PATH_PREFIX,
|
|
165
168
|
LOG_ROUTE_PATH,
|
|
166
169
|
LOG_REVIEW_STATUS_ROUTE,
|
|
170
|
+
LOG_REVIEW_GET_LOGS_ROUTE,
|
|
167
171
|
// Dynamic Constants
|
|
168
172
|
DynamicWord,
|
|
169
173
|
// Helpers
|
|
@@ -208,6 +212,7 @@ export {
|
|
|
208
212
|
capitalize,
|
|
209
213
|
shuffleArray,
|
|
210
214
|
getWordCount,
|
|
215
|
+
cloneDeep,
|
|
211
216
|
// Client helpers
|
|
212
217
|
initClient,
|
|
213
218
|
visitServerEndpoint,
|
|
@@ -238,6 +243,7 @@ export {
|
|
|
238
243
|
LogLevel,
|
|
239
244
|
IntelliTableColumn,
|
|
240
245
|
DropdownItemType,
|
|
246
|
+
LogReviewerFilterState,
|
|
241
247
|
// Component-specific-types
|
|
242
248
|
PickableItem,
|
|
243
249
|
DBEntry,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import LogType from '../LogType';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Action filter state (only relevant for action logs)
|
|
5
|
+
* @author Yuen Ler Chow
|
|
6
|
+
*/
|
|
7
|
+
type ActionErrorFilterState = {
|
|
8
|
+
// Required type of log
|
|
9
|
+
type: LogType | undefined, // If undefined, no filter applied
|
|
10
|
+
// Query for error message (only relevant if type is error)
|
|
11
|
+
errorMessage: string, // If empty, no filter applied
|
|
12
|
+
// Query for error code (only relevant if type is error)
|
|
13
|
+
errorCode: string, // If empty, no filter applied
|
|
14
|
+
// Action targets to include (only relevant if type is action)
|
|
15
|
+
target: {
|
|
16
|
+
[k: string]: boolean
|
|
17
|
+
},
|
|
18
|
+
// Action types to include (only relevant if type is action)
|
|
19
|
+
action: {
|
|
20
|
+
[k: string]: boolean
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default ActionErrorFilterState;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import LogSource from '../LogSource';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Advanced filter state
|
|
5
|
+
* @author Yuen Ler Chow
|
|
6
|
+
*/
|
|
7
|
+
type AdvancedFilterState = {
|
|
8
|
+
// Query for user first name (case insensitive)
|
|
9
|
+
userFirstName: string, // If empty, no filter applied
|
|
10
|
+
// Query for user last name (case insensitive)
|
|
11
|
+
userLastName: string, // If empty, no filter applied
|
|
12
|
+
// Query for user email (case insensitive)
|
|
13
|
+
userEmail: string, // If empty, no filter applied
|
|
14
|
+
// Match for userId (numerical)
|
|
15
|
+
userId: string, // If empty, no filter applied
|
|
16
|
+
// If true, include students
|
|
17
|
+
includeLearners: boolean,
|
|
18
|
+
// If true, include ttms
|
|
19
|
+
includeTTMs: boolean,
|
|
20
|
+
// If true, include admins
|
|
21
|
+
includeAdmins: boolean,
|
|
22
|
+
// Match for courseId (numerical)
|
|
23
|
+
courseId: string, // If empty, no filter applied
|
|
24
|
+
// Query for course name (case insensitive)
|
|
25
|
+
courseName: string, // If empty, no filter applied
|
|
26
|
+
// Required isMobile value
|
|
27
|
+
isMobile: (true | false | undefined), // If undefined, no filter applied
|
|
28
|
+
// Required log source value
|
|
29
|
+
source: LogSource | undefined, // If undefined, no filter applied
|
|
30
|
+
// Query for route path (only relevant if source is server)
|
|
31
|
+
routePath: string, // If empty, no filter applied
|
|
32
|
+
// Query for route template (only relevant if source is server)
|
|
33
|
+
routeTemplate: string, // If empty, no filter applied
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default AdvancedFilterState;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context filter state
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
type ContextFilterState = {
|
|
6
|
+
[k: string]: (
|
|
7
|
+
// No subcontexts
|
|
8
|
+
| boolean // True if selected
|
|
9
|
+
// Includes subcontexts
|
|
10
|
+
| {
|
|
11
|
+
[k: string]: boolean // True if selected
|
|
12
|
+
}
|
|
13
|
+
)
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default ContextFilterState;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date filter state
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
type DateFilterState = {
|
|
6
|
+
// Current start date
|
|
7
|
+
startDate: {
|
|
8
|
+
// Full year
|
|
9
|
+
year: number,
|
|
10
|
+
// 1-indexed month
|
|
11
|
+
month: number,
|
|
12
|
+
// 1-indexed day
|
|
13
|
+
day: number,
|
|
14
|
+
},
|
|
15
|
+
// Current end date
|
|
16
|
+
endDate: {
|
|
17
|
+
// Full year
|
|
18
|
+
year: number,
|
|
19
|
+
// 1-indexed month
|
|
20
|
+
month: number,
|
|
21
|
+
// 1-indexed day
|
|
22
|
+
day: number,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default DateFilterState;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import DateFilterState from './DateFilterState';
|
|
2
|
+
import ContextFilterState from './ContextFilterState';
|
|
3
|
+
import TagFilterState from './TagFilterState';
|
|
4
|
+
import ActionErrorFilterState from './ActionErrorFilterState';
|
|
5
|
+
import AdvancedFilterState from './AdvancedFilterState';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A bundle of filter state objects for each type of filter
|
|
9
|
+
* @author Gabe Abrams
|
|
10
|
+
*/
|
|
11
|
+
type LogReviewerFilterState = {
|
|
12
|
+
// Date filter state
|
|
13
|
+
dateFilterState: DateFilterState,
|
|
14
|
+
// Context filter state
|
|
15
|
+
contextFilterState: ContextFilterState,
|
|
16
|
+
// Tag filter state
|
|
17
|
+
tagFilterState: TagFilterState,
|
|
18
|
+
// Action error filter state
|
|
19
|
+
actionErrorFilterState: ActionErrorFilterState,
|
|
20
|
+
// Advanced filter state
|
|
21
|
+
advancedFilterState: AdvancedFilterState,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default LogReviewerFilterState;
|