dce-reactkit 3.2.2-beta.4 → 3.2.2-beta.41
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 +404 -201
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/ButtonInputGroup.d.ts +1 -0
- package/dist/cjs/types/components/Drawer.d.ts +1 -0
- package/dist/cjs/types/components/ItemPicker/NestableItemList.d.ts +1 -0
- package/dist/cjs/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/cjs/types/types/LogAction.d.ts +16 -16
- package/dist/cjs/types/types/LogBuiltInMetadata.d.ts +1 -1
- package/dist/esm/index.js +405 -202
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/ButtonInputGroup.d.ts +1 -0
- package/dist/esm/types/components/Drawer.d.ts +1 -0
- package/dist/esm/types/components/ItemPicker/NestableItemList.d.ts +1 -0
- package/dist/esm/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/esm/types/types/LogAction.d.ts +16 -16
- package/dist/esm/types/types/LogBuiltInMetadata.d.ts +1 -1
- package/dist/index.d.ts +20 -17
- package/package.json +1 -1
- package/src/components/ButtonInputGroup.tsx +5 -2
- package/src/components/CSVDownloadButton.tsx +1 -1
- package/src/components/Drawer.tsx +9 -1
- package/src/components/IntelliTable.tsx +95 -23
- package/src/components/ItemPicker/NestableItemList.tsx +32 -14
- package/src/components/ItemPicker/index.tsx +4 -0
- package/src/components/LogReviewer.tsx +301 -147
- package/src/components/SimpleDateChooser.tsx +20 -7
- package/src/helpers/genCSV.ts +21 -4
- package/src/helpers/genRouteHandler.ts +2 -2
- package/src/helpers/logClientEvent.tsx +6 -1
- package/src/server/initServer.ts +11 -4
- package/src/types/LogAction.ts +16 -16
- package/src/types/LogBuiltInMetadata.ts +5 -5
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect, useReducer } from 'react';
|
|
2
2
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
-
import { faExclamationTriangle, faCircle, faDotCircle, faCheckSquare, faHourglass, faClipboard, faChevronDown, faChevronRight, faCloudDownloadAlt, faCheckCircle, faXmarkCircle,
|
|
3
|
+
import { faExclamationTriangle, faCircle, faDotCircle, faCheckSquare, faHourglass, faClipboard, faChevronDown, faChevronRight, faCloudDownloadAlt, faMinus, faCheckCircle, faXmarkCircle, faSort, faSortDown, faSortUp, faCalendar, faTag, faHammer, faList, faTimes } from '@fortawesome/free-solid-svg-icons';
|
|
4
4
|
import { faCircle as faCircle$1, faSquareMinus, faSquare } from '@fortawesome/free-regular-svg-icons';
|
|
5
5
|
|
|
6
6
|
/******************************************************************************
|
|
@@ -511,17 +511,29 @@ const LOG_ROUTE_PATH = `${ROUTE_PATH_PREFIX}/log`;
|
|
|
511
511
|
const LogBuiltInMetadata = {
|
|
512
512
|
// Contexts
|
|
513
513
|
Context: {
|
|
514
|
-
Uncategorized: '
|
|
515
|
-
ServerRenderedErrorPage: '
|
|
516
|
-
ServerEndpointError: '
|
|
517
|
-
ClientFatalError: '
|
|
514
|
+
Uncategorized: 'Uncategorized',
|
|
515
|
+
ServerRenderedErrorPage: 'ServerRenderedErrorPage',
|
|
516
|
+
ServerEndpointError: 'ServerEndpointError',
|
|
517
|
+
ClientFatalError: 'ClientFatalError',
|
|
518
518
|
},
|
|
519
519
|
// Targets
|
|
520
520
|
Target: {
|
|
521
|
-
|
|
521
|
+
NoTarget: 'NoTarget',
|
|
522
522
|
},
|
|
523
523
|
};
|
|
524
524
|
|
|
525
|
+
/**
|
|
526
|
+
* Allowed log levels
|
|
527
|
+
* @author Gabe Abrams
|
|
528
|
+
*/
|
|
529
|
+
var LogLevel;
|
|
530
|
+
(function (LogLevel) {
|
|
531
|
+
LogLevel["Warn"] = "Warn";
|
|
532
|
+
LogLevel["Info"] = "Info";
|
|
533
|
+
LogLevel["Debug"] = "Debug";
|
|
534
|
+
})(LogLevel || (LogLevel = {}));
|
|
535
|
+
var LogLevel$1 = LogLevel;
|
|
536
|
+
|
|
525
537
|
// Keep track of whether or not session expiry has already been handled
|
|
526
538
|
let sessionAlreadyExpired = false;
|
|
527
539
|
/*------------------------------------------------------------------------*/
|
|
@@ -640,7 +652,7 @@ const visitServerEndpoint = (opts) => __awaiter(void 0, void 0, void 0, function
|
|
|
640
652
|
* @author Gabe Abrams
|
|
641
653
|
*/
|
|
642
654
|
const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
643
|
-
var _a, _b, _c, _d, _e, _f;
|
|
655
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
644
656
|
return visitServerEndpoint({
|
|
645
657
|
path: LOG_ROUTE_PATH,
|
|
646
658
|
method: 'POST',
|
|
@@ -649,8 +661,9 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
649
661
|
? opts.context
|
|
650
662
|
: ((_b = ((_a = opts.context) !== null && _a !== void 0 ? _a : {})._) !== null && _b !== void 0 ? _b : LogBuiltInMetadata.Context.Uncategorized)),
|
|
651
663
|
subcontext: ((_c = opts.subcontext) !== null && _c !== void 0 ? _c : LogBuiltInMetadata.Context.Uncategorized),
|
|
652
|
-
|
|
653
|
-
|
|
664
|
+
level: ((_d = opts.level) !== null && _d !== void 0 ? _d : LogLevel$1.Info),
|
|
665
|
+
tags: JSON.stringify((_e = opts.tags) !== null && _e !== void 0 ? _e : []),
|
|
666
|
+
metadata: JSON.stringify((_f = opts.metadata) !== null && _f !== void 0 ? _f : {}),
|
|
654
667
|
errorMessage: (opts.error
|
|
655
668
|
? opts.error.message
|
|
656
669
|
: undefined),
|
|
@@ -661,7 +674,7 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
661
674
|
? opts.error.stack
|
|
662
675
|
: undefined),
|
|
663
676
|
target: (opts.action
|
|
664
|
-
? ((
|
|
677
|
+
? ((_g = opts.target) !== null && _g !== void 0 ? _g : LogBuiltInMetadata.Target.NoTarget)
|
|
665
678
|
: undefined),
|
|
666
679
|
action: (opts.action
|
|
667
680
|
? opts.action
|
|
@@ -1167,21 +1180,21 @@ const ButtonInputGroup = (props) => {
|
|
|
1167
1180
|
/*------------------------------------------------------------------------*/
|
|
1168
1181
|
/* -------------- Props ------------- */
|
|
1169
1182
|
// Destructure all props
|
|
1170
|
-
const { label, minLabelWidth, children, } = props;
|
|
1183
|
+
const { label, minLabelWidth, children, className, } = props;
|
|
1171
1184
|
/*------------------------------------------------------------------------*/
|
|
1172
1185
|
/* Render */
|
|
1173
1186
|
/*------------------------------------------------------------------------*/
|
|
1174
1187
|
/*----------------------------------------*/
|
|
1175
1188
|
/* Main UI */
|
|
1176
1189
|
/*----------------------------------------*/
|
|
1177
|
-
return (React.createElement("div", { className:
|
|
1190
|
+
return (React.createElement("div", { className: `input-group ${className !== null && className !== void 0 ? className : ''}` },
|
|
1178
1191
|
React.createElement("div", { className: "input-group-prepend d-flex w-100" },
|
|
1179
1192
|
React.createElement("span", { className: "input-group-text", style: {
|
|
1180
1193
|
minWidth: (minLabelWidth !== null && minLabelWidth !== void 0 ? minLabelWidth : undefined),
|
|
1181
1194
|
borderTopRightRadius: 0,
|
|
1182
1195
|
borderBottomRightRadius: 0,
|
|
1183
1196
|
} }, label),
|
|
1184
|
-
React.createElement("span", { className: "input-group-text flex-grow-1 rounded-right", style: {
|
|
1197
|
+
React.createElement("span", { className: "input-group-text flex-grow-1 rounded-right d-flex flex-wrap", style: {
|
|
1185
1198
|
backgroundColor: 'white',
|
|
1186
1199
|
borderTopLeftRadius: 0,
|
|
1187
1200
|
borderBottomLeftRadius: 0,
|
|
@@ -1344,12 +1357,25 @@ const SimpleDateChooser = (props) => {
|
|
|
1344
1357
|
// Figure out which days are allowed
|
|
1345
1358
|
const days = [];
|
|
1346
1359
|
const numDaysInMonth = (new Date(year, month, 0)).getDate();
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1360
|
+
if (chooseFromPast) {
|
|
1361
|
+
// Past selection
|
|
1362
|
+
const numDaysToAdd = ((month === today.month)
|
|
1363
|
+
? today.day // Current month, only add up to today
|
|
1364
|
+
: numDaysInMonth // Past month, add all days
|
|
1365
|
+
);
|
|
1366
|
+
for (let day = 1; day <= numDaysToAdd; day++) {
|
|
1367
|
+
days.push(day);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
else {
|
|
1371
|
+
// Future selection: add all remaining days of the month
|
|
1372
|
+
const firstDay = (month === today.month
|
|
1373
|
+
? today.day // Current month: start at current date
|
|
1374
|
+
: 1 // Future month: start at beginning of month
|
|
1375
|
+
);
|
|
1376
|
+
for (let day = firstDay; day <= numDaysInMonth; day++) {
|
|
1377
|
+
days.push(day);
|
|
1378
|
+
}
|
|
1353
1379
|
}
|
|
1354
1380
|
choices.push({
|
|
1355
1381
|
choiceName: `${monthName} ${year}`,
|
|
@@ -1420,14 +1446,16 @@ const Drawer = (props) => {
|
|
|
1420
1446
|
/*------------------------------------------------------------------------*/
|
|
1421
1447
|
/* -------------- Props ------------- */
|
|
1422
1448
|
// Destructure all props
|
|
1423
|
-
const { children, } = props;
|
|
1449
|
+
const { customBackgroundColor, children, } = props;
|
|
1424
1450
|
/*------------------------------------------------------------------------*/
|
|
1425
1451
|
/* Render */
|
|
1426
1452
|
/*------------------------------------------------------------------------*/
|
|
1427
1453
|
/*----------------------------------------*/
|
|
1428
1454
|
/* Main UI */
|
|
1429
1455
|
/*----------------------------------------*/
|
|
1430
|
-
return (React.createElement("div", { className: "Drawer-container"
|
|
1456
|
+
return (React.createElement("div", { className: "Drawer-container", style: {
|
|
1457
|
+
backgroundColor: (customBackgroundColor !== null && customBackgroundColor !== void 0 ? customBackgroundColor : undefined),
|
|
1458
|
+
} },
|
|
1431
1459
|
React.createElement("style", null, style$4),
|
|
1432
1460
|
children));
|
|
1433
1461
|
};
|
|
@@ -1890,24 +1918,25 @@ const CopiableBox = (props) => {
|
|
|
1890
1918
|
/**
|
|
1891
1919
|
* Reusable nested item picker
|
|
1892
1920
|
* @author Yuen Ler Chow
|
|
1921
|
+
* @author Gabe Abrams
|
|
1893
1922
|
*/
|
|
1894
1923
|
/* ------------- Actions ------------ */
|
|
1895
1924
|
// Types of actions
|
|
1896
1925
|
var ActionType$2;
|
|
1897
1926
|
(function (ActionType) {
|
|
1898
|
-
// Toggle whether
|
|
1899
|
-
ActionType["
|
|
1927
|
+
// Toggle whether a child are being shown
|
|
1928
|
+
ActionType["ToggleChild"] = "toggle-child";
|
|
1900
1929
|
})(ActionType$2 || (ActionType$2 = {}));
|
|
1901
1930
|
/**
|
|
1902
1931
|
* Reducer that executes actions
|
|
1903
|
-
* @author
|
|
1932
|
+
* @author Gabe Abrams
|
|
1904
1933
|
* @param state current state
|
|
1905
1934
|
* @param action action to execute
|
|
1906
1935
|
*/
|
|
1907
1936
|
const reducer$2 = (state, action) => {
|
|
1908
1937
|
switch (action.type) {
|
|
1909
|
-
case ActionType$2.
|
|
1910
|
-
return {
|
|
1938
|
+
case ActionType$2.ToggleChild: {
|
|
1939
|
+
return Object.assign(Object.assign({}, state), { childExpanded: Object.assign(Object.assign({}, state.childExpanded), { [String(action.id)]: !state.childExpanded[String(action.id)] }) });
|
|
1911
1940
|
}
|
|
1912
1941
|
default: {
|
|
1913
1942
|
return state;
|
|
@@ -1925,14 +1954,19 @@ const NestableItemList = (props) => {
|
|
|
1925
1954
|
// Destructure all props
|
|
1926
1955
|
const { items, onChanged, } = props;
|
|
1927
1956
|
/* -------------- State ------------- */
|
|
1957
|
+
// Create initial map of child expanded booleans
|
|
1958
|
+
const initChildExpanded = {};
|
|
1959
|
+
items.forEach((item) => {
|
|
1960
|
+
initChildExpanded[String(item.id)] = false;
|
|
1961
|
+
});
|
|
1928
1962
|
// Initial state
|
|
1929
1963
|
const initialState = {
|
|
1930
|
-
|
|
1964
|
+
childExpanded: initChildExpanded,
|
|
1931
1965
|
};
|
|
1932
1966
|
// Initialize state
|
|
1933
1967
|
const [state, dispatch] = useReducer(reducer$2, initialState);
|
|
1934
1968
|
// Destructure common state
|
|
1935
|
-
const {
|
|
1969
|
+
const { childExpanded, } = state;
|
|
1936
1970
|
/*------------------------------------------------------------------------*/
|
|
1937
1971
|
/* Component Functions */
|
|
1938
1972
|
/*------------------------------------------------------------------------*/
|
|
@@ -2020,14 +2054,15 @@ const NestableItemList = (props) => {
|
|
|
2020
2054
|
backgroundColor: 'transparent',
|
|
2021
2055
|
}, type: "button", onClick: () => {
|
|
2022
2056
|
dispatch({
|
|
2023
|
-
type: ActionType$2.
|
|
2057
|
+
type: ActionType$2.ToggleChild,
|
|
2058
|
+
id: item.id,
|
|
2024
2059
|
});
|
|
2025
|
-
}, "aria-label": `${
|
|
2026
|
-
React.createElement(FontAwesomeIcon, { icon:
|
|
2060
|
+
}, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}` },
|
|
2061
|
+
React.createElement(FontAwesomeIcon, { icon: childExpanded[item.id] ? faChevronDown : faChevronRight })))),
|
|
2027
2062
|
React.createElement(CheckboxButton, { className: `NestableItemList-CheckboxButton-${item.id}`, text: item.name, checked: item.isGroup ? allChecked(item.children) : item.checked, dashed: item.isGroup ? !noneChecked(item.children) : false, onChanged: (checked) => {
|
|
2028
2063
|
onChanged(changeChecked(item.id, checked, items));
|
|
2029
2064
|
}, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$1.Light }),
|
|
2030
|
-
item.isGroup &&
|
|
2065
|
+
(item.isGroup && childExpanded[item.id]) && (React.createElement("div", { className: "NestableItemList-children-container", style: {
|
|
2031
2066
|
paddingLeft: '2.2rem',
|
|
2032
2067
|
} },
|
|
2033
2068
|
React.createElement(NestableItemList, { items: item.children, onChanged: (updatedItems) => {
|
|
@@ -2049,7 +2084,7 @@ const ItemPicker = (props) => {
|
|
|
2049
2084
|
/*------------------------------------------------------------------------*/
|
|
2050
2085
|
/* -------------- Props ------------- */
|
|
2051
2086
|
// Destructure all props
|
|
2052
|
-
const { title, items, onChanged, } = props;
|
|
2087
|
+
const { title, items, onChanged, noBottomMargin, } = props;
|
|
2053
2088
|
/*------------------------------------------------------------------------*/
|
|
2054
2089
|
/* Component Functions */
|
|
2055
2090
|
/*------------------------------------------------------------------------*/
|
|
@@ -2059,7 +2094,7 @@ const ItemPicker = (props) => {
|
|
|
2059
2094
|
/*----------------------------------------*/
|
|
2060
2095
|
/* Main UI */
|
|
2061
2096
|
/*----------------------------------------*/
|
|
2062
|
-
return (React.createElement(TabBox, { title: title },
|
|
2097
|
+
return (React.createElement(TabBox, { title: title, noBottomMargin: noBottomMargin },
|
|
2063
2098
|
React.createElement("div", { style: { overflowX: 'auto' } },
|
|
2064
2099
|
React.createElement(NestableItemList, { items: items, onChanged: onChanged }))));
|
|
2065
2100
|
};
|
|
@@ -2103,37 +2138,37 @@ var LogType$1 = LogType;
|
|
|
2103
2138
|
var LogAction;
|
|
2104
2139
|
(function (LogAction) {
|
|
2105
2140
|
// Target was opened by the user (it was not on screen, but now it is)
|
|
2106
|
-
LogAction["Open"] = "
|
|
2141
|
+
LogAction["Open"] = "Open";
|
|
2107
2142
|
// Target was closed by the user (it was on screen, but now it is not)
|
|
2108
|
-
LogAction["Close"] = "
|
|
2143
|
+
LogAction["Close"] = "Close";
|
|
2109
2144
|
// Target was cancelled by the user (it was on closed without saving)
|
|
2110
|
-
LogAction["Cancel"] = "
|
|
2145
|
+
LogAction["Cancel"] = "Cancel";
|
|
2111
2146
|
// Target was expanded by the user (it always remains on screen, but size was changed)
|
|
2112
|
-
LogAction["Expand"] = "
|
|
2147
|
+
LogAction["Expand"] = "Expand";
|
|
2113
2148
|
// Target was collapsed by the user (it always remains on screen, but size was changed)
|
|
2114
|
-
LogAction["Collapse"] = "
|
|
2149
|
+
LogAction["Collapse"] = "Collapse";
|
|
2115
2150
|
// Target was viewed by the user (only for items that are not opened or closed, those must use Open/Close actions)
|
|
2116
|
-
LogAction["View"] = "
|
|
2151
|
+
LogAction["View"] = "View";
|
|
2117
2152
|
// Target interrupted the user (popup, dialog, validation message, etc. appeared without user prompting)
|
|
2118
|
-
LogAction["Interrupt"] = "
|
|
2153
|
+
LogAction["Interrupt"] = "Interrupt";
|
|
2119
2154
|
// Target was created by the user (it did not exist before)
|
|
2120
|
-
LogAction["Create"] = "
|
|
2155
|
+
LogAction["Create"] = "Create";
|
|
2121
2156
|
// Target was edited by the user (it existed and was changed)
|
|
2122
|
-
LogAction["Edit"] = "
|
|
2157
|
+
LogAction["Edit"] = "Edit";
|
|
2123
2158
|
// Target was deleted by the user (it existed and now it doesn't)
|
|
2124
|
-
LogAction["Delete"] = "
|
|
2159
|
+
LogAction["Delete"] = "Delete";
|
|
2125
2160
|
// Target was added by the user (it already existed and was added to another place)
|
|
2126
|
-
LogAction["Add"] = "
|
|
2161
|
+
LogAction["Add"] = "Add";
|
|
2127
2162
|
// Target was removed by the user (it was removed from something but still exists)
|
|
2128
|
-
LogAction["Remove"] = "
|
|
2163
|
+
LogAction["Remove"] = "Remove";
|
|
2129
2164
|
// Target was activated by the user (click, check, tap, keypress, etc.)
|
|
2130
|
-
LogAction["Activate"] = "
|
|
2165
|
+
LogAction["Activate"] = "Activate";
|
|
2131
2166
|
// Target was deactivated by the user (click away, uncheck, tap outside of, tab away, etc.)
|
|
2132
|
-
LogAction["Deactivate"] = "
|
|
2167
|
+
LogAction["Deactivate"] = "Deactivate";
|
|
2133
2168
|
// User showed interest in a target (hover, peek, etc.)
|
|
2134
|
-
LogAction["Peek"] = "
|
|
2169
|
+
LogAction["Peek"] = "Peek";
|
|
2135
2170
|
// Unknown action
|
|
2136
|
-
LogAction["Unknown"] = "
|
|
2171
|
+
LogAction["Unknown"] = "Unknown";
|
|
2137
2172
|
})(LogAction || (LogAction = {}));
|
|
2138
2173
|
var LogAction$1 = LogAction;
|
|
2139
2174
|
|
|
@@ -2175,12 +2210,12 @@ const roundToNumDecimals = (num, numDecimals) => {
|
|
|
2175
2210
|
* @returns escaped cell text
|
|
2176
2211
|
*/
|
|
2177
2212
|
const escapeCellText = (text) => {
|
|
2178
|
-
if (!text.includes(',')) {
|
|
2213
|
+
if (!String(text).includes(',')) {
|
|
2179
2214
|
// No need to escape
|
|
2180
|
-
return text;
|
|
2215
|
+
return String(text);
|
|
2181
2216
|
}
|
|
2182
2217
|
// Perform escape
|
|
2183
|
-
return `"${text.replace(/"/g, '""')}`;
|
|
2218
|
+
return `"${String(text).replace(/"/g, '""')}`;
|
|
2184
2219
|
};
|
|
2185
2220
|
/**
|
|
2186
2221
|
* Generate a CSV file
|
|
@@ -2201,7 +2236,23 @@ const genCSV = (data, columns) => {
|
|
|
2201
2236
|
data.forEach((datum) => {
|
|
2202
2237
|
csv += (columns
|
|
2203
2238
|
.map((column) => {
|
|
2204
|
-
|
|
2239
|
+
let contents;
|
|
2240
|
+
const cell = datum[column.param];
|
|
2241
|
+
if (typeof cell === 'string'
|
|
2242
|
+
|| typeof cell === 'number') {
|
|
2243
|
+
contents = String(cell);
|
|
2244
|
+
}
|
|
2245
|
+
else if (typeof cell === 'undefined'
|
|
2246
|
+
|| cell === null) {
|
|
2247
|
+
contents = '';
|
|
2248
|
+
}
|
|
2249
|
+
else if (typeof cell === 'object') {
|
|
2250
|
+
contents = JSON.stringify(cell);
|
|
2251
|
+
}
|
|
2252
|
+
else {
|
|
2253
|
+
contents = '';
|
|
2254
|
+
}
|
|
2255
|
+
return escapeCellText(contents);
|
|
2205
2256
|
})
|
|
2206
2257
|
.join(','));
|
|
2207
2258
|
});
|
|
@@ -2234,7 +2285,8 @@ const CSVDownloadButton = (props) => {
|
|
|
2234
2285
|
? `Click to download ${filename}`
|
|
2235
2286
|
: ariaLabel), style: style, onClick: onClick },
|
|
2236
2287
|
!children && (React.createElement(React.Fragment, null,
|
|
2237
|
-
React.createElement(FontAwesomeIcon, { icon: faCloudDownloadAlt
|
|
2288
|
+
React.createElement(FontAwesomeIcon, { icon: faCloudDownloadAlt }),
|
|
2289
|
+
' ',
|
|
2238
2290
|
"Download CSV")),
|
|
2239
2291
|
children));
|
|
2240
2292
|
};
|
|
@@ -2258,7 +2310,7 @@ var ActionType$1;
|
|
|
2258
2310
|
// Toggle sort column param
|
|
2259
2311
|
ActionType["ToggleSortColumn"] = "toggle-sort-column";
|
|
2260
2312
|
// Toggle the visibility of a column
|
|
2261
|
-
ActionType["
|
|
2313
|
+
ActionType["UpdateColumnVisibility"] = "update-column-visibility";
|
|
2262
2314
|
// Toggle the column visibility customization modal
|
|
2263
2315
|
ActionType["ToggleColVisCusModalVisibility"] = "toggle-col-vis-cus-modal-visibility";
|
|
2264
2316
|
})(ActionType$1 || (ActionType$1 = {}));
|
|
@@ -2282,9 +2334,9 @@ const reducer$1 = (state, action) => {
|
|
|
2282
2334
|
// Stop sorting by column
|
|
2283
2335
|
return Object.assign(Object.assign({}, state), { sortColumnParam: undefined, sortType: SortType.Ascending });
|
|
2284
2336
|
}
|
|
2285
|
-
case ActionType$1.
|
|
2337
|
+
case ActionType$1.UpdateColumnVisibility: {
|
|
2286
2338
|
const { columnVisibilityMap } = state;
|
|
2287
|
-
columnVisibilityMap[action.param] =
|
|
2339
|
+
columnVisibilityMap[action.param] = action.visible;
|
|
2288
2340
|
return Object.assign(Object.assign({}, state), { columnVisibilityMap });
|
|
2289
2341
|
}
|
|
2290
2342
|
case ActionType$1.ToggleColVisCusModalVisibility: {
|
|
@@ -2305,7 +2357,11 @@ const IntelliTable = (props) => {
|
|
|
2305
2357
|
var _a;
|
|
2306
2358
|
/* -------------- Props ------------- */
|
|
2307
2359
|
// Destructure all props
|
|
2308
|
-
const { title, id,
|
|
2360
|
+
const { title, id, columns, } = props;
|
|
2361
|
+
// Get data, show empty row if none
|
|
2362
|
+
const data = ((props.data && props.data.length > 0)
|
|
2363
|
+
? props.data
|
|
2364
|
+
: [{ id: 'empty-row' }]);
|
|
2309
2365
|
/* -------------- State ------------- */
|
|
2310
2366
|
// Initial state
|
|
2311
2367
|
const initColumnVisibilityMap = {};
|
|
@@ -2322,20 +2378,29 @@ const IntelliTable = (props) => {
|
|
|
2322
2378
|
const [state, dispatch] = useReducer(reducer$1, initialState);
|
|
2323
2379
|
// Destructure common state
|
|
2324
2380
|
const { sortColumnParam, sortType, columnVisibilityMap, columnVisibilityCustomizationModalVisible, } = state;
|
|
2381
|
+
/*------------------------------------------------------------------------*/
|
|
2382
|
+
/* Render */
|
|
2383
|
+
/*------------------------------------------------------------------------*/
|
|
2384
|
+
/*----------------------------------------*/
|
|
2385
|
+
/* Modal */
|
|
2386
|
+
/*----------------------------------------*/
|
|
2387
|
+
// Modal that may be defined
|
|
2388
|
+
let modal;
|
|
2325
2389
|
/* ------- Col Vis Customization Modal ------ */
|
|
2326
2390
|
if (columnVisibilityCustomizationModalVisible) {
|
|
2327
2391
|
// Create modal
|
|
2328
|
-
(React.createElement(Modal, { type: ModalType$1.Okay, title: "Choose columns to show:", onClose: () => {
|
|
2392
|
+
modal = (React.createElement(Modal, { type: ModalType$1.Okay, title: "Choose columns to show:", onClose: () => {
|
|
2329
2393
|
dispatch({
|
|
2330
2394
|
type: ActionType$1.ToggleColVisCusModalVisibility,
|
|
2331
2395
|
});
|
|
2332
|
-
} }, columns.map((column) => {
|
|
2333
|
-
return (React.createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, text: column.title, onChanged: () => {
|
|
2396
|
+
}, okayVariant: Variant$1.Light }, columns.map((column) => {
|
|
2397
|
+
return (React.createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, className: "mb-2", text: column.title, onChanged: (checked) => {
|
|
2334
2398
|
dispatch({
|
|
2335
|
-
type: ActionType$1.
|
|
2399
|
+
type: ActionType$1.UpdateColumnVisibility,
|
|
2336
2400
|
param: column.param,
|
|
2401
|
+
visible: checked,
|
|
2337
2402
|
});
|
|
2338
|
-
}, checked: columnVisibilityMap[column.param], ariaLabel: `show "${column.title}" column
|
|
2403
|
+
}, checked: columnVisibilityMap[column.param], ariaLabel: `show "${column.title}" column`, checkedVariant: Variant$1.Light, uncheckedVariant: Variant$1.Secondary }));
|
|
2339
2404
|
})));
|
|
2340
2405
|
}
|
|
2341
2406
|
/*----------------------------------------*/
|
|
@@ -2350,6 +2415,7 @@ const IntelliTable = (props) => {
|
|
|
2350
2415
|
// Custom info based on current sort type
|
|
2351
2416
|
let sortButtonAriaLabel;
|
|
2352
2417
|
let sortIcon = faSort;
|
|
2418
|
+
let sortingByThisColumn = false;
|
|
2353
2419
|
if (!sortColumnParam) {
|
|
2354
2420
|
// Not being sorted yet
|
|
2355
2421
|
sortButtonAriaLabel = `sort ascending by ${column.title}`;
|
|
@@ -2357,6 +2423,7 @@ const IntelliTable = (props) => {
|
|
|
2357
2423
|
}
|
|
2358
2424
|
else if (column.param === sortColumnParam) {
|
|
2359
2425
|
// Already sorted by this column
|
|
2426
|
+
sortingByThisColumn = true;
|
|
2360
2427
|
if (sortType === SortType.Ascending) {
|
|
2361
2428
|
// Sorted ascending
|
|
2362
2429
|
sortButtonAriaLabel = `sort descending by ${column.title}`;
|
|
@@ -2374,11 +2441,14 @@ const IntelliTable = (props) => {
|
|
|
2374
2441
|
sortIcon = faSort;
|
|
2375
2442
|
}
|
|
2376
2443
|
// Create the cell UI
|
|
2377
|
-
return (React.createElement("th", { key: column.param, scope: "col", id: `IntelliTable-${id}-header-${column.param}
|
|
2378
|
-
|
|
2379
|
-
|
|
2444
|
+
return (React.createElement("th", { key: column.param, scope: "col", id: `IntelliTable-${id}-header-${column.param}`, className: "text-start", style: {
|
|
2445
|
+
borderRight: '0.05rem solid #555',
|
|
2446
|
+
borderLeft: '0.05rem solid #555',
|
|
2447
|
+
} },
|
|
2448
|
+
React.createElement("div", { className: "d-flex align-items-center justify-content-start flex-row h-100" },
|
|
2449
|
+
React.createElement("span", { className: "text-nowrap" }, column.title),
|
|
2380
2450
|
React.createElement("div", null,
|
|
2381
|
-
React.createElement("button", { type: "button", className:
|
|
2451
|
+
React.createElement("button", { type: "button", id: `IntelliTable-${id}-sort-by-${column.param}-button`, className: `btn btn-${sortingByThisColumn ? 'light' : 'secondary'} btn-sm ms-1 ps-1 pe-1 pt-0 pb-0`, "aria-label": sortButtonAriaLabel, onClick: () => {
|
|
2382
2452
|
dispatch({
|
|
2383
2453
|
type: ActionType$1.ToggleSortColumn,
|
|
2384
2454
|
param: column.param,
|
|
@@ -2396,8 +2466,28 @@ const IntelliTable = (props) => {
|
|
|
2396
2466
|
const descending = (sortType === SortType.Descending);
|
|
2397
2467
|
if (sortColumnParam) {
|
|
2398
2468
|
sortedData.sort((a, b) => {
|
|
2469
|
+
var _a, _b;
|
|
2399
2470
|
const aVal = a[sortColumnParam];
|
|
2400
2471
|
const bVal = b[sortColumnParam];
|
|
2472
|
+
// Tiebreaker sort by timestamp, most recent first (used if tied)
|
|
2473
|
+
const tiebreaker = (((_a = b.timestamp) !== null && _a !== void 0 ? _a : 0)
|
|
2474
|
+
- ((_b = a.timestamp) !== null && _b !== void 0 ? _b : 0));
|
|
2475
|
+
// Auto-sort undefined and null to end of list
|
|
2476
|
+
if ((aVal === undefined || aVal === null)
|
|
2477
|
+
|| (bVal === undefined || bVal === null)) {
|
|
2478
|
+
// At least one was undefined
|
|
2479
|
+
if ((aVal === undefined || aVal === null)
|
|
2480
|
+
&& (bVal === undefined || bVal === null)) {
|
|
2481
|
+
// Both undefined
|
|
2482
|
+
return tiebreaker;
|
|
2483
|
+
}
|
|
2484
|
+
if (aVal === undefined || aVal === null) {
|
|
2485
|
+
// First was undefined
|
|
2486
|
+
return 1;
|
|
2487
|
+
}
|
|
2488
|
+
// Second was undefined
|
|
2489
|
+
return -1;
|
|
2490
|
+
}
|
|
2401
2491
|
// Sort differently based on the data type
|
|
2402
2492
|
// > Boolean
|
|
2403
2493
|
if (paramType === ParamType$1.Boolean) {
|
|
@@ -2407,7 +2497,7 @@ const IntelliTable = (props) => {
|
|
|
2407
2497
|
if (!aVal && bVal) {
|
|
2408
2498
|
return (descending ? 1 : -1);
|
|
2409
2499
|
}
|
|
2410
|
-
return
|
|
2500
|
+
return tiebreaker;
|
|
2411
2501
|
}
|
|
2412
2502
|
// > Number
|
|
2413
2503
|
if (paramType === ParamType$1.Int
|
|
@@ -2419,12 +2509,12 @@ const IntelliTable = (props) => {
|
|
|
2419
2509
|
// > String
|
|
2420
2510
|
if (paramType === ParamType$1.String) {
|
|
2421
2511
|
if (aVal < bVal) {
|
|
2422
|
-
return (descending ?
|
|
2512
|
+
return (descending ? 1 : -1);
|
|
2423
2513
|
}
|
|
2424
2514
|
if (aVal > bVal) {
|
|
2425
|
-
return (descending ? 1 :
|
|
2515
|
+
return (descending ? -1 : 1);
|
|
2426
2516
|
}
|
|
2427
|
-
return
|
|
2517
|
+
return tiebreaker;
|
|
2428
2518
|
}
|
|
2429
2519
|
// > JSON
|
|
2430
2520
|
if (paramType === ParamType$1.JSON) {
|
|
@@ -2439,7 +2529,7 @@ const IntelliTable = (props) => {
|
|
|
2439
2529
|
: (aSize - bSize));
|
|
2440
2530
|
}
|
|
2441
2531
|
// No sort
|
|
2442
|
-
return
|
|
2532
|
+
return tiebreaker;
|
|
2443
2533
|
});
|
|
2444
2534
|
}
|
|
2445
2535
|
// Table body
|
|
@@ -2464,9 +2554,12 @@ const IntelliTable = (props) => {
|
|
|
2464
2554
|
const noValue = (value === undefined
|
|
2465
2555
|
|| value === null);
|
|
2466
2556
|
visibleValue = (noValue
|
|
2467
|
-
? (React.createElement(FontAwesomeIcon, { icon:
|
|
2468
|
-
: (React.createElement(FontAwesomeIcon, { icon: faXmarkCircle })));
|
|
2557
|
+
? (React.createElement(FontAwesomeIcon, { icon: faMinus }))
|
|
2558
|
+
: (React.createElement(FontAwesomeIcon, { icon: fullValue ? faCheckCircle : faXmarkCircle })));
|
|
2469
2559
|
title = (fullValue ? 'True' : 'False');
|
|
2560
|
+
if (noValue) {
|
|
2561
|
+
title = 'Empty Cell';
|
|
2562
|
+
}
|
|
2470
2563
|
}
|
|
2471
2564
|
else if (column.type === ParamType$1.Int) {
|
|
2472
2565
|
fullValue = Number.parseInt(value, 10);
|
|
@@ -2475,6 +2568,9 @@ const IntelliTable = (props) => {
|
|
|
2475
2568
|
? (React.createElement(FontAwesomeIcon, { icon: faMinus }))
|
|
2476
2569
|
: fullValue);
|
|
2477
2570
|
title = String(fullValue);
|
|
2571
|
+
if (noValue) {
|
|
2572
|
+
title = 'Empty Cell';
|
|
2573
|
+
}
|
|
2478
2574
|
}
|
|
2479
2575
|
else if (column.type === ParamType$1.Float) {
|
|
2480
2576
|
fullValue = Number.parseFloat(value);
|
|
@@ -2483,14 +2579,22 @@ const IntelliTable = (props) => {
|
|
|
2483
2579
|
? (React.createElement(FontAwesomeIcon, { icon: faMinus }))
|
|
2484
2580
|
: roundToNumDecimals(fullValue, 2));
|
|
2485
2581
|
title = String(fullValue);
|
|
2582
|
+
if (noValue) {
|
|
2583
|
+
title = 'Empty Cell';
|
|
2584
|
+
}
|
|
2486
2585
|
}
|
|
2487
2586
|
else if (column.type === ParamType$1.String) {
|
|
2488
2587
|
fullValue = String(value).trim();
|
|
2489
|
-
const noValue = (value
|
|
2588
|
+
const noValue = (value === undefined
|
|
2589
|
+
|| value === null
|
|
2590
|
+
|| String(fullValue).trim().length === 0);
|
|
2490
2591
|
visibleValue = (noValue
|
|
2491
2592
|
? (React.createElement(FontAwesomeIcon, { icon: faMinus }))
|
|
2492
2593
|
: fullValue);
|
|
2493
2594
|
title = `"${value}"`;
|
|
2595
|
+
if (noValue) {
|
|
2596
|
+
title = 'Empty Cell';
|
|
2597
|
+
}
|
|
2494
2598
|
}
|
|
2495
2599
|
else if (column.type === ParamType$1.JSON) {
|
|
2496
2600
|
fullValue = JSON.stringify(value);
|
|
@@ -2500,9 +2604,13 @@ const IntelliTable = (props) => {
|
|
|
2500
2604
|
visibleValue = (noValue
|
|
2501
2605
|
? (React.createElement(FontAwesomeIcon, { icon: faMinus }))
|
|
2502
2606
|
: fullValue);
|
|
2607
|
+
title = "JSON Object";
|
|
2503
2608
|
}
|
|
2504
2609
|
// Create UI
|
|
2505
|
-
return (React.createElement("td", { key: `${datum.id}-${column.param}`, title: title
|
|
2610
|
+
return (React.createElement("td", { key: `${datum.id}-${column.param}`, title: title, style: {
|
|
2611
|
+
borderRight: '0.05rem solid #555',
|
|
2612
|
+
borderLeft: '0.05rem solid #555',
|
|
2613
|
+
} }, visibleValue));
|
|
2506
2614
|
}));
|
|
2507
2615
|
// Add cells to a row
|
|
2508
2616
|
return (React.createElement("tr", { key: datum.id }, cells));
|
|
@@ -2522,11 +2630,12 @@ const IntelliTable = (props) => {
|
|
|
2522
2630
|
const csv = genCSV(data, columns);
|
|
2523
2631
|
// Build main UI
|
|
2524
2632
|
return (React.createElement("div", { className: `IntelliTable-container-${id}` },
|
|
2525
|
-
|
|
2633
|
+
modal,
|
|
2634
|
+
React.createElement("div", { className: "d-flex align-items-center justify-content-start" },
|
|
2526
2635
|
React.createElement("h3", { className: "m-0" }, title),
|
|
2527
2636
|
React.createElement("div", { className: "flex-grow-1 text-end" },
|
|
2528
2637
|
React.createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: `${title}.csv`, csv: csv }),
|
|
2529
|
-
React.createElement("button", { type: "button", className: "btn btn-secondary", "aria-label": `show panel for customizing which columns show in table ${title}`, id: `IntelliTable-${id}-show-column-customization-modal`, onClick: () => {
|
|
2638
|
+
React.createElement("button", { type: "button", className: "btn btn-secondary ms-2", "aria-label": `show panel for customizing which columns show in table ${title}`, id: `IntelliTable-${id}-show-column-customization-modal`, onClick: () => {
|
|
2530
2639
|
dispatch({
|
|
2531
2640
|
type: ActionType$1.ToggleColVisCusModalVisibility,
|
|
2532
2641
|
});
|
|
@@ -2538,7 +2647,7 @@ const IntelliTable = (props) => {
|
|
|
2538
2647
|
numHiddenCols,
|
|
2539
2648
|
' ',
|
|
2540
2649
|
"hidden)"))))),
|
|
2541
|
-
React.createElement("div", { className: `IntelliTable-table-${id}`, style: {
|
|
2650
|
+
React.createElement("div", { className: `IntelliTable-table-${id} mt-2`, style: {
|
|
2542
2651
|
overflowX: 'auto',
|
|
2543
2652
|
} }, table)));
|
|
2544
2653
|
};
|
|
@@ -2590,6 +2699,11 @@ const style = `
|
|
|
2590
2699
|
border: 0.05rem solid black;
|
|
2591
2700
|
border-radius: 0.5rem;
|
|
2592
2701
|
overflow: hidden;
|
|
2702
|
+
padding: 0.7rem;
|
|
2703
|
+
|
|
2704
|
+
/* Solid background */
|
|
2705
|
+
background-color: white;
|
|
2706
|
+
color: black;
|
|
2593
2707
|
|
|
2594
2708
|
/* Place contents in flex column */
|
|
2595
2709
|
flex-direction: column;
|
|
@@ -2616,6 +2730,27 @@ const style = `
|
|
|
2616
2730
|
/* Vertical scroll */
|
|
2617
2731
|
overflow-y: auto;
|
|
2618
2732
|
}
|
|
2733
|
+
|
|
2734
|
+
.LogReviewer-header-close-button {
|
|
2735
|
+
border: 0 !important;
|
|
2736
|
+
background-color: transparent !important;
|
|
2737
|
+
padding-top: 0 !important;
|
|
2738
|
+
padding-bottom: 0 !important;
|
|
2739
|
+
padding-right: 1em !important;
|
|
2740
|
+
margin: 0 !important;
|
|
2741
|
+
color: #444 !important;
|
|
2742
|
+
|
|
2743
|
+
right: 0 !important;
|
|
2744
|
+
position: absolute !important;
|
|
2745
|
+
}
|
|
2746
|
+
.LogReviewer-header-close-button:hover {
|
|
2747
|
+
border: 0 !important;
|
|
2748
|
+
background-color: transparent !important;
|
|
2749
|
+
padding-top: 0 !important;
|
|
2750
|
+
padding-bottom: 0 !important;
|
|
2751
|
+
margin: 0 !important;
|
|
2752
|
+
color: #000 !important;
|
|
2753
|
+
}
|
|
2619
2754
|
`;
|
|
2620
2755
|
/*------------------------------------------------------------------------*/
|
|
2621
2756
|
/* Static Functions */
|
|
@@ -2635,7 +2770,7 @@ const genHumanReadableName = (machineReadableName) => {
|
|
|
2635
2770
|
// Uppercase! Add a space before
|
|
2636
2771
|
humanReadableName += ' ';
|
|
2637
2772
|
}
|
|
2638
|
-
humanReadableName +=
|
|
2773
|
+
humanReadableName += char;
|
|
2639
2774
|
});
|
|
2640
2775
|
// Trim and return
|
|
2641
2776
|
return humanReadableName.trim();
|
|
@@ -2697,7 +2832,19 @@ const reducer = (state, action) => {
|
|
|
2697
2832
|
return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
|
|
2698
2833
|
}
|
|
2699
2834
|
case ActionType.UpdateTagFilterState: {
|
|
2700
|
-
|
|
2835
|
+
const { tagFilterState } = action;
|
|
2836
|
+
// Select all if every tag is deselected
|
|
2837
|
+
const numTagsSelected = (Object.values(tagFilterState)
|
|
2838
|
+
.filter((isSelected) => {
|
|
2839
|
+
return isSelected;
|
|
2840
|
+
})
|
|
2841
|
+
.length);
|
|
2842
|
+
if (numTagsSelected === 0) {
|
|
2843
|
+
Object.keys(tagFilterState).forEach((tag) => {
|
|
2844
|
+
tagFilterState[tag] = true;
|
|
2845
|
+
});
|
|
2846
|
+
}
|
|
2847
|
+
return Object.assign(Object.assign({}, state), { tagFilterState });
|
|
2701
2848
|
}
|
|
2702
2849
|
case ActionType.UpdateActionErrorFilterState: {
|
|
2703
2850
|
return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
|
|
@@ -2717,10 +2864,35 @@ const LogReviewer = (props) => {
|
|
|
2717
2864
|
/*------------------------------------------------------------------------*/
|
|
2718
2865
|
/* Setup */
|
|
2719
2866
|
/*------------------------------------------------------------------------*/
|
|
2720
|
-
var _a, _b, _c, _d, _e;
|
|
2867
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2721
2868
|
/* -------------- Props ------------- */
|
|
2722
2869
|
// Destructure props
|
|
2723
2870
|
const { LogMetadata, onClose, } = props;
|
|
2871
|
+
// Add built-in LogMetadata
|
|
2872
|
+
// > Add "uncategorized" subcontext to each context
|
|
2873
|
+
Object.keys((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {}).forEach((context) => {
|
|
2874
|
+
if (
|
|
2875
|
+
// Context exists
|
|
2876
|
+
LogMetadata.Context
|
|
2877
|
+
// Context has children already
|
|
2878
|
+
&& typeof LogMetadata.Context[context] !== 'string') {
|
|
2879
|
+
LogMetadata.Context[context][LogBuiltInMetadata.Context.Uncategorized] = (LogBuiltInMetadata.Context.Uncategorized);
|
|
2880
|
+
}
|
|
2881
|
+
});
|
|
2882
|
+
// > Add built-in contexts
|
|
2883
|
+
LogMetadata.Context = ((_b = LogMetadata.Context) !== null && _b !== void 0 ? _b : {});
|
|
2884
|
+
Object.keys(LogBuiltInMetadata.Context).forEach((context) => {
|
|
2885
|
+
if (LogMetadata.Context) {
|
|
2886
|
+
LogMetadata.Context[context] = context;
|
|
2887
|
+
}
|
|
2888
|
+
});
|
|
2889
|
+
// > Add built-in targets
|
|
2890
|
+
LogMetadata.Target = ((_c = LogMetadata.Target) !== null && _c !== void 0 ? _c : {});
|
|
2891
|
+
Object.keys(LogBuiltInMetadata.Target).forEach((target) => {
|
|
2892
|
+
if (LogMetadata.Target) {
|
|
2893
|
+
LogMetadata.Target[target] = target;
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2724
2896
|
/* -------------- State ------------- */
|
|
2725
2897
|
// Create initial date filter state
|
|
2726
2898
|
const today = getTimeInfoInET();
|
|
@@ -2740,26 +2912,30 @@ const LogReviewer = (props) => {
|
|
|
2740
2912
|
};
|
|
2741
2913
|
// Create initial context filter state
|
|
2742
2914
|
const initContextFilterState = {};
|
|
2743
|
-
Object.keys((
|
|
2915
|
+
Object.keys((_d = LogMetadata.Context) !== null && _d !== void 0 ? _d : {}).forEach((context) => {
|
|
2744
2916
|
var _a, _b;
|
|
2745
2917
|
const contextValue = ((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {})[context];
|
|
2746
2918
|
if (typeof contextValue === 'string') {
|
|
2747
|
-
// Case: no subcontexts
|
|
2919
|
+
// Case: no subcontexts, init as checked
|
|
2748
2920
|
initContextFilterState[contextValue] = true;
|
|
2749
2921
|
}
|
|
2750
2922
|
else {
|
|
2751
2923
|
// Case: subcontexts exist
|
|
2752
|
-
initContextFilterState[
|
|
2924
|
+
initContextFilterState[context] = {};
|
|
2753
2925
|
Object.values(((_b = LogMetadata.Context) !== null && _b !== void 0 ? _b : {})[context]).forEach((subcontext) => {
|
|
2754
|
-
|
|
2755
|
-
|
|
2926
|
+
// Skip self ("_")
|
|
2927
|
+
if (subcontext === '_') {
|
|
2928
|
+
return;
|
|
2929
|
+
}
|
|
2930
|
+
// Initialize as checked
|
|
2931
|
+
initContextFilterState[context][subcontext] = true;
|
|
2756
2932
|
});
|
|
2757
2933
|
}
|
|
2758
2934
|
});
|
|
2759
2935
|
// Create initial tag filter state
|
|
2760
2936
|
const initTagFilterState = {};
|
|
2761
|
-
Object.
|
|
2762
|
-
initTagFilterState[
|
|
2937
|
+
Object.keys((_e = LogMetadata.Tag) !== null && _e !== void 0 ? _e : {}).forEach((tag) => {
|
|
2938
|
+
initTagFilterState[tag] = false;
|
|
2763
2939
|
});
|
|
2764
2940
|
// Create advanced filter state
|
|
2765
2941
|
const initAdvancedFilterState = {
|
|
@@ -2785,12 +2961,16 @@ const LogReviewer = (props) => {
|
|
|
2785
2961
|
target: {},
|
|
2786
2962
|
action: {},
|
|
2787
2963
|
};
|
|
2788
|
-
Object.values((
|
|
2964
|
+
Object.values((_f = LogMetadata.Target) !== null && _f !== void 0 ? _f : {}).forEach((target) => {
|
|
2789
2965
|
initActionErrorFilterState.target[target] = true;
|
|
2790
2966
|
});
|
|
2791
2967
|
Object.values(LogAction$1).forEach((action) => {
|
|
2792
2968
|
initActionErrorFilterState.action[action] = true;
|
|
2793
2969
|
});
|
|
2970
|
+
// Add built-in targets
|
|
2971
|
+
Object.values(LogBuiltInMetadata.Target).forEach((target) => {
|
|
2972
|
+
initActionErrorFilterState.target[target] = true;
|
|
2973
|
+
});
|
|
2794
2974
|
// Initial state
|
|
2795
2975
|
const initialState = {
|
|
2796
2976
|
loading: true,
|
|
@@ -2824,15 +3004,18 @@ const LogReviewer = (props) => {
|
|
|
2824
3004
|
let month = newDateFilterState.startDate.month;
|
|
2825
3005
|
while (
|
|
2826
3006
|
// Earlier year
|
|
2827
|
-
(year
|
|
3007
|
+
(year < newDateFilterState.endDate.year)
|
|
2828
3008
|
// Current year but included month
|
|
2829
3009
|
|| (year === newDateFilterState.endDate.year
|
|
2830
3010
|
&& month <= newDateFilterState.endDate.month)) {
|
|
2831
|
-
// Add to list
|
|
2832
|
-
|
|
2833
|
-
year
|
|
2834
|
-
|
|
2835
|
-
|
|
3011
|
+
// Add to list if not already loaded
|
|
3012
|
+
if (!logMap[year]
|
|
3013
|
+
|| !logMap[year][month]) {
|
|
3014
|
+
toLoad.push({
|
|
3015
|
+
year,
|
|
3016
|
+
month,
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
2836
3019
|
// Increment
|
|
2837
3020
|
month += 1;
|
|
2838
3021
|
if (month > 12) {
|
|
@@ -2920,10 +3103,10 @@ const LogReviewer = (props) => {
|
|
|
2920
3103
|
/* Filters */
|
|
2921
3104
|
/*----------------------------------------*/
|
|
2922
3105
|
// Filter toggle
|
|
2923
|
-
const filterToggles = (React.createElement("div", { className: "LogReviewer-filter-toggles
|
|
3106
|
+
const filterToggles = (React.createElement("div", { className: "LogReviewer-filter-toggles" },
|
|
2924
3107
|
React.createElement("h3", { className: "m-0" }, "Filters:"),
|
|
2925
|
-
React.createElement("div", { className: "LogReviewer-filter-toggle-buttons" },
|
|
2926
|
-
React.createElement("button", { type: "button", id: "LogReviewer-toggle-date-filter-drawer", className: `btn btn-${FilterDrawer.Date === expandedFilterDrawer} me-2`, "aria-label": "toggle date filter drawer", onClick: () => {
|
|
3108
|
+
React.createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
|
|
3109
|
+
React.createElement("button", { type: "button", id: "LogReviewer-toggle-date-filter-drawer", className: `btn btn-${FilterDrawer.Date === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle date filter drawer", onClick: () => {
|
|
2927
3110
|
dispatch({
|
|
2928
3111
|
type: ActionType.ToggleFilterDrawer,
|
|
2929
3112
|
filterDrawer: FilterDrawer.Date,
|
|
@@ -2931,7 +3114,7 @@ const LogReviewer = (props) => {
|
|
|
2931
3114
|
} },
|
|
2932
3115
|
React.createElement(FontAwesomeIcon, { icon: faCalendar, className: "me-2" }),
|
|
2933
3116
|
"Date"),
|
|
2934
|
-
React.createElement("button", { type: "button", id: "LogReviewer-toggle-context-filter-drawer", className: `btn btn-${FilterDrawer.Context === expandedFilterDrawer} me-2`, "aria-label": "toggle context filter drawer", onClick: () => {
|
|
3117
|
+
React.createElement("button", { type: "button", id: "LogReviewer-toggle-context-filter-drawer", className: `btn btn-${FilterDrawer.Context === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle context filter drawer", onClick: () => {
|
|
2935
3118
|
dispatch({
|
|
2936
3119
|
type: ActionType.ToggleFilterDrawer,
|
|
2937
3120
|
filterDrawer: FilterDrawer.Context,
|
|
@@ -2939,15 +3122,15 @@ const LogReviewer = (props) => {
|
|
|
2939
3122
|
} },
|
|
2940
3123
|
React.createElement(FontAwesomeIcon, { icon: faCircle, className: "me-2" }),
|
|
2941
3124
|
"Context"),
|
|
2942
|
-
React.createElement("button", { type: "button", id: "LogReviewer-toggle-tag-filter-drawer", className: `btn btn-${FilterDrawer.Tag === expandedFilterDrawer} me-2`, "aria-label": "toggle tag filter drawer", onClick: () => {
|
|
3125
|
+
(LogMetadata.Tag && Object.keys(LogMetadata.Tag).length > 0) && (React.createElement("button", { type: "button", id: "LogReviewer-toggle-tag-filter-drawer", className: `btn btn-${FilterDrawer.Tag === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle tag filter drawer", onClick: () => {
|
|
2943
3126
|
dispatch({
|
|
2944
3127
|
type: ActionType.ToggleFilterDrawer,
|
|
2945
3128
|
filterDrawer: FilterDrawer.Tag,
|
|
2946
3129
|
});
|
|
2947
3130
|
} },
|
|
2948
3131
|
React.createElement(FontAwesomeIcon, { icon: faTag, className: "me-2" }),
|
|
2949
|
-
"Tag"),
|
|
2950
|
-
React.createElement("button", { type: "button", id: "LogReviewer-toggle-action-filter-drawer", className: `btn btn-${FilterDrawer.Action === expandedFilterDrawer} me-2`, "aria-label": "toggle action and error filter drawer", onClick: () => {
|
|
3132
|
+
"Tag")),
|
|
3133
|
+
React.createElement("button", { type: "button", id: "LogReviewer-toggle-action-filter-drawer", className: `btn btn-${FilterDrawer.Action === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle action and error filter drawer", onClick: () => {
|
|
2951
3134
|
dispatch({
|
|
2952
3135
|
type: ActionType.ToggleFilterDrawer,
|
|
2953
3136
|
filterDrawer: FilterDrawer.Action,
|
|
@@ -2955,7 +3138,7 @@ const LogReviewer = (props) => {
|
|
|
2955
3138
|
} },
|
|
2956
3139
|
React.createElement(FontAwesomeIcon, { icon: faHammer, className: "me-2" }),
|
|
2957
3140
|
"Action"),
|
|
2958
|
-
React.createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer}`, "aria-label": "toggle advanced filter drawer", onClick: () => {
|
|
3141
|
+
React.createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer ? 'warning' : 'light'}`, "aria-label": "toggle advanced filter drawer", onClick: () => {
|
|
2959
3142
|
dispatch({
|
|
2960
3143
|
type: ActionType.ToggleFilterDrawer,
|
|
2961
3144
|
filterDrawer: FilterDrawer.Advanced,
|
|
@@ -2968,25 +3151,29 @@ const LogReviewer = (props) => {
|
|
|
2968
3151
|
if (expandedFilterDrawer) {
|
|
2969
3152
|
if (expandedFilterDrawer === FilterDrawer.Date) {
|
|
2970
3153
|
filterDrawer = (React.createElement(TabBox, { title: "Date" },
|
|
2971
|
-
React.createElement(SimpleDateChooser, { ariaLabel: "filter start date", name: "filter-start-date", year: dateFilterState.startDate.year, month: dateFilterState.startDate.month, day: dateFilterState.startDate.day, onChange: (month, day, year) => {
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
dateFilterState: Object.assign(Object.assign({}, dateFilterState), { startDate: { month, day, year } }),
|
|
2975
|
-
});
|
|
3154
|
+
React.createElement(SimpleDateChooser, { ariaLabel: "filter start date", name: "filter-start-date", year: dateFilterState.startDate.year, month: dateFilterState.startDate.month, day: dateFilterState.startDate.day, chooseFromPast: true, numMonthsToShow: 12, onChange: (month, day, year) => {
|
|
3155
|
+
dateFilterState.startDate = { month, day, year };
|
|
3156
|
+
handleDateRangeUpdated(dateFilterState);
|
|
2976
3157
|
} }),
|
|
2977
3158
|
' ',
|
|
2978
3159
|
"to",
|
|
2979
3160
|
' ',
|
|
2980
|
-
React.createElement(SimpleDateChooser, { ariaLabel: "filter end date", name: "filter-end-date", year: dateFilterState.endDate.year, month: dateFilterState.endDate.month, day: dateFilterState.endDate.day, onChange: (month, day, year) => {
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
3161
|
+
React.createElement(SimpleDateChooser, { ariaLabel: "filter end date", name: "filter-end-date", year: dateFilterState.endDate.year, month: dateFilterState.endDate.month, day: dateFilterState.endDate.day, chooseFromPast: true, numMonthsToShow: 12, onChange: (month, day, year) => {
|
|
3162
|
+
if (year < dateFilterState.startDate.year
|
|
3163
|
+
|| (year === dateFilterState.startDate.year
|
|
3164
|
+
&& month < dateFilterState.startDate.month)
|
|
3165
|
+
|| (year === dateFilterState.startDate.year
|
|
3166
|
+
&& month === dateFilterState.startDate.month
|
|
3167
|
+
&& day < dateFilterState.startDate.day)) {
|
|
3168
|
+
return alert$1('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
3169
|
+
}
|
|
3170
|
+
dateFilterState.endDate = { month, day, year };
|
|
3171
|
+
handleDateRangeUpdated(dateFilterState);
|
|
2985
3172
|
} })));
|
|
2986
3173
|
}
|
|
2987
3174
|
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
2988
3175
|
// Create item picker items
|
|
2989
|
-
const pickableItems = (Object.keys((
|
|
3176
|
+
const pickableItems = (Object.keys((_g = LogMetadata.Context) !== null && _g !== void 0 ? _g : {})
|
|
2990
3177
|
.map((context) => {
|
|
2991
3178
|
var _a;
|
|
2992
3179
|
const value = ((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {})[context];
|
|
@@ -3007,15 +3194,15 @@ const LogReviewer = (props) => {
|
|
|
3007
3194
|
})
|
|
3008
3195
|
.map((subcontext) => {
|
|
3009
3196
|
return {
|
|
3010
|
-
id:
|
|
3197
|
+
id: subcontext,
|
|
3011
3198
|
name: genHumanReadableName(subcontext),
|
|
3012
3199
|
isGroup: false,
|
|
3013
|
-
checked:
|
|
3200
|
+
checked: contextFilterState[context][subcontext],
|
|
3014
3201
|
};
|
|
3015
3202
|
}));
|
|
3016
3203
|
const item = {
|
|
3017
3204
|
id: context,
|
|
3018
|
-
name: context,
|
|
3205
|
+
name: genHumanReadableName(context),
|
|
3019
3206
|
isGroup: true,
|
|
3020
3207
|
children,
|
|
3021
3208
|
};
|
|
@@ -3028,7 +3215,9 @@ const LogReviewer = (props) => {
|
|
|
3028
3215
|
if (pickableItem.isGroup) {
|
|
3029
3216
|
// Has subcontexts
|
|
3030
3217
|
pickableItem.children.forEach((subcontextItem) => {
|
|
3031
|
-
|
|
3218
|
+
if (!subcontextItem.isGroup) {
|
|
3219
|
+
contextFilterState[pickableItem.id][subcontextItem.id] = (subcontextItem.checked);
|
|
3220
|
+
}
|
|
3032
3221
|
});
|
|
3033
3222
|
}
|
|
3034
3223
|
else {
|
|
@@ -3044,11 +3233,15 @@ const LogReviewer = (props) => {
|
|
|
3044
3233
|
}
|
|
3045
3234
|
else if (expandedFilterDrawer === FilterDrawer.Tag) {
|
|
3046
3235
|
// Create filter UI
|
|
3047
|
-
filterDrawer = (React.createElement(TabBox, { title: "Tags" }, Object.keys(
|
|
3236
|
+
filterDrawer = (React.createElement(TabBox, { title: "Tags" }, Object.keys((_h = LogMetadata.Tag) !== null && _h !== void 0 ? _h : {})
|
|
3048
3237
|
.map((tag, i) => {
|
|
3049
3238
|
const description = genHumanReadableName(tag);
|
|
3050
|
-
return (React.createElement(CheckboxButton, { id: `LogReviewer-tag-${tag}-checkbox`, text: description, ariaLabel: `
|
|
3239
|
+
return (React.createElement(CheckboxButton, { id: `LogReviewer-tag-${tag}-checkbox`, text: description, ariaLabel: `require that logs be tagged with "${description}" or any other selected tag`, noMarginOnRight: i === Object.keys(tagFilterState).length - 1, checked: tagFilterState[tag], onChanged: (checked) => {
|
|
3051
3240
|
tagFilterState[tag] = checked;
|
|
3241
|
+
dispatch({
|
|
3242
|
+
type: ActionType.UpdateTagFilterState,
|
|
3243
|
+
tagFilterState,
|
|
3244
|
+
});
|
|
3052
3245
|
} }));
|
|
3053
3246
|
})));
|
|
3054
3247
|
}
|
|
@@ -3079,29 +3272,33 @@ const LogReviewer = (props) => {
|
|
|
3079
3272
|
}, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
|
|
3080
3273
|
(actionErrorFilterState.type === undefined
|
|
3081
3274
|
|| actionErrorFilterState.type === LogType$1.Action) && (React.createElement(TabBox, { title: "Action Log Details" },
|
|
3082
|
-
React.createElement(ButtonInputGroup, { label: "Action" }, Object.keys(LogAction$1)
|
|
3275
|
+
React.createElement(ButtonInputGroup, { label: "Action", className: "mb-2" }, Object.keys(LogAction$1)
|
|
3083
3276
|
.map((action, i) => {
|
|
3084
3277
|
const description = genHumanReadableName(action);
|
|
3085
|
-
return (React.createElement(CheckboxButton, { id: `LogReviewer-action-${action}-checkbox`, text: description, ariaLabel: `include logs with action type "${description}" in results`, noMarginOnRight: i === Object.keys(LogAction$1).length - 1, onChanged: (checked) => {
|
|
3278
|
+
return (React.createElement(CheckboxButton, { key: action, id: `LogReviewer-action-${action}-checkbox`, text: description, ariaLabel: `include logs with action type "${description}" in results`, noMarginOnRight: i === Object.keys(LogAction$1).length - 1, checked: actionErrorFilterState.action[action], onChanged: (checked) => {
|
|
3086
3279
|
actionErrorFilterState.action[action] = checked;
|
|
3280
|
+
console.log(actionErrorFilterState, action, checked);
|
|
3087
3281
|
dispatch({
|
|
3088
3282
|
type: ActionType.UpdateActionErrorFilterState,
|
|
3089
3283
|
actionErrorFilterState,
|
|
3090
3284
|
});
|
|
3091
3285
|
} }));
|
|
3092
3286
|
})),
|
|
3093
|
-
React.createElement(ButtonInputGroup, { label: "Target" },
|
|
3094
|
-
.
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
actionErrorFilterState,
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3287
|
+
React.createElement(ButtonInputGroup, { label: "Target" },
|
|
3288
|
+
(Object.keys((_j = LogMetadata.Target) !== null && _j !== void 0 ? _j : {}).length === 0) && (React.createElement("div", null, "This app does not have any targets yet.")),
|
|
3289
|
+
Object.keys((_k = LogMetadata.Target) !== null && _k !== void 0 ? _k : {})
|
|
3290
|
+
.map((target, i) => {
|
|
3291
|
+
var _a;
|
|
3292
|
+
const description = genHumanReadableName(target);
|
|
3293
|
+
return (React.createElement(CheckboxButton, { key: target, id: `LogReviewer-target-${target}-checkbox`, text: description, ariaLabel: `include logs with target "${description}" in results`, checked: actionErrorFilterState.target[target], onChanged: (checked) => {
|
|
3294
|
+
actionErrorFilterState.target[target] = checked;
|
|
3295
|
+
console.log(actionErrorFilterState, target, checked);
|
|
3296
|
+
dispatch({
|
|
3297
|
+
type: ActionType.UpdateActionErrorFilterState,
|
|
3298
|
+
actionErrorFilterState,
|
|
3299
|
+
});
|
|
3300
|
+
}, noMarginOnRight: i === Object.keys((_a = LogMetadata.Target) !== null && _a !== void 0 ? _a : {}).length - 1 }));
|
|
3301
|
+
})))),
|
|
3105
3302
|
(actionErrorFilterState.type === undefined
|
|
3106
3303
|
|| actionErrorFilterState.type === LogType$1.Error) && (React.createElement(TabBox, { title: "Error Log Details" },
|
|
3107
3304
|
React.createElement("div", { className: "input-group mb-2" },
|
|
@@ -3115,7 +3312,7 @@ const LogReviewer = (props) => {
|
|
|
3115
3312
|
} })),
|
|
3116
3313
|
React.createElement("div", { className: "input-group mb-2" },
|
|
3117
3314
|
React.createElement("span", { className: "input-group-text" }, "Error Code"),
|
|
3118
|
-
React.createElement("input", { type: "text", className: "form-control", "aria-label": "query for error code", value: actionErrorFilterState.
|
|
3315
|
+
React.createElement("input", { type: "text", className: "form-control", "aria-label": "query for error code", value: actionErrorFilterState.errorCode, onChange: (e) => {
|
|
3119
3316
|
actionErrorFilterState.errorCode = ((e.target.value)
|
|
3120
3317
|
.trim()
|
|
3121
3318
|
.toUpperCase());
|
|
@@ -3263,37 +3460,38 @@ const LogReviewer = (props) => {
|
|
|
3263
3460
|
advancedFilterState,
|
|
3264
3461
|
});
|
|
3265
3462
|
}, noMarginOnRight: true })),
|
|
3266
|
-
React.createElement("div", { className: "
|
|
3267
|
-
React.createElement("
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
.
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
React.createElement("
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
.
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3463
|
+
advancedFilterState.source !== LogSource$1.Client && (React.createElement("div", { className: "mt-2" },
|
|
3464
|
+
React.createElement("div", { className: "input-group mb-2" },
|
|
3465
|
+
React.createElement("span", { className: "input-group-text" }, "Server Route Path"),
|
|
3466
|
+
React.createElement("input", { type: "text", className: "form-control", "aria-label": "query for server route path", placeholder: "e.g. /api/ttm/courses/12345", value: advancedFilterState.routePath, onChange: (e) => {
|
|
3467
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
3468
|
+
.trim());
|
|
3469
|
+
dispatch({
|
|
3470
|
+
type: ActionType.UpdateAdvancedFilterState,
|
|
3471
|
+
advancedFilterState,
|
|
3472
|
+
});
|
|
3473
|
+
} })),
|
|
3474
|
+
React.createElement("div", { className: "input-group mb-2" },
|
|
3475
|
+
React.createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
3476
|
+
React.createElement("input", { type: "text", className: "form-control", "aria-label": "query for server route template", value: advancedFilterState.routeTemplate, placeholder: "e.g. /api/ttm/courses/:courseId", onChange: (e) => {
|
|
3477
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
3478
|
+
.trim());
|
|
3479
|
+
dispatch({
|
|
3480
|
+
type: ActionType.UpdateAdvancedFilterState,
|
|
3481
|
+
advancedFilterState,
|
|
3482
|
+
});
|
|
3483
|
+
} })))))));
|
|
3286
3484
|
}
|
|
3287
3485
|
}
|
|
3288
3486
|
// Filters UI
|
|
3289
3487
|
const filters = (React.createElement(React.Fragment, null,
|
|
3290
3488
|
filterToggles,
|
|
3291
|
-
filterDrawer && (React.createElement(Drawer,
|
|
3489
|
+
filterDrawer && (React.createElement(Drawer, { customBackgroundColor: "#eee" }, filterDrawer))));
|
|
3292
3490
|
// Actually filter the logs
|
|
3293
3491
|
// > Perform filters
|
|
3294
3492
|
const logs = [];
|
|
3295
3493
|
Object.keys(logMap).forEach((year) => {
|
|
3296
|
-
Object.keys(logMap).forEach((month) => {
|
|
3494
|
+
Object.keys(logMap[year]).forEach((month) => {
|
|
3297
3495
|
logMap[year][month].forEach((log) => {
|
|
3298
3496
|
/* ----------- Date Filter ---------- */
|
|
3299
3497
|
var _a;
|
|
@@ -3329,16 +3527,23 @@ const LogReviewer = (props) => {
|
|
|
3329
3527
|
// Whole context is deselected
|
|
3330
3528
|
contextFilterState[log.context] === false
|
|
3331
3529
|
// None of the subcontexts are selected
|
|
3332
|
-
|| (
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3530
|
+
|| (
|
|
3531
|
+
// Has subcontexts
|
|
3532
|
+
typeof contextFilterState[log.context] !== 'boolean'
|
|
3533
|
+
// None of the subcontexts are selected
|
|
3534
|
+
&& Object.values((_a = contextFilterState[log.context]) !== null && _a !== void 0 ? _a : {})
|
|
3535
|
+
.every((isSelected) => {
|
|
3536
|
+
return !isSelected;
|
|
3537
|
+
}))) {
|
|
3538
|
+
console.log(log.context, contextFilterState);
|
|
3336
3539
|
return;
|
|
3337
3540
|
}
|
|
3338
3541
|
// Subcontext doesn't match
|
|
3339
3542
|
if (
|
|
3340
|
-
// Log
|
|
3341
|
-
log.
|
|
3543
|
+
// Log context is not "uncategorized" (no point in further filters)
|
|
3544
|
+
log.context !== LogBuiltInMetadata.Context.Uncategorized
|
|
3545
|
+
// Log has a subcontext
|
|
3546
|
+
&& log.subcontext
|
|
3342
3547
|
// Context has subcontexts
|
|
3343
3548
|
&& (contextFilterState[log.context]
|
|
3344
3549
|
&& contextFilterState[log.context] !== false
|
|
@@ -3350,12 +3555,16 @@ const LogReviewer = (props) => {
|
|
|
3350
3555
|
/* -------------- Tags -------------- */
|
|
3351
3556
|
// No tags match
|
|
3352
3557
|
if (
|
|
3353
|
-
//
|
|
3354
|
-
|
|
3558
|
+
// At least one tag is required
|
|
3559
|
+
Object.values(tagFilterState)
|
|
3560
|
+
.filter((isSelected) => {
|
|
3561
|
+
return isSelected;
|
|
3562
|
+
})
|
|
3563
|
+
.length > 0
|
|
3355
3564
|
// No tags match
|
|
3356
|
-
&&
|
|
3565
|
+
&& log.tags.every((tag) => {
|
|
3357
3566
|
return !tagFilterState[tag];
|
|
3358
|
-
}))
|
|
3567
|
+
})) {
|
|
3359
3568
|
return;
|
|
3360
3569
|
}
|
|
3361
3570
|
/* ------- Actions and Errors ------- */
|
|
@@ -3489,7 +3698,7 @@ const LogReviewer = (props) => {
|
|
|
3489
3698
|
// Device info exists
|
|
3490
3699
|
&& log.device
|
|
3491
3700
|
// Mobile filter doesn't match
|
|
3492
|
-
&& (advancedFilterState.isMobile
|
|
3701
|
+
&& (advancedFilterState.isMobile !== log.device.isMobile)) {
|
|
3493
3702
|
return;
|
|
3494
3703
|
}
|
|
3495
3704
|
// Log source doesn't match
|
|
@@ -3554,18 +3763,18 @@ const LogReviewer = (props) => {
|
|
|
3554
3763
|
type: ParamType$1.Int,
|
|
3555
3764
|
},
|
|
3556
3765
|
{
|
|
3557
|
-
title: 'Student',
|
|
3766
|
+
title: 'Student?',
|
|
3558
3767
|
param: 'isLearner',
|
|
3559
3768
|
type: ParamType$1.Boolean,
|
|
3560
3769
|
},
|
|
3561
3770
|
{
|
|
3562
|
-
title: 'Teaching Staff',
|
|
3771
|
+
title: 'Teaching Staff?',
|
|
3563
3772
|
param: 'isTTM',
|
|
3564
3773
|
type: ParamType$1.Boolean,
|
|
3565
3774
|
startsHidden: true,
|
|
3566
3775
|
},
|
|
3567
3776
|
{
|
|
3568
|
-
title: 'Admin',
|
|
3777
|
+
title: 'Admin?',
|
|
3569
3778
|
param: 'isAdmin',
|
|
3570
3779
|
type: ParamType$1.Boolean,
|
|
3571
3780
|
startsHidden: true,
|
|
@@ -3600,7 +3809,7 @@ const LogReviewer = (props) => {
|
|
|
3600
3809
|
startsHidden: true,
|
|
3601
3810
|
},
|
|
3602
3811
|
{
|
|
3603
|
-
title: 'Mobile',
|
|
3812
|
+
title: 'Mobile?',
|
|
3604
3813
|
param: 'device.isMobile',
|
|
3605
3814
|
type: ParamType$1.Boolean,
|
|
3606
3815
|
startsHidden: true,
|
|
@@ -3718,12 +3927,20 @@ const LogReviewer = (props) => {
|
|
|
3718
3927
|
startsHidden: true,
|
|
3719
3928
|
},
|
|
3720
3929
|
];
|
|
3930
|
+
// Nothing to show notice
|
|
3931
|
+
const noLogsNotice = (logs.length === 0
|
|
3932
|
+
? (React.createElement("div", { className: "alert alert-warning text-center mt-2" },
|
|
3933
|
+
React.createElement("h4", { className: "m-1" }, "No Logs to Show"),
|
|
3934
|
+
React.createElement("div", null, "Either your filters are too strict or no matching logs have been created yet.")))
|
|
3935
|
+
: undefined);
|
|
3721
3936
|
// Create intelliTable
|
|
3722
|
-
const dataTable = (React.createElement(IntelliTable, { title: "Matching Logs", id: "logs", data: logs, columns: columns }));
|
|
3937
|
+
const dataTable = (React.createElement(IntelliTable, { title: "Matching Logs:", id: "logs", data: logs, columns: columns }));
|
|
3723
3938
|
// Main body
|
|
3724
3939
|
body = (React.createElement(React.Fragment, null,
|
|
3725
3940
|
filters,
|
|
3726
|
-
|
|
3941
|
+
React.createElement("div", { className: "mt-2" },
|
|
3942
|
+
dataTable,
|
|
3943
|
+
noLogsNotice)));
|
|
3727
3944
|
}
|
|
3728
3945
|
/* ---------- Wrap in Modal --------- */
|
|
3729
3946
|
return (React.createElement("div", { className: "LogReviewer-outer-container" },
|
|
@@ -3731,14 +3948,10 @@ const LogReviewer = (props) => {
|
|
|
3731
3948
|
React.createElement("div", { className: "LogReviewer-inner-container" },
|
|
3732
3949
|
React.createElement("div", { className: "LogReviewer-header" },
|
|
3733
3950
|
React.createElement("div", { className: "LogReviewer-header-title" },
|
|
3734
|
-
React.createElement("
|
|
3735
|
-
React.createElement("
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
padding: 0,
|
|
3739
|
-
margin: 0,
|
|
3740
|
-
} },
|
|
3741
|
-
React.createElement(FontAwesomeIcon, { icon: faTimes }))),
|
|
3951
|
+
React.createElement("h3", { className: "text-center m-0" }, "Log Review Dashboard")),
|
|
3952
|
+
React.createElement("div", { style: { width: 0 } },
|
|
3953
|
+
React.createElement("button", { type: "button", className: "LogReviewer-header-close-button btn btn-dark btn-lg pe-0", "aria-label": "close log reviewer panel", onClick: onClose },
|
|
3954
|
+
React.createElement(FontAwesomeIcon, { icon: faTimes })))),
|
|
3742
3955
|
React.createElement("div", { className: "LogReviewer-contents" }, body))));
|
|
3743
3956
|
};
|
|
3744
3957
|
|
|
@@ -4062,22 +4275,24 @@ const initServer = (opts) => {
|
|
|
4062
4275
|
* @param {number} month the month to query (e.g. 1 = January)
|
|
4063
4276
|
* @returns {Log[]} list of logs from the given month
|
|
4064
4277
|
*/
|
|
4065
|
-
opts.app.
|
|
4278
|
+
opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler({
|
|
4066
4279
|
paramTypes: {
|
|
4067
4280
|
year: ParamType$1.Int,
|
|
4068
4281
|
month: ParamType$1.Int,
|
|
4069
4282
|
},
|
|
4070
4283
|
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4071
4284
|
// Get user info
|
|
4072
|
-
const { userId, isAdmin } = params;
|
|
4285
|
+
const { year, month, userId, isAdmin, } = params;
|
|
4073
4286
|
// Validate user
|
|
4074
|
-
// isAdmin is already checked because path starts with '/admin'
|
|
4075
4287
|
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
4076
4288
|
if (!canReview) {
|
|
4077
4289
|
throw new ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ReactKitErrorCode$1.NotAllowedToReviewLogs);
|
|
4078
4290
|
}
|
|
4079
4291
|
// Query for logs
|
|
4080
|
-
const logs = yield _logCollection.find({
|
|
4292
|
+
const logs = yield _logCollection.find({
|
|
4293
|
+
year,
|
|
4294
|
+
month,
|
|
4295
|
+
});
|
|
4081
4296
|
// Return logs
|
|
4082
4297
|
return logs;
|
|
4083
4298
|
}),
|
|
@@ -4381,18 +4596,6 @@ const parseUserAgent = (userAgent) => {
|
|
|
4381
4596
|
};
|
|
4382
4597
|
};
|
|
4383
4598
|
|
|
4384
|
-
/**
|
|
4385
|
-
* Allowed log levels
|
|
4386
|
-
* @author Gabe Abrams
|
|
4387
|
-
*/
|
|
4388
|
-
var LogLevel;
|
|
4389
|
-
(function (LogLevel) {
|
|
4390
|
-
LogLevel["Warn"] = "Warn";
|
|
4391
|
-
LogLevel["Info"] = "Info";
|
|
4392
|
-
LogLevel["Debug"] = "Debug";
|
|
4393
|
-
})(LogLevel || (LogLevel = {}));
|
|
4394
|
-
var LogLevel$1 = LogLevel;
|
|
4395
|
-
|
|
4396
4599
|
/**
|
|
4397
4600
|
* Generate an express API route handler
|
|
4398
4601
|
* @author Gabe Abrams
|
|
@@ -4738,7 +4941,7 @@ const genRouteHandler = (opts) => {
|
|
|
4738
4941
|
isAdmin: !!launchInfo.isAdmin,
|
|
4739
4942
|
isTTM: !!launchInfo.isTTM,
|
|
4740
4943
|
courseId: launchInfo.courseId,
|
|
4741
|
-
courseName: launchInfo.
|
|
4944
|
+
courseName: launchInfo.contextLabel,
|
|
4742
4945
|
browser,
|
|
4743
4946
|
device,
|
|
4744
4947
|
year,
|
|
@@ -4765,7 +4968,7 @@ const genRouteHandler = (opts) => {
|
|
|
4765
4968
|
}
|
|
4766
4969
|
: {
|
|
4767
4970
|
type: LogType$1.Action,
|
|
4768
|
-
target: ((_m = opts.target) !== null && _m !== void 0 ? _m : LogBuiltInMetadata.Target.
|
|
4971
|
+
target: ((_m = opts.target) !== null && _m !== void 0 ? _m : LogBuiltInMetadata.Target.NoTarget),
|
|
4769
4972
|
action: ((_o = opts.action) !== null && _o !== void 0 ? _o : LogAction$1.Unknown),
|
|
4770
4973
|
});
|
|
4771
4974
|
// Source-specific info
|