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/cjs/index.js
CHANGED
|
@@ -519,17 +519,29 @@ const LOG_ROUTE_PATH = `${ROUTE_PATH_PREFIX}/log`;
|
|
|
519
519
|
const LogBuiltInMetadata = {
|
|
520
520
|
// Contexts
|
|
521
521
|
Context: {
|
|
522
|
-
Uncategorized: '
|
|
523
|
-
ServerRenderedErrorPage: '
|
|
524
|
-
ServerEndpointError: '
|
|
525
|
-
ClientFatalError: '
|
|
522
|
+
Uncategorized: 'Uncategorized',
|
|
523
|
+
ServerRenderedErrorPage: 'ServerRenderedErrorPage',
|
|
524
|
+
ServerEndpointError: 'ServerEndpointError',
|
|
525
|
+
ClientFatalError: 'ClientFatalError',
|
|
526
526
|
},
|
|
527
527
|
// Targets
|
|
528
528
|
Target: {
|
|
529
|
-
|
|
529
|
+
NoTarget: 'NoTarget',
|
|
530
530
|
},
|
|
531
531
|
};
|
|
532
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Allowed log levels
|
|
535
|
+
* @author Gabe Abrams
|
|
536
|
+
*/
|
|
537
|
+
var LogLevel;
|
|
538
|
+
(function (LogLevel) {
|
|
539
|
+
LogLevel["Warn"] = "Warn";
|
|
540
|
+
LogLevel["Info"] = "Info";
|
|
541
|
+
LogLevel["Debug"] = "Debug";
|
|
542
|
+
})(LogLevel || (LogLevel = {}));
|
|
543
|
+
var LogLevel$1 = LogLevel;
|
|
544
|
+
|
|
533
545
|
// Keep track of whether or not session expiry has already been handled
|
|
534
546
|
let sessionAlreadyExpired = false;
|
|
535
547
|
/*------------------------------------------------------------------------*/
|
|
@@ -648,7 +660,7 @@ const visitServerEndpoint = (opts) => __awaiter(void 0, void 0, void 0, function
|
|
|
648
660
|
* @author Gabe Abrams
|
|
649
661
|
*/
|
|
650
662
|
const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
651
|
-
var _a, _b, _c, _d, _e, _f;
|
|
663
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
652
664
|
return visitServerEndpoint({
|
|
653
665
|
path: LOG_ROUTE_PATH,
|
|
654
666
|
method: 'POST',
|
|
@@ -657,8 +669,9 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
657
669
|
? opts.context
|
|
658
670
|
: ((_b = ((_a = opts.context) !== null && _a !== void 0 ? _a : {})._) !== null && _b !== void 0 ? _b : LogBuiltInMetadata.Context.Uncategorized)),
|
|
659
671
|
subcontext: ((_c = opts.subcontext) !== null && _c !== void 0 ? _c : LogBuiltInMetadata.Context.Uncategorized),
|
|
660
|
-
|
|
661
|
-
|
|
672
|
+
level: ((_d = opts.level) !== null && _d !== void 0 ? _d : LogLevel$1.Info),
|
|
673
|
+
tags: JSON.stringify((_e = opts.tags) !== null && _e !== void 0 ? _e : []),
|
|
674
|
+
metadata: JSON.stringify((_f = opts.metadata) !== null && _f !== void 0 ? _f : {}),
|
|
662
675
|
errorMessage: (opts.error
|
|
663
676
|
? opts.error.message
|
|
664
677
|
: undefined),
|
|
@@ -669,7 +682,7 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
669
682
|
? opts.error.stack
|
|
670
683
|
: undefined),
|
|
671
684
|
target: (opts.action
|
|
672
|
-
? ((
|
|
685
|
+
? ((_g = opts.target) !== null && _g !== void 0 ? _g : LogBuiltInMetadata.Target.NoTarget)
|
|
673
686
|
: undefined),
|
|
674
687
|
action: (opts.action
|
|
675
688
|
? opts.action
|
|
@@ -1175,21 +1188,21 @@ const ButtonInputGroup = (props) => {
|
|
|
1175
1188
|
/*------------------------------------------------------------------------*/
|
|
1176
1189
|
/* -------------- Props ------------- */
|
|
1177
1190
|
// Destructure all props
|
|
1178
|
-
const { label, minLabelWidth, children, } = props;
|
|
1191
|
+
const { label, minLabelWidth, children, className, } = props;
|
|
1179
1192
|
/*------------------------------------------------------------------------*/
|
|
1180
1193
|
/* Render */
|
|
1181
1194
|
/*------------------------------------------------------------------------*/
|
|
1182
1195
|
/*----------------------------------------*/
|
|
1183
1196
|
/* Main UI */
|
|
1184
1197
|
/*----------------------------------------*/
|
|
1185
|
-
return (React__default["default"].createElement("div", { className:
|
|
1198
|
+
return (React__default["default"].createElement("div", { className: `input-group ${className !== null && className !== void 0 ? className : ''}` },
|
|
1186
1199
|
React__default["default"].createElement("div", { className: "input-group-prepend d-flex w-100" },
|
|
1187
1200
|
React__default["default"].createElement("span", { className: "input-group-text", style: {
|
|
1188
1201
|
minWidth: (minLabelWidth !== null && minLabelWidth !== void 0 ? minLabelWidth : undefined),
|
|
1189
1202
|
borderTopRightRadius: 0,
|
|
1190
1203
|
borderBottomRightRadius: 0,
|
|
1191
1204
|
} }, label),
|
|
1192
|
-
React__default["default"].createElement("span", { className: "input-group-text flex-grow-1 rounded-right", style: {
|
|
1205
|
+
React__default["default"].createElement("span", { className: "input-group-text flex-grow-1 rounded-right d-flex flex-wrap", style: {
|
|
1193
1206
|
backgroundColor: 'white',
|
|
1194
1207
|
borderTopLeftRadius: 0,
|
|
1195
1208
|
borderBottomLeftRadius: 0,
|
|
@@ -1352,12 +1365,25 @@ const SimpleDateChooser = (props) => {
|
|
|
1352
1365
|
// Figure out which days are allowed
|
|
1353
1366
|
const days = [];
|
|
1354
1367
|
const numDaysInMonth = (new Date(year, month, 0)).getDate();
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1368
|
+
if (chooseFromPast) {
|
|
1369
|
+
// Past selection
|
|
1370
|
+
const numDaysToAdd = ((month === today.month)
|
|
1371
|
+
? today.day // Current month, only add up to today
|
|
1372
|
+
: numDaysInMonth // Past month, add all days
|
|
1373
|
+
);
|
|
1374
|
+
for (let day = 1; day <= numDaysToAdd; day++) {
|
|
1375
|
+
days.push(day);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
// Future selection: add all remaining days of the month
|
|
1380
|
+
const firstDay = (month === today.month
|
|
1381
|
+
? today.day // Current month: start at current date
|
|
1382
|
+
: 1 // Future month: start at beginning of month
|
|
1383
|
+
);
|
|
1384
|
+
for (let day = firstDay; day <= numDaysInMonth; day++) {
|
|
1385
|
+
days.push(day);
|
|
1386
|
+
}
|
|
1361
1387
|
}
|
|
1362
1388
|
choices.push({
|
|
1363
1389
|
choiceName: `${monthName} ${year}`,
|
|
@@ -1428,14 +1454,16 @@ const Drawer = (props) => {
|
|
|
1428
1454
|
/*------------------------------------------------------------------------*/
|
|
1429
1455
|
/* -------------- Props ------------- */
|
|
1430
1456
|
// Destructure all props
|
|
1431
|
-
const { children, } = props;
|
|
1457
|
+
const { customBackgroundColor, children, } = props;
|
|
1432
1458
|
/*------------------------------------------------------------------------*/
|
|
1433
1459
|
/* Render */
|
|
1434
1460
|
/*------------------------------------------------------------------------*/
|
|
1435
1461
|
/*----------------------------------------*/
|
|
1436
1462
|
/* Main UI */
|
|
1437
1463
|
/*----------------------------------------*/
|
|
1438
|
-
return (React__default["default"].createElement("div", { className: "Drawer-container"
|
|
1464
|
+
return (React__default["default"].createElement("div", { className: "Drawer-container", style: {
|
|
1465
|
+
backgroundColor: (customBackgroundColor !== null && customBackgroundColor !== void 0 ? customBackgroundColor : undefined),
|
|
1466
|
+
} },
|
|
1439
1467
|
React__default["default"].createElement("style", null, style$4),
|
|
1440
1468
|
children));
|
|
1441
1469
|
};
|
|
@@ -1898,24 +1926,25 @@ const CopiableBox = (props) => {
|
|
|
1898
1926
|
/**
|
|
1899
1927
|
* Reusable nested item picker
|
|
1900
1928
|
* @author Yuen Ler Chow
|
|
1929
|
+
* @author Gabe Abrams
|
|
1901
1930
|
*/
|
|
1902
1931
|
/* ------------- Actions ------------ */
|
|
1903
1932
|
// Types of actions
|
|
1904
1933
|
var ActionType$2;
|
|
1905
1934
|
(function (ActionType) {
|
|
1906
|
-
// Toggle whether
|
|
1907
|
-
ActionType["
|
|
1935
|
+
// Toggle whether a child are being shown
|
|
1936
|
+
ActionType["ToggleChild"] = "toggle-child";
|
|
1908
1937
|
})(ActionType$2 || (ActionType$2 = {}));
|
|
1909
1938
|
/**
|
|
1910
1939
|
* Reducer that executes actions
|
|
1911
|
-
* @author
|
|
1940
|
+
* @author Gabe Abrams
|
|
1912
1941
|
* @param state current state
|
|
1913
1942
|
* @param action action to execute
|
|
1914
1943
|
*/
|
|
1915
1944
|
const reducer$2 = (state, action) => {
|
|
1916
1945
|
switch (action.type) {
|
|
1917
|
-
case ActionType$2.
|
|
1918
|
-
return {
|
|
1946
|
+
case ActionType$2.ToggleChild: {
|
|
1947
|
+
return Object.assign(Object.assign({}, state), { childExpanded: Object.assign(Object.assign({}, state.childExpanded), { [String(action.id)]: !state.childExpanded[String(action.id)] }) });
|
|
1919
1948
|
}
|
|
1920
1949
|
default: {
|
|
1921
1950
|
return state;
|
|
@@ -1933,14 +1962,19 @@ const NestableItemList = (props) => {
|
|
|
1933
1962
|
// Destructure all props
|
|
1934
1963
|
const { items, onChanged, } = props;
|
|
1935
1964
|
/* -------------- State ------------- */
|
|
1965
|
+
// Create initial map of child expanded booleans
|
|
1966
|
+
const initChildExpanded = {};
|
|
1967
|
+
items.forEach((item) => {
|
|
1968
|
+
initChildExpanded[String(item.id)] = false;
|
|
1969
|
+
});
|
|
1936
1970
|
// Initial state
|
|
1937
1971
|
const initialState = {
|
|
1938
|
-
|
|
1972
|
+
childExpanded: initChildExpanded,
|
|
1939
1973
|
};
|
|
1940
1974
|
// Initialize state
|
|
1941
1975
|
const [state, dispatch] = React.useReducer(reducer$2, initialState);
|
|
1942
1976
|
// Destructure common state
|
|
1943
|
-
const {
|
|
1977
|
+
const { childExpanded, } = state;
|
|
1944
1978
|
/*------------------------------------------------------------------------*/
|
|
1945
1979
|
/* Component Functions */
|
|
1946
1980
|
/*------------------------------------------------------------------------*/
|
|
@@ -2028,14 +2062,15 @@ const NestableItemList = (props) => {
|
|
|
2028
2062
|
backgroundColor: 'transparent',
|
|
2029
2063
|
}, type: "button", onClick: () => {
|
|
2030
2064
|
dispatch({
|
|
2031
|
-
type: ActionType$2.
|
|
2065
|
+
type: ActionType$2.ToggleChild,
|
|
2066
|
+
id: item.id,
|
|
2032
2067
|
});
|
|
2033
|
-
}, "aria-label": `${
|
|
2034
|
-
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon:
|
|
2068
|
+
}, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}` },
|
|
2069
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: childExpanded[item.id] ? freeSolidSvgIcons.faChevronDown : freeSolidSvgIcons.faChevronRight })))),
|
|
2035
2070
|
React__default["default"].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) => {
|
|
2036
2071
|
onChanged(changeChecked(item.id, checked, items));
|
|
2037
2072
|
}, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$1.Light }),
|
|
2038
|
-
item.isGroup &&
|
|
2073
|
+
(item.isGroup && childExpanded[item.id]) && (React__default["default"].createElement("div", { className: "NestableItemList-children-container", style: {
|
|
2039
2074
|
paddingLeft: '2.2rem',
|
|
2040
2075
|
} },
|
|
2041
2076
|
React__default["default"].createElement(NestableItemList, { items: item.children, onChanged: (updatedItems) => {
|
|
@@ -2057,7 +2092,7 @@ const ItemPicker = (props) => {
|
|
|
2057
2092
|
/*------------------------------------------------------------------------*/
|
|
2058
2093
|
/* -------------- Props ------------- */
|
|
2059
2094
|
// Destructure all props
|
|
2060
|
-
const { title, items, onChanged, } = props;
|
|
2095
|
+
const { title, items, onChanged, noBottomMargin, } = props;
|
|
2061
2096
|
/*------------------------------------------------------------------------*/
|
|
2062
2097
|
/* Component Functions */
|
|
2063
2098
|
/*------------------------------------------------------------------------*/
|
|
@@ -2067,7 +2102,7 @@ const ItemPicker = (props) => {
|
|
|
2067
2102
|
/*----------------------------------------*/
|
|
2068
2103
|
/* Main UI */
|
|
2069
2104
|
/*----------------------------------------*/
|
|
2070
|
-
return (React__default["default"].createElement(TabBox, { title: title },
|
|
2105
|
+
return (React__default["default"].createElement(TabBox, { title: title, noBottomMargin: noBottomMargin },
|
|
2071
2106
|
React__default["default"].createElement("div", { style: { overflowX: 'auto' } },
|
|
2072
2107
|
React__default["default"].createElement(NestableItemList, { items: items, onChanged: onChanged }))));
|
|
2073
2108
|
};
|
|
@@ -2111,37 +2146,37 @@ var LogType$1 = LogType;
|
|
|
2111
2146
|
var LogAction;
|
|
2112
2147
|
(function (LogAction) {
|
|
2113
2148
|
// Target was opened by the user (it was not on screen, but now it is)
|
|
2114
|
-
LogAction["Open"] = "
|
|
2149
|
+
LogAction["Open"] = "Open";
|
|
2115
2150
|
// Target was closed by the user (it was on screen, but now it is not)
|
|
2116
|
-
LogAction["Close"] = "
|
|
2151
|
+
LogAction["Close"] = "Close";
|
|
2117
2152
|
// Target was cancelled by the user (it was on closed without saving)
|
|
2118
|
-
LogAction["Cancel"] = "
|
|
2153
|
+
LogAction["Cancel"] = "Cancel";
|
|
2119
2154
|
// Target was expanded by the user (it always remains on screen, but size was changed)
|
|
2120
|
-
LogAction["Expand"] = "
|
|
2155
|
+
LogAction["Expand"] = "Expand";
|
|
2121
2156
|
// Target was collapsed by the user (it always remains on screen, but size was changed)
|
|
2122
|
-
LogAction["Collapse"] = "
|
|
2157
|
+
LogAction["Collapse"] = "Collapse";
|
|
2123
2158
|
// Target was viewed by the user (only for items that are not opened or closed, those must use Open/Close actions)
|
|
2124
|
-
LogAction["View"] = "
|
|
2159
|
+
LogAction["View"] = "View";
|
|
2125
2160
|
// Target interrupted the user (popup, dialog, validation message, etc. appeared without user prompting)
|
|
2126
|
-
LogAction["Interrupt"] = "
|
|
2161
|
+
LogAction["Interrupt"] = "Interrupt";
|
|
2127
2162
|
// Target was created by the user (it did not exist before)
|
|
2128
|
-
LogAction["Create"] = "
|
|
2163
|
+
LogAction["Create"] = "Create";
|
|
2129
2164
|
// Target was edited by the user (it existed and was changed)
|
|
2130
|
-
LogAction["Edit"] = "
|
|
2165
|
+
LogAction["Edit"] = "Edit";
|
|
2131
2166
|
// Target was deleted by the user (it existed and now it doesn't)
|
|
2132
|
-
LogAction["Delete"] = "
|
|
2167
|
+
LogAction["Delete"] = "Delete";
|
|
2133
2168
|
// Target was added by the user (it already existed and was added to another place)
|
|
2134
|
-
LogAction["Add"] = "
|
|
2169
|
+
LogAction["Add"] = "Add";
|
|
2135
2170
|
// Target was removed by the user (it was removed from something but still exists)
|
|
2136
|
-
LogAction["Remove"] = "
|
|
2171
|
+
LogAction["Remove"] = "Remove";
|
|
2137
2172
|
// Target was activated by the user (click, check, tap, keypress, etc.)
|
|
2138
|
-
LogAction["Activate"] = "
|
|
2173
|
+
LogAction["Activate"] = "Activate";
|
|
2139
2174
|
// Target was deactivated by the user (click away, uncheck, tap outside of, tab away, etc.)
|
|
2140
|
-
LogAction["Deactivate"] = "
|
|
2175
|
+
LogAction["Deactivate"] = "Deactivate";
|
|
2141
2176
|
// User showed interest in a target (hover, peek, etc.)
|
|
2142
|
-
LogAction["Peek"] = "
|
|
2177
|
+
LogAction["Peek"] = "Peek";
|
|
2143
2178
|
// Unknown action
|
|
2144
|
-
LogAction["Unknown"] = "
|
|
2179
|
+
LogAction["Unknown"] = "Unknown";
|
|
2145
2180
|
})(LogAction || (LogAction = {}));
|
|
2146
2181
|
var LogAction$1 = LogAction;
|
|
2147
2182
|
|
|
@@ -2183,12 +2218,12 @@ const roundToNumDecimals = (num, numDecimals) => {
|
|
|
2183
2218
|
* @returns escaped cell text
|
|
2184
2219
|
*/
|
|
2185
2220
|
const escapeCellText = (text) => {
|
|
2186
|
-
if (!text.includes(',')) {
|
|
2221
|
+
if (!String(text).includes(',')) {
|
|
2187
2222
|
// No need to escape
|
|
2188
|
-
return text;
|
|
2223
|
+
return String(text);
|
|
2189
2224
|
}
|
|
2190
2225
|
// Perform escape
|
|
2191
|
-
return `"${text.replace(/"/g, '""')}`;
|
|
2226
|
+
return `"${String(text).replace(/"/g, '""')}`;
|
|
2192
2227
|
};
|
|
2193
2228
|
/**
|
|
2194
2229
|
* Generate a CSV file
|
|
@@ -2209,7 +2244,23 @@ const genCSV = (data, columns) => {
|
|
|
2209
2244
|
data.forEach((datum) => {
|
|
2210
2245
|
csv += (columns
|
|
2211
2246
|
.map((column) => {
|
|
2212
|
-
|
|
2247
|
+
let contents;
|
|
2248
|
+
const cell = datum[column.param];
|
|
2249
|
+
if (typeof cell === 'string'
|
|
2250
|
+
|| typeof cell === 'number') {
|
|
2251
|
+
contents = String(cell);
|
|
2252
|
+
}
|
|
2253
|
+
else if (typeof cell === 'undefined'
|
|
2254
|
+
|| cell === null) {
|
|
2255
|
+
contents = '';
|
|
2256
|
+
}
|
|
2257
|
+
else if (typeof cell === 'object') {
|
|
2258
|
+
contents = JSON.stringify(cell);
|
|
2259
|
+
}
|
|
2260
|
+
else {
|
|
2261
|
+
contents = '';
|
|
2262
|
+
}
|
|
2263
|
+
return escapeCellText(contents);
|
|
2213
2264
|
})
|
|
2214
2265
|
.join(','));
|
|
2215
2266
|
});
|
|
@@ -2242,7 +2293,8 @@ const CSVDownloadButton = (props) => {
|
|
|
2242
2293
|
? `Click to download ${filename}`
|
|
2243
2294
|
: ariaLabel), style: style, onClick: onClick },
|
|
2244
2295
|
!children && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
2245
|
-
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCloudDownloadAlt
|
|
2296
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCloudDownloadAlt }),
|
|
2297
|
+
' ',
|
|
2246
2298
|
"Download CSV")),
|
|
2247
2299
|
children));
|
|
2248
2300
|
};
|
|
@@ -2266,7 +2318,7 @@ var ActionType$1;
|
|
|
2266
2318
|
// Toggle sort column param
|
|
2267
2319
|
ActionType["ToggleSortColumn"] = "toggle-sort-column";
|
|
2268
2320
|
// Toggle the visibility of a column
|
|
2269
|
-
ActionType["
|
|
2321
|
+
ActionType["UpdateColumnVisibility"] = "update-column-visibility";
|
|
2270
2322
|
// Toggle the column visibility customization modal
|
|
2271
2323
|
ActionType["ToggleColVisCusModalVisibility"] = "toggle-col-vis-cus-modal-visibility";
|
|
2272
2324
|
})(ActionType$1 || (ActionType$1 = {}));
|
|
@@ -2290,9 +2342,9 @@ const reducer$1 = (state, action) => {
|
|
|
2290
2342
|
// Stop sorting by column
|
|
2291
2343
|
return Object.assign(Object.assign({}, state), { sortColumnParam: undefined, sortType: SortType.Ascending });
|
|
2292
2344
|
}
|
|
2293
|
-
case ActionType$1.
|
|
2345
|
+
case ActionType$1.UpdateColumnVisibility: {
|
|
2294
2346
|
const { columnVisibilityMap } = state;
|
|
2295
|
-
columnVisibilityMap[action.param] =
|
|
2347
|
+
columnVisibilityMap[action.param] = action.visible;
|
|
2296
2348
|
return Object.assign(Object.assign({}, state), { columnVisibilityMap });
|
|
2297
2349
|
}
|
|
2298
2350
|
case ActionType$1.ToggleColVisCusModalVisibility: {
|
|
@@ -2313,7 +2365,11 @@ const IntelliTable = (props) => {
|
|
|
2313
2365
|
var _a;
|
|
2314
2366
|
/* -------------- Props ------------- */
|
|
2315
2367
|
// Destructure all props
|
|
2316
|
-
const { title, id,
|
|
2368
|
+
const { title, id, columns, } = props;
|
|
2369
|
+
// Get data, show empty row if none
|
|
2370
|
+
const data = ((props.data && props.data.length > 0)
|
|
2371
|
+
? props.data
|
|
2372
|
+
: [{ id: 'empty-row' }]);
|
|
2317
2373
|
/* -------------- State ------------- */
|
|
2318
2374
|
// Initial state
|
|
2319
2375
|
const initColumnVisibilityMap = {};
|
|
@@ -2330,20 +2386,29 @@ const IntelliTable = (props) => {
|
|
|
2330
2386
|
const [state, dispatch] = React.useReducer(reducer$1, initialState);
|
|
2331
2387
|
// Destructure common state
|
|
2332
2388
|
const { sortColumnParam, sortType, columnVisibilityMap, columnVisibilityCustomizationModalVisible, } = state;
|
|
2389
|
+
/*------------------------------------------------------------------------*/
|
|
2390
|
+
/* Render */
|
|
2391
|
+
/*------------------------------------------------------------------------*/
|
|
2392
|
+
/*----------------------------------------*/
|
|
2393
|
+
/* Modal */
|
|
2394
|
+
/*----------------------------------------*/
|
|
2395
|
+
// Modal that may be defined
|
|
2396
|
+
let modal;
|
|
2333
2397
|
/* ------- Col Vis Customization Modal ------ */
|
|
2334
2398
|
if (columnVisibilityCustomizationModalVisible) {
|
|
2335
2399
|
// Create modal
|
|
2336
|
-
(React__default["default"].createElement(Modal, { type: ModalType$1.Okay, title: "Choose columns to show:", onClose: () => {
|
|
2400
|
+
modal = (React__default["default"].createElement(Modal, { type: ModalType$1.Okay, title: "Choose columns to show:", onClose: () => {
|
|
2337
2401
|
dispatch({
|
|
2338
2402
|
type: ActionType$1.ToggleColVisCusModalVisibility,
|
|
2339
2403
|
});
|
|
2340
|
-
} }, columns.map((column) => {
|
|
2341
|
-
return (React__default["default"].createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, text: column.title, onChanged: () => {
|
|
2404
|
+
}, okayVariant: Variant$1.Light }, columns.map((column) => {
|
|
2405
|
+
return (React__default["default"].createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, className: "mb-2", text: column.title, onChanged: (checked) => {
|
|
2342
2406
|
dispatch({
|
|
2343
|
-
type: ActionType$1.
|
|
2407
|
+
type: ActionType$1.UpdateColumnVisibility,
|
|
2344
2408
|
param: column.param,
|
|
2409
|
+
visible: checked,
|
|
2345
2410
|
});
|
|
2346
|
-
}, checked: columnVisibilityMap[column.param], ariaLabel: `show "${column.title}" column
|
|
2411
|
+
}, checked: columnVisibilityMap[column.param], ariaLabel: `show "${column.title}" column`, checkedVariant: Variant$1.Light, uncheckedVariant: Variant$1.Secondary }));
|
|
2347
2412
|
})));
|
|
2348
2413
|
}
|
|
2349
2414
|
/*----------------------------------------*/
|
|
@@ -2358,6 +2423,7 @@ const IntelliTable = (props) => {
|
|
|
2358
2423
|
// Custom info based on current sort type
|
|
2359
2424
|
let sortButtonAriaLabel;
|
|
2360
2425
|
let sortIcon = freeSolidSvgIcons.faSort;
|
|
2426
|
+
let sortingByThisColumn = false;
|
|
2361
2427
|
if (!sortColumnParam) {
|
|
2362
2428
|
// Not being sorted yet
|
|
2363
2429
|
sortButtonAriaLabel = `sort ascending by ${column.title}`;
|
|
@@ -2365,6 +2431,7 @@ const IntelliTable = (props) => {
|
|
|
2365
2431
|
}
|
|
2366
2432
|
else if (column.param === sortColumnParam) {
|
|
2367
2433
|
// Already sorted by this column
|
|
2434
|
+
sortingByThisColumn = true;
|
|
2368
2435
|
if (sortType === SortType.Ascending) {
|
|
2369
2436
|
// Sorted ascending
|
|
2370
2437
|
sortButtonAriaLabel = `sort descending by ${column.title}`;
|
|
@@ -2382,11 +2449,14 @@ const IntelliTable = (props) => {
|
|
|
2382
2449
|
sortIcon = freeSolidSvgIcons.faSort;
|
|
2383
2450
|
}
|
|
2384
2451
|
// Create the cell UI
|
|
2385
|
-
return (React__default["default"].createElement("th", { key: column.param, scope: "col", id: `IntelliTable-${id}-header-${column.param}
|
|
2386
|
-
|
|
2387
|
-
|
|
2452
|
+
return (React__default["default"].createElement("th", { key: column.param, scope: "col", id: `IntelliTable-${id}-header-${column.param}`, className: "text-start", style: {
|
|
2453
|
+
borderRight: '0.05rem solid #555',
|
|
2454
|
+
borderLeft: '0.05rem solid #555',
|
|
2455
|
+
} },
|
|
2456
|
+
React__default["default"].createElement("div", { className: "d-flex align-items-center justify-content-start flex-row h-100" },
|
|
2457
|
+
React__default["default"].createElement("span", { className: "text-nowrap" }, column.title),
|
|
2388
2458
|
React__default["default"].createElement("div", null,
|
|
2389
|
-
React__default["default"].createElement("button", { type: "button", className:
|
|
2459
|
+
React__default["default"].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: () => {
|
|
2390
2460
|
dispatch({
|
|
2391
2461
|
type: ActionType$1.ToggleSortColumn,
|
|
2392
2462
|
param: column.param,
|
|
@@ -2404,8 +2474,28 @@ const IntelliTable = (props) => {
|
|
|
2404
2474
|
const descending = (sortType === SortType.Descending);
|
|
2405
2475
|
if (sortColumnParam) {
|
|
2406
2476
|
sortedData.sort((a, b) => {
|
|
2477
|
+
var _a, _b;
|
|
2407
2478
|
const aVal = a[sortColumnParam];
|
|
2408
2479
|
const bVal = b[sortColumnParam];
|
|
2480
|
+
// Tiebreaker sort by timestamp, most recent first (used if tied)
|
|
2481
|
+
const tiebreaker = (((_a = b.timestamp) !== null && _a !== void 0 ? _a : 0)
|
|
2482
|
+
- ((_b = a.timestamp) !== null && _b !== void 0 ? _b : 0));
|
|
2483
|
+
// Auto-sort undefined and null to end of list
|
|
2484
|
+
if ((aVal === undefined || aVal === null)
|
|
2485
|
+
|| (bVal === undefined || bVal === null)) {
|
|
2486
|
+
// At least one was undefined
|
|
2487
|
+
if ((aVal === undefined || aVal === null)
|
|
2488
|
+
&& (bVal === undefined || bVal === null)) {
|
|
2489
|
+
// Both undefined
|
|
2490
|
+
return tiebreaker;
|
|
2491
|
+
}
|
|
2492
|
+
if (aVal === undefined || aVal === null) {
|
|
2493
|
+
// First was undefined
|
|
2494
|
+
return 1;
|
|
2495
|
+
}
|
|
2496
|
+
// Second was undefined
|
|
2497
|
+
return -1;
|
|
2498
|
+
}
|
|
2409
2499
|
// Sort differently based on the data type
|
|
2410
2500
|
// > Boolean
|
|
2411
2501
|
if (paramType === ParamType$1.Boolean) {
|
|
@@ -2415,7 +2505,7 @@ const IntelliTable = (props) => {
|
|
|
2415
2505
|
if (!aVal && bVal) {
|
|
2416
2506
|
return (descending ? 1 : -1);
|
|
2417
2507
|
}
|
|
2418
|
-
return
|
|
2508
|
+
return tiebreaker;
|
|
2419
2509
|
}
|
|
2420
2510
|
// > Number
|
|
2421
2511
|
if (paramType === ParamType$1.Int
|
|
@@ -2427,12 +2517,12 @@ const IntelliTable = (props) => {
|
|
|
2427
2517
|
// > String
|
|
2428
2518
|
if (paramType === ParamType$1.String) {
|
|
2429
2519
|
if (aVal < bVal) {
|
|
2430
|
-
return (descending ?
|
|
2520
|
+
return (descending ? 1 : -1);
|
|
2431
2521
|
}
|
|
2432
2522
|
if (aVal > bVal) {
|
|
2433
|
-
return (descending ? 1 :
|
|
2523
|
+
return (descending ? -1 : 1);
|
|
2434
2524
|
}
|
|
2435
|
-
return
|
|
2525
|
+
return tiebreaker;
|
|
2436
2526
|
}
|
|
2437
2527
|
// > JSON
|
|
2438
2528
|
if (paramType === ParamType$1.JSON) {
|
|
@@ -2447,7 +2537,7 @@ const IntelliTable = (props) => {
|
|
|
2447
2537
|
: (aSize - bSize));
|
|
2448
2538
|
}
|
|
2449
2539
|
// No sort
|
|
2450
|
-
return
|
|
2540
|
+
return tiebreaker;
|
|
2451
2541
|
});
|
|
2452
2542
|
}
|
|
2453
2543
|
// Table body
|
|
@@ -2472,9 +2562,12 @@ const IntelliTable = (props) => {
|
|
|
2472
2562
|
const noValue = (value === undefined
|
|
2473
2563
|
|| value === null);
|
|
2474
2564
|
visibleValue = (noValue
|
|
2475
|
-
? (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.
|
|
2476
|
-
: (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faXmarkCircle })));
|
|
2565
|
+
? (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faMinus }))
|
|
2566
|
+
: (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: fullValue ? freeSolidSvgIcons.faCheckCircle : freeSolidSvgIcons.faXmarkCircle })));
|
|
2477
2567
|
title = (fullValue ? 'True' : 'False');
|
|
2568
|
+
if (noValue) {
|
|
2569
|
+
title = 'Empty Cell';
|
|
2570
|
+
}
|
|
2478
2571
|
}
|
|
2479
2572
|
else if (column.type === ParamType$1.Int) {
|
|
2480
2573
|
fullValue = Number.parseInt(value, 10);
|
|
@@ -2483,6 +2576,9 @@ const IntelliTable = (props) => {
|
|
|
2483
2576
|
? (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faMinus }))
|
|
2484
2577
|
: fullValue);
|
|
2485
2578
|
title = String(fullValue);
|
|
2579
|
+
if (noValue) {
|
|
2580
|
+
title = 'Empty Cell';
|
|
2581
|
+
}
|
|
2486
2582
|
}
|
|
2487
2583
|
else if (column.type === ParamType$1.Float) {
|
|
2488
2584
|
fullValue = Number.parseFloat(value);
|
|
@@ -2491,14 +2587,22 @@ const IntelliTable = (props) => {
|
|
|
2491
2587
|
? (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faMinus }))
|
|
2492
2588
|
: roundToNumDecimals(fullValue, 2));
|
|
2493
2589
|
title = String(fullValue);
|
|
2590
|
+
if (noValue) {
|
|
2591
|
+
title = 'Empty Cell';
|
|
2592
|
+
}
|
|
2494
2593
|
}
|
|
2495
2594
|
else if (column.type === ParamType$1.String) {
|
|
2496
2595
|
fullValue = String(value).trim();
|
|
2497
|
-
const noValue = (value
|
|
2596
|
+
const noValue = (value === undefined
|
|
2597
|
+
|| value === null
|
|
2598
|
+
|| String(fullValue).trim().length === 0);
|
|
2498
2599
|
visibleValue = (noValue
|
|
2499
2600
|
? (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faMinus }))
|
|
2500
2601
|
: fullValue);
|
|
2501
2602
|
title = `"${value}"`;
|
|
2603
|
+
if (noValue) {
|
|
2604
|
+
title = 'Empty Cell';
|
|
2605
|
+
}
|
|
2502
2606
|
}
|
|
2503
2607
|
else if (column.type === ParamType$1.JSON) {
|
|
2504
2608
|
fullValue = JSON.stringify(value);
|
|
@@ -2508,9 +2612,13 @@ const IntelliTable = (props) => {
|
|
|
2508
2612
|
visibleValue = (noValue
|
|
2509
2613
|
? (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faMinus }))
|
|
2510
2614
|
: fullValue);
|
|
2615
|
+
title = "JSON Object";
|
|
2511
2616
|
}
|
|
2512
2617
|
// Create UI
|
|
2513
|
-
return (React__default["default"].createElement("td", { key: `${datum.id}-${column.param}`, title: title
|
|
2618
|
+
return (React__default["default"].createElement("td", { key: `${datum.id}-${column.param}`, title: title, style: {
|
|
2619
|
+
borderRight: '0.05rem solid #555',
|
|
2620
|
+
borderLeft: '0.05rem solid #555',
|
|
2621
|
+
} }, visibleValue));
|
|
2514
2622
|
}));
|
|
2515
2623
|
// Add cells to a row
|
|
2516
2624
|
return (React__default["default"].createElement("tr", { key: datum.id }, cells));
|
|
@@ -2530,11 +2638,12 @@ const IntelliTable = (props) => {
|
|
|
2530
2638
|
const csv = genCSV(data, columns);
|
|
2531
2639
|
// Build main UI
|
|
2532
2640
|
return (React__default["default"].createElement("div", { className: `IntelliTable-container-${id}` },
|
|
2533
|
-
|
|
2641
|
+
modal,
|
|
2642
|
+
React__default["default"].createElement("div", { className: "d-flex align-items-center justify-content-start" },
|
|
2534
2643
|
React__default["default"].createElement("h3", { className: "m-0" }, title),
|
|
2535
2644
|
React__default["default"].createElement("div", { className: "flex-grow-1 text-end" },
|
|
2536
2645
|
React__default["default"].createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: `${title}.csv`, csv: csv }),
|
|
2537
|
-
React__default["default"].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: () => {
|
|
2646
|
+
React__default["default"].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: () => {
|
|
2538
2647
|
dispatch({
|
|
2539
2648
|
type: ActionType$1.ToggleColVisCusModalVisibility,
|
|
2540
2649
|
});
|
|
@@ -2546,7 +2655,7 @@ const IntelliTable = (props) => {
|
|
|
2546
2655
|
numHiddenCols,
|
|
2547
2656
|
' ',
|
|
2548
2657
|
"hidden)"))))),
|
|
2549
|
-
React__default["default"].createElement("div", { className: `IntelliTable-table-${id}`, style: {
|
|
2658
|
+
React__default["default"].createElement("div", { className: `IntelliTable-table-${id} mt-2`, style: {
|
|
2550
2659
|
overflowX: 'auto',
|
|
2551
2660
|
} }, table)));
|
|
2552
2661
|
};
|
|
@@ -2598,6 +2707,11 @@ const style = `
|
|
|
2598
2707
|
border: 0.05rem solid black;
|
|
2599
2708
|
border-radius: 0.5rem;
|
|
2600
2709
|
overflow: hidden;
|
|
2710
|
+
padding: 0.7rem;
|
|
2711
|
+
|
|
2712
|
+
/* Solid background */
|
|
2713
|
+
background-color: white;
|
|
2714
|
+
color: black;
|
|
2601
2715
|
|
|
2602
2716
|
/* Place contents in flex column */
|
|
2603
2717
|
flex-direction: column;
|
|
@@ -2624,6 +2738,27 @@ const style = `
|
|
|
2624
2738
|
/* Vertical scroll */
|
|
2625
2739
|
overflow-y: auto;
|
|
2626
2740
|
}
|
|
2741
|
+
|
|
2742
|
+
.LogReviewer-header-close-button {
|
|
2743
|
+
border: 0 !important;
|
|
2744
|
+
background-color: transparent !important;
|
|
2745
|
+
padding-top: 0 !important;
|
|
2746
|
+
padding-bottom: 0 !important;
|
|
2747
|
+
padding-right: 1em !important;
|
|
2748
|
+
margin: 0 !important;
|
|
2749
|
+
color: #444 !important;
|
|
2750
|
+
|
|
2751
|
+
right: 0 !important;
|
|
2752
|
+
position: absolute !important;
|
|
2753
|
+
}
|
|
2754
|
+
.LogReviewer-header-close-button:hover {
|
|
2755
|
+
border: 0 !important;
|
|
2756
|
+
background-color: transparent !important;
|
|
2757
|
+
padding-top: 0 !important;
|
|
2758
|
+
padding-bottom: 0 !important;
|
|
2759
|
+
margin: 0 !important;
|
|
2760
|
+
color: #000 !important;
|
|
2761
|
+
}
|
|
2627
2762
|
`;
|
|
2628
2763
|
/*------------------------------------------------------------------------*/
|
|
2629
2764
|
/* Static Functions */
|
|
@@ -2643,7 +2778,7 @@ const genHumanReadableName = (machineReadableName) => {
|
|
|
2643
2778
|
// Uppercase! Add a space before
|
|
2644
2779
|
humanReadableName += ' ';
|
|
2645
2780
|
}
|
|
2646
|
-
humanReadableName +=
|
|
2781
|
+
humanReadableName += char;
|
|
2647
2782
|
});
|
|
2648
2783
|
// Trim and return
|
|
2649
2784
|
return humanReadableName.trim();
|
|
@@ -2705,7 +2840,19 @@ const reducer = (state, action) => {
|
|
|
2705
2840
|
return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
|
|
2706
2841
|
}
|
|
2707
2842
|
case ActionType.UpdateTagFilterState: {
|
|
2708
|
-
|
|
2843
|
+
const { tagFilterState } = action;
|
|
2844
|
+
// Select all if every tag is deselected
|
|
2845
|
+
const numTagsSelected = (Object.values(tagFilterState)
|
|
2846
|
+
.filter((isSelected) => {
|
|
2847
|
+
return isSelected;
|
|
2848
|
+
})
|
|
2849
|
+
.length);
|
|
2850
|
+
if (numTagsSelected === 0) {
|
|
2851
|
+
Object.keys(tagFilterState).forEach((tag) => {
|
|
2852
|
+
tagFilterState[tag] = true;
|
|
2853
|
+
});
|
|
2854
|
+
}
|
|
2855
|
+
return Object.assign(Object.assign({}, state), { tagFilterState });
|
|
2709
2856
|
}
|
|
2710
2857
|
case ActionType.UpdateActionErrorFilterState: {
|
|
2711
2858
|
return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
|
|
@@ -2725,10 +2872,35 @@ const LogReviewer = (props) => {
|
|
|
2725
2872
|
/*------------------------------------------------------------------------*/
|
|
2726
2873
|
/* Setup */
|
|
2727
2874
|
/*------------------------------------------------------------------------*/
|
|
2728
|
-
var _a, _b, _c, _d, _e;
|
|
2875
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2729
2876
|
/* -------------- Props ------------- */
|
|
2730
2877
|
// Destructure props
|
|
2731
2878
|
const { LogMetadata, onClose, } = props;
|
|
2879
|
+
// Add built-in LogMetadata
|
|
2880
|
+
// > Add "uncategorized" subcontext to each context
|
|
2881
|
+
Object.keys((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {}).forEach((context) => {
|
|
2882
|
+
if (
|
|
2883
|
+
// Context exists
|
|
2884
|
+
LogMetadata.Context
|
|
2885
|
+
// Context has children already
|
|
2886
|
+
&& typeof LogMetadata.Context[context] !== 'string') {
|
|
2887
|
+
LogMetadata.Context[context][LogBuiltInMetadata.Context.Uncategorized] = (LogBuiltInMetadata.Context.Uncategorized);
|
|
2888
|
+
}
|
|
2889
|
+
});
|
|
2890
|
+
// > Add built-in contexts
|
|
2891
|
+
LogMetadata.Context = ((_b = LogMetadata.Context) !== null && _b !== void 0 ? _b : {});
|
|
2892
|
+
Object.keys(LogBuiltInMetadata.Context).forEach((context) => {
|
|
2893
|
+
if (LogMetadata.Context) {
|
|
2894
|
+
LogMetadata.Context[context] = context;
|
|
2895
|
+
}
|
|
2896
|
+
});
|
|
2897
|
+
// > Add built-in targets
|
|
2898
|
+
LogMetadata.Target = ((_c = LogMetadata.Target) !== null && _c !== void 0 ? _c : {});
|
|
2899
|
+
Object.keys(LogBuiltInMetadata.Target).forEach((target) => {
|
|
2900
|
+
if (LogMetadata.Target) {
|
|
2901
|
+
LogMetadata.Target[target] = target;
|
|
2902
|
+
}
|
|
2903
|
+
});
|
|
2732
2904
|
/* -------------- State ------------- */
|
|
2733
2905
|
// Create initial date filter state
|
|
2734
2906
|
const today = getTimeInfoInET();
|
|
@@ -2748,26 +2920,30 @@ const LogReviewer = (props) => {
|
|
|
2748
2920
|
};
|
|
2749
2921
|
// Create initial context filter state
|
|
2750
2922
|
const initContextFilterState = {};
|
|
2751
|
-
Object.keys((
|
|
2923
|
+
Object.keys((_d = LogMetadata.Context) !== null && _d !== void 0 ? _d : {}).forEach((context) => {
|
|
2752
2924
|
var _a, _b;
|
|
2753
2925
|
const contextValue = ((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {})[context];
|
|
2754
2926
|
if (typeof contextValue === 'string') {
|
|
2755
|
-
// Case: no subcontexts
|
|
2927
|
+
// Case: no subcontexts, init as checked
|
|
2756
2928
|
initContextFilterState[contextValue] = true;
|
|
2757
2929
|
}
|
|
2758
2930
|
else {
|
|
2759
2931
|
// Case: subcontexts exist
|
|
2760
|
-
initContextFilterState[
|
|
2932
|
+
initContextFilterState[context] = {};
|
|
2761
2933
|
Object.values(((_b = LogMetadata.Context) !== null && _b !== void 0 ? _b : {})[context]).forEach((subcontext) => {
|
|
2762
|
-
|
|
2763
|
-
|
|
2934
|
+
// Skip self ("_")
|
|
2935
|
+
if (subcontext === '_') {
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
// Initialize as checked
|
|
2939
|
+
initContextFilterState[context][subcontext] = true;
|
|
2764
2940
|
});
|
|
2765
2941
|
}
|
|
2766
2942
|
});
|
|
2767
2943
|
// Create initial tag filter state
|
|
2768
2944
|
const initTagFilterState = {};
|
|
2769
|
-
Object.
|
|
2770
|
-
initTagFilterState[
|
|
2945
|
+
Object.keys((_e = LogMetadata.Tag) !== null && _e !== void 0 ? _e : {}).forEach((tag) => {
|
|
2946
|
+
initTagFilterState[tag] = false;
|
|
2771
2947
|
});
|
|
2772
2948
|
// Create advanced filter state
|
|
2773
2949
|
const initAdvancedFilterState = {
|
|
@@ -2793,12 +2969,16 @@ const LogReviewer = (props) => {
|
|
|
2793
2969
|
target: {},
|
|
2794
2970
|
action: {},
|
|
2795
2971
|
};
|
|
2796
|
-
Object.values((
|
|
2972
|
+
Object.values((_f = LogMetadata.Target) !== null && _f !== void 0 ? _f : {}).forEach((target) => {
|
|
2797
2973
|
initActionErrorFilterState.target[target] = true;
|
|
2798
2974
|
});
|
|
2799
2975
|
Object.values(LogAction$1).forEach((action) => {
|
|
2800
2976
|
initActionErrorFilterState.action[action] = true;
|
|
2801
2977
|
});
|
|
2978
|
+
// Add built-in targets
|
|
2979
|
+
Object.values(LogBuiltInMetadata.Target).forEach((target) => {
|
|
2980
|
+
initActionErrorFilterState.target[target] = true;
|
|
2981
|
+
});
|
|
2802
2982
|
// Initial state
|
|
2803
2983
|
const initialState = {
|
|
2804
2984
|
loading: true,
|
|
@@ -2832,15 +3012,18 @@ const LogReviewer = (props) => {
|
|
|
2832
3012
|
let month = newDateFilterState.startDate.month;
|
|
2833
3013
|
while (
|
|
2834
3014
|
// Earlier year
|
|
2835
|
-
(year
|
|
3015
|
+
(year < newDateFilterState.endDate.year)
|
|
2836
3016
|
// Current year but included month
|
|
2837
3017
|
|| (year === newDateFilterState.endDate.year
|
|
2838
3018
|
&& month <= newDateFilterState.endDate.month)) {
|
|
2839
|
-
// Add to list
|
|
2840
|
-
|
|
2841
|
-
year
|
|
2842
|
-
|
|
2843
|
-
|
|
3019
|
+
// Add to list if not already loaded
|
|
3020
|
+
if (!logMap[year]
|
|
3021
|
+
|| !logMap[year][month]) {
|
|
3022
|
+
toLoad.push({
|
|
3023
|
+
year,
|
|
3024
|
+
month,
|
|
3025
|
+
});
|
|
3026
|
+
}
|
|
2844
3027
|
// Increment
|
|
2845
3028
|
month += 1;
|
|
2846
3029
|
if (month > 12) {
|
|
@@ -2928,10 +3111,10 @@ const LogReviewer = (props) => {
|
|
|
2928
3111
|
/* Filters */
|
|
2929
3112
|
/*----------------------------------------*/
|
|
2930
3113
|
// Filter toggle
|
|
2931
|
-
const filterToggles = (React__default["default"].createElement("div", { className: "LogReviewer-filter-toggles
|
|
3114
|
+
const filterToggles = (React__default["default"].createElement("div", { className: "LogReviewer-filter-toggles" },
|
|
2932
3115
|
React__default["default"].createElement("h3", { className: "m-0" }, "Filters:"),
|
|
2933
|
-
React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons" },
|
|
2934
|
-
React__default["default"].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: () => {
|
|
3116
|
+
React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
|
|
3117
|
+
React__default["default"].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: () => {
|
|
2935
3118
|
dispatch({
|
|
2936
3119
|
type: ActionType.ToggleFilterDrawer,
|
|
2937
3120
|
filterDrawer: FilterDrawer.Date,
|
|
@@ -2939,7 +3122,7 @@ const LogReviewer = (props) => {
|
|
|
2939
3122
|
} },
|
|
2940
3123
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCalendar, className: "me-2" }),
|
|
2941
3124
|
"Date"),
|
|
2942
|
-
React__default["default"].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: () => {
|
|
3125
|
+
React__default["default"].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: () => {
|
|
2943
3126
|
dispatch({
|
|
2944
3127
|
type: ActionType.ToggleFilterDrawer,
|
|
2945
3128
|
filterDrawer: FilterDrawer.Context,
|
|
@@ -2947,15 +3130,15 @@ const LogReviewer = (props) => {
|
|
|
2947
3130
|
} },
|
|
2948
3131
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "me-2" }),
|
|
2949
3132
|
"Context"),
|
|
2950
|
-
React__default["default"].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: () => {
|
|
3133
|
+
(LogMetadata.Tag && Object.keys(LogMetadata.Tag).length > 0) && (React__default["default"].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: () => {
|
|
2951
3134
|
dispatch({
|
|
2952
3135
|
type: ActionType.ToggleFilterDrawer,
|
|
2953
3136
|
filterDrawer: FilterDrawer.Tag,
|
|
2954
3137
|
});
|
|
2955
3138
|
} },
|
|
2956
3139
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTag, className: "me-2" }),
|
|
2957
|
-
"Tag"),
|
|
2958
|
-
React__default["default"].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: () => {
|
|
3140
|
+
"Tag")),
|
|
3141
|
+
React__default["default"].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: () => {
|
|
2959
3142
|
dispatch({
|
|
2960
3143
|
type: ActionType.ToggleFilterDrawer,
|
|
2961
3144
|
filterDrawer: FilterDrawer.Action,
|
|
@@ -2963,7 +3146,7 @@ const LogReviewer = (props) => {
|
|
|
2963
3146
|
} },
|
|
2964
3147
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faHammer, className: "me-2" }),
|
|
2965
3148
|
"Action"),
|
|
2966
|
-
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer}`, "aria-label": "toggle advanced filter drawer", onClick: () => {
|
|
3149
|
+
React__default["default"].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: () => {
|
|
2967
3150
|
dispatch({
|
|
2968
3151
|
type: ActionType.ToggleFilterDrawer,
|
|
2969
3152
|
filterDrawer: FilterDrawer.Advanced,
|
|
@@ -2976,25 +3159,29 @@ const LogReviewer = (props) => {
|
|
|
2976
3159
|
if (expandedFilterDrawer) {
|
|
2977
3160
|
if (expandedFilterDrawer === FilterDrawer.Date) {
|
|
2978
3161
|
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Date" },
|
|
2979
|
-
React__default["default"].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) => {
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
dateFilterState: Object.assign(Object.assign({}, dateFilterState), { startDate: { month, day, year } }),
|
|
2983
|
-
});
|
|
3162
|
+
React__default["default"].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) => {
|
|
3163
|
+
dateFilterState.startDate = { month, day, year };
|
|
3164
|
+
handleDateRangeUpdated(dateFilterState);
|
|
2984
3165
|
} }),
|
|
2985
3166
|
' ',
|
|
2986
3167
|
"to",
|
|
2987
3168
|
' ',
|
|
2988
|
-
React__default["default"].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) => {
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
3169
|
+
React__default["default"].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) => {
|
|
3170
|
+
if (year < dateFilterState.startDate.year
|
|
3171
|
+
|| (year === dateFilterState.startDate.year
|
|
3172
|
+
&& month < dateFilterState.startDate.month)
|
|
3173
|
+
|| (year === dateFilterState.startDate.year
|
|
3174
|
+
&& month === dateFilterState.startDate.month
|
|
3175
|
+
&& day < dateFilterState.startDate.day)) {
|
|
3176
|
+
return alert$1('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
3177
|
+
}
|
|
3178
|
+
dateFilterState.endDate = { month, day, year };
|
|
3179
|
+
handleDateRangeUpdated(dateFilterState);
|
|
2993
3180
|
} })));
|
|
2994
3181
|
}
|
|
2995
3182
|
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
2996
3183
|
// Create item picker items
|
|
2997
|
-
const pickableItems = (Object.keys((
|
|
3184
|
+
const pickableItems = (Object.keys((_g = LogMetadata.Context) !== null && _g !== void 0 ? _g : {})
|
|
2998
3185
|
.map((context) => {
|
|
2999
3186
|
var _a;
|
|
3000
3187
|
const value = ((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {})[context];
|
|
@@ -3015,15 +3202,15 @@ const LogReviewer = (props) => {
|
|
|
3015
3202
|
})
|
|
3016
3203
|
.map((subcontext) => {
|
|
3017
3204
|
return {
|
|
3018
|
-
id:
|
|
3205
|
+
id: subcontext,
|
|
3019
3206
|
name: genHumanReadableName(subcontext),
|
|
3020
3207
|
isGroup: false,
|
|
3021
|
-
checked:
|
|
3208
|
+
checked: contextFilterState[context][subcontext],
|
|
3022
3209
|
};
|
|
3023
3210
|
}));
|
|
3024
3211
|
const item = {
|
|
3025
3212
|
id: context,
|
|
3026
|
-
name: context,
|
|
3213
|
+
name: genHumanReadableName(context),
|
|
3027
3214
|
isGroup: true,
|
|
3028
3215
|
children,
|
|
3029
3216
|
};
|
|
@@ -3036,7 +3223,9 @@ const LogReviewer = (props) => {
|
|
|
3036
3223
|
if (pickableItem.isGroup) {
|
|
3037
3224
|
// Has subcontexts
|
|
3038
3225
|
pickableItem.children.forEach((subcontextItem) => {
|
|
3039
|
-
|
|
3226
|
+
if (!subcontextItem.isGroup) {
|
|
3227
|
+
contextFilterState[pickableItem.id][subcontextItem.id] = (subcontextItem.checked);
|
|
3228
|
+
}
|
|
3040
3229
|
});
|
|
3041
3230
|
}
|
|
3042
3231
|
else {
|
|
@@ -3052,11 +3241,15 @@ const LogReviewer = (props) => {
|
|
|
3052
3241
|
}
|
|
3053
3242
|
else if (expandedFilterDrawer === FilterDrawer.Tag) {
|
|
3054
3243
|
// Create filter UI
|
|
3055
|
-
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Tags" }, Object.keys(
|
|
3244
|
+
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Tags" }, Object.keys((_h = LogMetadata.Tag) !== null && _h !== void 0 ? _h : {})
|
|
3056
3245
|
.map((tag, i) => {
|
|
3057
3246
|
const description = genHumanReadableName(tag);
|
|
3058
|
-
return (React__default["default"].createElement(CheckboxButton, { id: `LogReviewer-tag-${tag}-checkbox`, text: description, ariaLabel: `
|
|
3247
|
+
return (React__default["default"].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) => {
|
|
3059
3248
|
tagFilterState[tag] = checked;
|
|
3249
|
+
dispatch({
|
|
3250
|
+
type: ActionType.UpdateTagFilterState,
|
|
3251
|
+
tagFilterState,
|
|
3252
|
+
});
|
|
3060
3253
|
} }));
|
|
3061
3254
|
})));
|
|
3062
3255
|
}
|
|
@@ -3087,29 +3280,33 @@ const LogReviewer = (props) => {
|
|
|
3087
3280
|
}, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
|
|
3088
3281
|
(actionErrorFilterState.type === undefined
|
|
3089
3282
|
|| actionErrorFilterState.type === LogType$1.Action) && (React__default["default"].createElement(TabBox, { title: "Action Log Details" },
|
|
3090
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Action" }, Object.keys(LogAction$1)
|
|
3283
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Action", className: "mb-2" }, Object.keys(LogAction$1)
|
|
3091
3284
|
.map((action, i) => {
|
|
3092
3285
|
const description = genHumanReadableName(action);
|
|
3093
|
-
return (React__default["default"].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) => {
|
|
3286
|
+
return (React__default["default"].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) => {
|
|
3094
3287
|
actionErrorFilterState.action[action] = checked;
|
|
3288
|
+
console.log(actionErrorFilterState, action, checked);
|
|
3095
3289
|
dispatch({
|
|
3096
3290
|
type: ActionType.UpdateActionErrorFilterState,
|
|
3097
3291
|
actionErrorFilterState,
|
|
3098
3292
|
});
|
|
3099
3293
|
} }));
|
|
3100
3294
|
})),
|
|
3101
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Target" },
|
|
3102
|
-
.
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
actionErrorFilterState,
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3295
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Target" },
|
|
3296
|
+
(Object.keys((_j = LogMetadata.Target) !== null && _j !== void 0 ? _j : {}).length === 0) && (React__default["default"].createElement("div", null, "This app does not have any targets yet.")),
|
|
3297
|
+
Object.keys((_k = LogMetadata.Target) !== null && _k !== void 0 ? _k : {})
|
|
3298
|
+
.map((target, i) => {
|
|
3299
|
+
var _a;
|
|
3300
|
+
const description = genHumanReadableName(target);
|
|
3301
|
+
return (React__default["default"].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) => {
|
|
3302
|
+
actionErrorFilterState.target[target] = checked;
|
|
3303
|
+
console.log(actionErrorFilterState, target, checked);
|
|
3304
|
+
dispatch({
|
|
3305
|
+
type: ActionType.UpdateActionErrorFilterState,
|
|
3306
|
+
actionErrorFilterState,
|
|
3307
|
+
});
|
|
3308
|
+
}, noMarginOnRight: i === Object.keys((_a = LogMetadata.Target) !== null && _a !== void 0 ? _a : {}).length - 1 }));
|
|
3309
|
+
})))),
|
|
3113
3310
|
(actionErrorFilterState.type === undefined
|
|
3114
3311
|
|| actionErrorFilterState.type === LogType$1.Error) && (React__default["default"].createElement(TabBox, { title: "Error Log Details" },
|
|
3115
3312
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
@@ -3123,7 +3320,7 @@ const LogReviewer = (props) => {
|
|
|
3123
3320
|
} })),
|
|
3124
3321
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
3125
3322
|
React__default["default"].createElement("span", { className: "input-group-text" }, "Error Code"),
|
|
3126
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for error code", value: actionErrorFilterState.
|
|
3323
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for error code", value: actionErrorFilterState.errorCode, onChange: (e) => {
|
|
3127
3324
|
actionErrorFilterState.errorCode = ((e.target.value)
|
|
3128
3325
|
.trim()
|
|
3129
3326
|
.toUpperCase());
|
|
@@ -3271,37 +3468,38 @@ const LogReviewer = (props) => {
|
|
|
3271
3468
|
advancedFilterState,
|
|
3272
3469
|
});
|
|
3273
3470
|
}, noMarginOnRight: true })),
|
|
3274
|
-
React__default["default"].createElement("div", { className: "
|
|
3275
|
-
React__default["default"].createElement("
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
.
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
React__default["default"].createElement("
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
.
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3471
|
+
advancedFilterState.source !== LogSource$1.Client && (React__default["default"].createElement("div", { className: "mt-2" },
|
|
3472
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
3473
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Path"),
|
|
3474
|
+
React__default["default"].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) => {
|
|
3475
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
3476
|
+
.trim());
|
|
3477
|
+
dispatch({
|
|
3478
|
+
type: ActionType.UpdateAdvancedFilterState,
|
|
3479
|
+
advancedFilterState,
|
|
3480
|
+
});
|
|
3481
|
+
} })),
|
|
3482
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
3483
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
3484
|
+
React__default["default"].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) => {
|
|
3485
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
3486
|
+
.trim());
|
|
3487
|
+
dispatch({
|
|
3488
|
+
type: ActionType.UpdateAdvancedFilterState,
|
|
3489
|
+
advancedFilterState,
|
|
3490
|
+
});
|
|
3491
|
+
} })))))));
|
|
3294
3492
|
}
|
|
3295
3493
|
}
|
|
3296
3494
|
// Filters UI
|
|
3297
3495
|
const filters = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
3298
3496
|
filterToggles,
|
|
3299
|
-
filterDrawer && (React__default["default"].createElement(Drawer,
|
|
3497
|
+
filterDrawer && (React__default["default"].createElement(Drawer, { customBackgroundColor: "#eee" }, filterDrawer))));
|
|
3300
3498
|
// Actually filter the logs
|
|
3301
3499
|
// > Perform filters
|
|
3302
3500
|
const logs = [];
|
|
3303
3501
|
Object.keys(logMap).forEach((year) => {
|
|
3304
|
-
Object.keys(logMap).forEach((month) => {
|
|
3502
|
+
Object.keys(logMap[year]).forEach((month) => {
|
|
3305
3503
|
logMap[year][month].forEach((log) => {
|
|
3306
3504
|
/* ----------- Date Filter ---------- */
|
|
3307
3505
|
var _a;
|
|
@@ -3337,16 +3535,23 @@ const LogReviewer = (props) => {
|
|
|
3337
3535
|
// Whole context is deselected
|
|
3338
3536
|
contextFilterState[log.context] === false
|
|
3339
3537
|
// None of the subcontexts are selected
|
|
3340
|
-
|| (
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3538
|
+
|| (
|
|
3539
|
+
// Has subcontexts
|
|
3540
|
+
typeof contextFilterState[log.context] !== 'boolean'
|
|
3541
|
+
// None of the subcontexts are selected
|
|
3542
|
+
&& Object.values((_a = contextFilterState[log.context]) !== null && _a !== void 0 ? _a : {})
|
|
3543
|
+
.every((isSelected) => {
|
|
3544
|
+
return !isSelected;
|
|
3545
|
+
}))) {
|
|
3546
|
+
console.log(log.context, contextFilterState);
|
|
3344
3547
|
return;
|
|
3345
3548
|
}
|
|
3346
3549
|
// Subcontext doesn't match
|
|
3347
3550
|
if (
|
|
3348
|
-
// Log
|
|
3349
|
-
log.
|
|
3551
|
+
// Log context is not "uncategorized" (no point in further filters)
|
|
3552
|
+
log.context !== LogBuiltInMetadata.Context.Uncategorized
|
|
3553
|
+
// Log has a subcontext
|
|
3554
|
+
&& log.subcontext
|
|
3350
3555
|
// Context has subcontexts
|
|
3351
3556
|
&& (contextFilterState[log.context]
|
|
3352
3557
|
&& contextFilterState[log.context] !== false
|
|
@@ -3358,12 +3563,16 @@ const LogReviewer = (props) => {
|
|
|
3358
3563
|
/* -------------- Tags -------------- */
|
|
3359
3564
|
// No tags match
|
|
3360
3565
|
if (
|
|
3361
|
-
//
|
|
3362
|
-
|
|
3566
|
+
// At least one tag is required
|
|
3567
|
+
Object.values(tagFilterState)
|
|
3568
|
+
.filter((isSelected) => {
|
|
3569
|
+
return isSelected;
|
|
3570
|
+
})
|
|
3571
|
+
.length > 0
|
|
3363
3572
|
// No tags match
|
|
3364
|
-
&&
|
|
3573
|
+
&& log.tags.every((tag) => {
|
|
3365
3574
|
return !tagFilterState[tag];
|
|
3366
|
-
}))
|
|
3575
|
+
})) {
|
|
3367
3576
|
return;
|
|
3368
3577
|
}
|
|
3369
3578
|
/* ------- Actions and Errors ------- */
|
|
@@ -3497,7 +3706,7 @@ const LogReviewer = (props) => {
|
|
|
3497
3706
|
// Device info exists
|
|
3498
3707
|
&& log.device
|
|
3499
3708
|
// Mobile filter doesn't match
|
|
3500
|
-
&& (advancedFilterState.isMobile
|
|
3709
|
+
&& (advancedFilterState.isMobile !== log.device.isMobile)) {
|
|
3501
3710
|
return;
|
|
3502
3711
|
}
|
|
3503
3712
|
// Log source doesn't match
|
|
@@ -3562,18 +3771,18 @@ const LogReviewer = (props) => {
|
|
|
3562
3771
|
type: ParamType$1.Int,
|
|
3563
3772
|
},
|
|
3564
3773
|
{
|
|
3565
|
-
title: 'Student',
|
|
3774
|
+
title: 'Student?',
|
|
3566
3775
|
param: 'isLearner',
|
|
3567
3776
|
type: ParamType$1.Boolean,
|
|
3568
3777
|
},
|
|
3569
3778
|
{
|
|
3570
|
-
title: 'Teaching Staff',
|
|
3779
|
+
title: 'Teaching Staff?',
|
|
3571
3780
|
param: 'isTTM',
|
|
3572
3781
|
type: ParamType$1.Boolean,
|
|
3573
3782
|
startsHidden: true,
|
|
3574
3783
|
},
|
|
3575
3784
|
{
|
|
3576
|
-
title: 'Admin',
|
|
3785
|
+
title: 'Admin?',
|
|
3577
3786
|
param: 'isAdmin',
|
|
3578
3787
|
type: ParamType$1.Boolean,
|
|
3579
3788
|
startsHidden: true,
|
|
@@ -3608,7 +3817,7 @@ const LogReviewer = (props) => {
|
|
|
3608
3817
|
startsHidden: true,
|
|
3609
3818
|
},
|
|
3610
3819
|
{
|
|
3611
|
-
title: 'Mobile',
|
|
3820
|
+
title: 'Mobile?',
|
|
3612
3821
|
param: 'device.isMobile',
|
|
3613
3822
|
type: ParamType$1.Boolean,
|
|
3614
3823
|
startsHidden: true,
|
|
@@ -3726,12 +3935,20 @@ const LogReviewer = (props) => {
|
|
|
3726
3935
|
startsHidden: true,
|
|
3727
3936
|
},
|
|
3728
3937
|
];
|
|
3938
|
+
// Nothing to show notice
|
|
3939
|
+
const noLogsNotice = (logs.length === 0
|
|
3940
|
+
? (React__default["default"].createElement("div", { className: "alert alert-warning text-center mt-2" },
|
|
3941
|
+
React__default["default"].createElement("h4", { className: "m-1" }, "No Logs to Show"),
|
|
3942
|
+
React__default["default"].createElement("div", null, "Either your filters are too strict or no matching logs have been created yet.")))
|
|
3943
|
+
: undefined);
|
|
3729
3944
|
// Create intelliTable
|
|
3730
|
-
const dataTable = (React__default["default"].createElement(IntelliTable, { title: "Matching Logs", id: "logs", data: logs, columns: columns }));
|
|
3945
|
+
const dataTable = (React__default["default"].createElement(IntelliTable, { title: "Matching Logs:", id: "logs", data: logs, columns: columns }));
|
|
3731
3946
|
// Main body
|
|
3732
3947
|
body = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
3733
3948
|
filters,
|
|
3734
|
-
|
|
3949
|
+
React__default["default"].createElement("div", { className: "mt-2" },
|
|
3950
|
+
dataTable,
|
|
3951
|
+
noLogsNotice)));
|
|
3735
3952
|
}
|
|
3736
3953
|
/* ---------- Wrap in Modal --------- */
|
|
3737
3954
|
return (React__default["default"].createElement("div", { className: "LogReviewer-outer-container" },
|
|
@@ -3739,14 +3956,10 @@ const LogReviewer = (props) => {
|
|
|
3739
3956
|
React__default["default"].createElement("div", { className: "LogReviewer-inner-container" },
|
|
3740
3957
|
React__default["default"].createElement("div", { className: "LogReviewer-header" },
|
|
3741
3958
|
React__default["default"].createElement("div", { className: "LogReviewer-header-title" },
|
|
3742
|
-
React__default["default"].createElement("
|
|
3743
|
-
React__default["default"].createElement("
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
padding: 0,
|
|
3747
|
-
margin: 0,
|
|
3748
|
-
} },
|
|
3749
|
-
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes }))),
|
|
3959
|
+
React__default["default"].createElement("h3", { className: "text-center m-0" }, "Log Review Dashboard")),
|
|
3960
|
+
React__default["default"].createElement("div", { style: { width: 0 } },
|
|
3961
|
+
React__default["default"].createElement("button", { type: "button", className: "LogReviewer-header-close-button btn btn-dark btn-lg pe-0", "aria-label": "close log reviewer panel", onClick: onClose },
|
|
3962
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes })))),
|
|
3750
3963
|
React__default["default"].createElement("div", { className: "LogReviewer-contents" }, body))));
|
|
3751
3964
|
};
|
|
3752
3965
|
|
|
@@ -4070,22 +4283,24 @@ const initServer = (opts) => {
|
|
|
4070
4283
|
* @param {number} month the month to query (e.g. 1 = January)
|
|
4071
4284
|
* @returns {Log[]} list of logs from the given month
|
|
4072
4285
|
*/
|
|
4073
|
-
opts.app.
|
|
4286
|
+
opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler({
|
|
4074
4287
|
paramTypes: {
|
|
4075
4288
|
year: ParamType$1.Int,
|
|
4076
4289
|
month: ParamType$1.Int,
|
|
4077
4290
|
},
|
|
4078
4291
|
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4079
4292
|
// Get user info
|
|
4080
|
-
const { userId, isAdmin } = params;
|
|
4293
|
+
const { year, month, userId, isAdmin, } = params;
|
|
4081
4294
|
// Validate user
|
|
4082
|
-
// isAdmin is already checked because path starts with '/admin'
|
|
4083
4295
|
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
4084
4296
|
if (!canReview) {
|
|
4085
4297
|
throw new ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ReactKitErrorCode$1.NotAllowedToReviewLogs);
|
|
4086
4298
|
}
|
|
4087
4299
|
// Query for logs
|
|
4088
|
-
const logs = yield _logCollection.find({
|
|
4300
|
+
const logs = yield _logCollection.find({
|
|
4301
|
+
year,
|
|
4302
|
+
month,
|
|
4303
|
+
});
|
|
4089
4304
|
// Return logs
|
|
4090
4305
|
return logs;
|
|
4091
4306
|
}),
|
|
@@ -4389,18 +4604,6 @@ const parseUserAgent = (userAgent) => {
|
|
|
4389
4604
|
};
|
|
4390
4605
|
};
|
|
4391
4606
|
|
|
4392
|
-
/**
|
|
4393
|
-
* Allowed log levels
|
|
4394
|
-
* @author Gabe Abrams
|
|
4395
|
-
*/
|
|
4396
|
-
var LogLevel;
|
|
4397
|
-
(function (LogLevel) {
|
|
4398
|
-
LogLevel["Warn"] = "Warn";
|
|
4399
|
-
LogLevel["Info"] = "Info";
|
|
4400
|
-
LogLevel["Debug"] = "Debug";
|
|
4401
|
-
})(LogLevel || (LogLevel = {}));
|
|
4402
|
-
var LogLevel$1 = LogLevel;
|
|
4403
|
-
|
|
4404
4607
|
/**
|
|
4405
4608
|
* Generate an express API route handler
|
|
4406
4609
|
* @author Gabe Abrams
|
|
@@ -4746,7 +4949,7 @@ const genRouteHandler = (opts) => {
|
|
|
4746
4949
|
isAdmin: !!launchInfo.isAdmin,
|
|
4747
4950
|
isTTM: !!launchInfo.isTTM,
|
|
4748
4951
|
courseId: launchInfo.courseId,
|
|
4749
|
-
courseName: launchInfo.
|
|
4952
|
+
courseName: launchInfo.contextLabel,
|
|
4750
4953
|
browser,
|
|
4751
4954
|
device,
|
|
4752
4955
|
year,
|
|
@@ -4773,7 +4976,7 @@ const genRouteHandler = (opts) => {
|
|
|
4773
4976
|
}
|
|
4774
4977
|
: {
|
|
4775
4978
|
type: LogType$1.Action,
|
|
4776
|
-
target: ((_m = opts.target) !== null && _m !== void 0 ? _m : LogBuiltInMetadata.Target.
|
|
4979
|
+
target: ((_m = opts.target) !== null && _m !== void 0 ? _m : LogBuiltInMetadata.Target.NoTarget),
|
|
4777
4980
|
action: ((_o = opts.action) !== null && _o !== void 0 ? _o : LogAction$1.Unknown),
|
|
4778
4981
|
});
|
|
4779
4982
|
// Source-specific info
|