dce-reactkit 3.9.4-beta-prompt.2 → 3.9.4-beta-logreviewer.3
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 +670 -869
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AppWrapper.d.ts +0 -24
- package/dist/cjs/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
- package/dist/cjs/types/index.d.ts +2 -2
- package/dist/cjs/types/types/LogReviewerFilterState/ActionErrorFilterState.d.ts +13 -0
- package/dist/cjs/types/types/LogReviewerFilterState/AdvancedFilterState.d.ts +17 -0
- package/dist/cjs/types/types/LogReviewerFilterState/ContextFilterState.d.ts +6 -0
- package/dist/cjs/types/types/LogReviewerFilterState/DateFilterState.d.ts +13 -0
- package/dist/cjs/types/types/LogReviewerFilterState/TagFilterState.d.ts +4 -0
- package/dist/cjs/types/types/LogReviewerFilterState/index.d.ts +17 -0
- package/dist/cjs/types/types/ModalType.d.ts +0 -1
- package/dist/esm/index.js +672 -870
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AppWrapper.d.ts +0 -24
- package/dist/esm/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
- package/dist/esm/types/index.d.ts +2 -2
- package/dist/esm/types/types/LogReviewerFilterState/ActionErrorFilterState.d.ts +13 -0
- package/dist/esm/types/types/LogReviewerFilterState/AdvancedFilterState.d.ts +17 -0
- package/dist/esm/types/types/LogReviewerFilterState/ContextFilterState.d.ts +6 -0
- package/dist/esm/types/types/LogReviewerFilterState/DateFilterState.d.ts +13 -0
- package/dist/esm/types/types/LogReviewerFilterState/TagFilterState.d.ts +4 -0
- package/dist/esm/types/types/LogReviewerFilterState/index.d.ts +17 -0
- package/dist/esm/types/types/ModalType.d.ts +0 -1
- package/dist/index.d.ts +1 -26
- package/package.json +1 -1
- package/src/components/AppWrapper.tsx +0 -216
- package/src/components/LogReviewer.tsx +840 -1232
- package/src/components/Modal/index.tsx +0 -3
- package/src/constants/LOG_REVIEW_GET_LOGS_ROUTE.ts +9 -0
- package/src/index.ts +0 -2
- package/src/server/initServer.ts +216 -19
- package/src/types/LogReviewerFilterState/ActionErrorFilterState.ts +21 -0
- package/src/types/LogReviewerFilterState/AdvancedFilterState.ts +33 -0
- package/src/types/LogReviewerFilterState/ContextFilterState.ts +13 -0
- package/src/types/LogReviewerFilterState/DateFilterState.ts +23 -0
- package/src/types/LogReviewerFilterState/TagFilterState.ts +6 -0
- package/src/types/LogReviewerFilterState/index.ts +24 -0
- package/src/types/ModalType.tsx +0 -1
- package/dist/cjs/types/constants/LOG_REVIEW_ROUTE_PATH_PREFIX.d.ts +0 -6
- package/dist/esm/types/constants/LOG_REVIEW_ROUTE_PATH_PREFIX.d.ts +0 -6
- package/src/constants/LOG_REVIEW_ROUTE_PATH_PREFIX.ts +0 -9
package/dist/cjs/index.js
CHANGED
|
@@ -186,7 +186,6 @@ var ModalButtonType$1 = ModalButtonType;
|
|
|
186
186
|
var ModalType;
|
|
187
187
|
(function (ModalType) {
|
|
188
188
|
ModalType["Okay"] = "okay";
|
|
189
|
-
ModalType["Cancel"] = "cancel";
|
|
190
189
|
ModalType["OkayCancel"] = "okay-cancel";
|
|
191
190
|
ModalType["YesNo"] = "yes-no";
|
|
192
191
|
ModalType["YesNoCancel"] = "yes-no-cancel";
|
|
@@ -341,9 +340,6 @@ const modalTypeToModalButtonTypes = {
|
|
|
341
340
|
[ModalType$1.Okay]: [
|
|
342
341
|
ModalButtonType$1.Okay,
|
|
343
342
|
],
|
|
344
|
-
[ModalType$1.Cancel]: [
|
|
345
|
-
ModalButtonType$1.Cancel,
|
|
346
|
-
],
|
|
347
343
|
[ModalType$1.OkayCancel]: [
|
|
348
344
|
ModalButtonType$1.Okay,
|
|
349
345
|
ModalButtonType$1.Cancel,
|
|
@@ -1084,74 +1080,6 @@ const confirm = (title, text, opts) => __awaiter(void 0, void 0, void 0, functio
|
|
|
1084
1080
|
});
|
|
1085
1081
|
});
|
|
1086
1082
|
/*----------------------------------------*/
|
|
1087
|
-
/* --------------- Prompt -------------- */
|
|
1088
|
-
/*----------------------------------------*/
|
|
1089
|
-
// Stored copies of setters
|
|
1090
|
-
let setPromptInfo;
|
|
1091
|
-
// Function to call when prompt is closed
|
|
1092
|
-
let onPromptClosed;
|
|
1093
|
-
/**
|
|
1094
|
-
* Show a prompt modal asking the user for input
|
|
1095
|
-
* @author Yuen Ler Chow
|
|
1096
|
-
* @param title the title text to display at the top of the prompt
|
|
1097
|
-
* @param text the text to display in the prompt
|
|
1098
|
-
* @param [opts={}] additional options for the prompt dialog
|
|
1099
|
-
* @param [opts.placeholder] the placeholder text for the input field
|
|
1100
|
-
* @param [opts.defaultText] the default text for the input field
|
|
1101
|
-
* @param [opts.confirmButtonText=Okay] the text of the confirm button
|
|
1102
|
-
* @param [opts.confirmButtonVariant=Variant.Dark] the variant of the confirm button
|
|
1103
|
-
* @param [opts.cancelButtonText=Cancel] the text of the cancel button
|
|
1104
|
-
* @param [opts.cancelButtonVariant=Variant.Secondary] the variant of the cancel button
|
|
1105
|
-
* @returns Promise that resolves with the input string or null if canceled
|
|
1106
|
-
*/
|
|
1107
|
-
const prompt = (title, text, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1108
|
-
var _a;
|
|
1109
|
-
// Wait for helper to exist
|
|
1110
|
-
yield waitForHelper(() => {
|
|
1111
|
-
return !!setPromptInfo;
|
|
1112
|
-
});
|
|
1113
|
-
// Fallback if prompt is not available
|
|
1114
|
-
if (!setPromptInfo) {
|
|
1115
|
-
const resultPassesValidation = false;
|
|
1116
|
-
while (!resultPassesValidation) {
|
|
1117
|
-
// eslint-disable-next-line no-alert
|
|
1118
|
-
const result = window.prompt(`${title}\n\n${text}`, (_a = opts === null || opts === void 0 ? void 0 : opts.defaultText) !== null && _a !== void 0 ? _a : '');
|
|
1119
|
-
if (result === null) {
|
|
1120
|
-
return null;
|
|
1121
|
-
}
|
|
1122
|
-
// Validate min num chars
|
|
1123
|
-
const minNumCharsValidationError = (((opts === null || opts === void 0 ? void 0 : opts.minNumChars) && result.length < opts.minNumChars)
|
|
1124
|
-
? `Please enter at least ${opts.minNumChars} characters.`
|
|
1125
|
-
: undefined);
|
|
1126
|
-
// Run custom validation
|
|
1127
|
-
const customValidationError = ((opts === null || opts === void 0 ? void 0 : opts.findValidationError)
|
|
1128
|
-
&& opts.findValidationError(result));
|
|
1129
|
-
// Show validation issue
|
|
1130
|
-
if (minNumCharsValidationError || customValidationError) {
|
|
1131
|
-
alert('Invalid Input', `${minNumCharsValidationError !== null && minNumCharsValidationError !== void 0 ? minNumCharsValidationError : ''} ${customValidationError !== null && customValidationError !== void 0 ? customValidationError : ''}`);
|
|
1132
|
-
}
|
|
1133
|
-
else {
|
|
1134
|
-
return result;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
// Return promise that resolves with result of prompt
|
|
1139
|
-
return new Promise((resolve) => {
|
|
1140
|
-
var _a;
|
|
1141
|
-
// Setup handler
|
|
1142
|
-
onPromptClosed = (result) => {
|
|
1143
|
-
resolve(result);
|
|
1144
|
-
};
|
|
1145
|
-
// Show the prompt
|
|
1146
|
-
setPromptInfo({
|
|
1147
|
-
title,
|
|
1148
|
-
text,
|
|
1149
|
-
currentInputFieldText: ((_a = opts === null || opts === void 0 ? void 0 : opts.defaultText) !== null && _a !== void 0 ? _a : ''),
|
|
1150
|
-
opts: (opts !== null && opts !== void 0 ? opts : {}),
|
|
1151
|
-
});
|
|
1152
|
-
});
|
|
1153
|
-
});
|
|
1154
|
-
/*----------------------------------------*/
|
|
1155
1083
|
/* ------------- Fatal Error ------------ */
|
|
1156
1084
|
/*----------------------------------------*/
|
|
1157
1085
|
// Stored copies of setters
|
|
@@ -1167,14 +1095,14 @@ const fatalErrorHandlers = [];
|
|
|
1167
1095
|
* @param [errorTitle] title of the error box
|
|
1168
1096
|
*/
|
|
1169
1097
|
const showFatalError = (error, errorTitle = 'An Error Occurred') => __awaiter(void 0, void 0, void 0, function* () {
|
|
1170
|
-
var
|
|
1098
|
+
var _a, _b;
|
|
1171
1099
|
// Determine message and code
|
|
1172
1100
|
const message = (typeof error === 'string'
|
|
1173
1101
|
? error.trim()
|
|
1174
|
-
: String((
|
|
1102
|
+
: String((_a = error.message) !== null && _a !== void 0 ? _a : 'An unknown error occurred.'));
|
|
1175
1103
|
const code = (typeof error === 'string'
|
|
1176
1104
|
? ReactKitErrorCode$1.NoCode
|
|
1177
|
-
: String((
|
|
1105
|
+
: String((_b = error.code) !== null && _b !== void 0 ? _b : ReactKitErrorCode$1.NoCode));
|
|
1178
1106
|
// Call all fatal error listeners
|
|
1179
1107
|
try {
|
|
1180
1108
|
fatalErrorHandlers.forEach((handler) => {
|
|
@@ -1301,9 +1229,6 @@ const AppWrapper = (props) => {
|
|
|
1301
1229
|
// Confirm
|
|
1302
1230
|
const [confirmInfo, setConfirmInfoInner,] = React.useState(undefined);
|
|
1303
1231
|
setConfirmInfo = setConfirmInfoInner;
|
|
1304
|
-
// Prompt
|
|
1305
|
-
const [promptInfo, setPromptInfoInner] = React.useState(undefined);
|
|
1306
|
-
setPromptInfo = setPromptInfoInner;
|
|
1307
1232
|
// Session expired
|
|
1308
1233
|
const [sessionHasExpired, setSessionHasExpiredInner,] = React.useState(false);
|
|
1309
1234
|
setSessionHasExpired = setSessionHasExpiredInner;
|
|
@@ -1334,37 +1259,6 @@ const AppWrapper = (props) => {
|
|
|
1334
1259
|
}
|
|
1335
1260
|
}, onTopOfOtherModals: true, dontAllowBackdropExit: true }, confirmInfo.text));
|
|
1336
1261
|
}
|
|
1337
|
-
/* ------------- Prompt ------------ */
|
|
1338
|
-
if (promptInfo) {
|
|
1339
|
-
// Run min char validation
|
|
1340
|
-
const minNumCharsValidationError = ((promptInfo.opts.minNumChars
|
|
1341
|
-
&& promptInfo.currentInputFieldText.length < promptInfo.opts.minNumChars)
|
|
1342
|
-
? `Please enter at least ${promptInfo.opts.minNumChars} characters.`
|
|
1343
|
-
: undefined);
|
|
1344
|
-
// Run custom validation
|
|
1345
|
-
const customValidationError = (promptInfo.opts.findValidationError
|
|
1346
|
-
&& promptInfo.opts.findValidationError(promptInfo.currentInputFieldText));
|
|
1347
|
-
modal = (React__default["default"].createElement(Modal, { key: `prompt-${promptInfo.title}-${promptInfo.text}`, title: promptInfo.title,
|
|
1348
|
-
// Don't show ok button if there is a validation error
|
|
1349
|
-
type: ((customValidationError || minNumCharsValidationError)
|
|
1350
|
-
? ModalType$1.Cancel
|
|
1351
|
-
: ModalType$1.OkayCancel), okayLabel: promptInfo.opts.confirmButtonText, okayVariant: promptInfo.opts.confirmButtonVariant, cancelLabel: promptInfo.opts.cancelButtonText, cancelVariant: promptInfo.opts.cancelButtonVariant, onClose: (buttonType) => {
|
|
1352
|
-
const result = (buttonType === ModalButtonType$1.Okay
|
|
1353
|
-
? promptInfo.currentInputFieldText
|
|
1354
|
-
: null);
|
|
1355
|
-
setPromptInfo(undefined);
|
|
1356
|
-
if (onPromptClosed) {
|
|
1357
|
-
onPromptClosed(result);
|
|
1358
|
-
}
|
|
1359
|
-
}, onTopOfOtherModals: true, dontAllowBackdropExit: true },
|
|
1360
|
-
React__default["default"].createElement("div", { className: "p-3" },
|
|
1361
|
-
React__default["default"].createElement("p", null, promptInfo.text),
|
|
1362
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control mb-2", placeholder: promptInfo.opts.placeholder, value: promptInfo.currentInputFieldText, onChange: (e) => {
|
|
1363
|
-
return setPromptInfo(Object.assign(Object.assign({}, promptInfo), { currentInputFieldText: e.target.value }));
|
|
1364
|
-
} }),
|
|
1365
|
-
minNumCharsValidationError && (React__default["default"].createElement("div", { className: "text-danger fw-bold mt-2" }, minNumCharsValidationError)),
|
|
1366
|
-
customValidationError && (React__default["default"].createElement("div", { className: "text-danger fw-bold mt-2" }, customValidationError)))));
|
|
1367
|
-
}
|
|
1368
1262
|
/* ------ Custom Modal Portals ------ */
|
|
1369
1263
|
// Custom modal portals
|
|
1370
1264
|
const customModalPortals = [];
|
|
@@ -2680,10 +2574,10 @@ const getHumanReadableDate = (dateOrTimestamp) => {
|
|
|
2680
2574
|
};
|
|
2681
2575
|
|
|
2682
2576
|
/**
|
|
2683
|
-
* Path of the route for
|
|
2577
|
+
* Path of the route for getting logs for log review
|
|
2684
2578
|
* @author Gabe Abrams
|
|
2685
2579
|
*/
|
|
2686
|
-
const
|
|
2580
|
+
const LOG_REVIEW_GET_LOGS_ROUTE = `/admin${ROUTE_PATH_PREFIX}/logs`;
|
|
2687
2581
|
|
|
2688
2582
|
/**
|
|
2689
2583
|
* Source of a log event
|
|
@@ -3643,7 +3537,7 @@ var ActionType$6;
|
|
|
3643
3537
|
(function (ActionType) {
|
|
3644
3538
|
// Show the loading bar
|
|
3645
3539
|
ActionType["StartLoading"] = "start-loading";
|
|
3646
|
-
// Finish loading
|
|
3540
|
+
// Finish loading logs
|
|
3647
3541
|
ActionType["FinishLoading"] = "finish-loading";
|
|
3648
3542
|
// Reset filters to initial values
|
|
3649
3543
|
ActionType["ResetFilters"] = "reset-filters";
|
|
@@ -3661,6 +3555,12 @@ var ActionType$6;
|
|
|
3661
3555
|
ActionType["UpdateActionErrorFilterState"] = "update-action-error-filter-state";
|
|
3662
3556
|
// Update the advanced filter state
|
|
3663
3557
|
ActionType["UpdateAdvancedFilterState"] = "update-advanced-filter-state";
|
|
3558
|
+
// Increment the page number
|
|
3559
|
+
ActionType["IncrementPageNumber"] = "increment-page-number";
|
|
3560
|
+
// Decrement the page number
|
|
3561
|
+
ActionType["DecrementPageNumber"] = "decrement-page-number";
|
|
3562
|
+
// Set has another page
|
|
3563
|
+
ActionType["SetHasAnotherPage"] = "set-has-another-page";
|
|
3664
3564
|
})(ActionType$6 || (ActionType$6 = {}));
|
|
3665
3565
|
/**
|
|
3666
3566
|
* Reducer that executes actions
|
|
@@ -3674,7 +3574,7 @@ const reducer$7 = (state, action) => {
|
|
|
3674
3574
|
return Object.assign(Object.assign({}, state), { loading: true });
|
|
3675
3575
|
}
|
|
3676
3576
|
case ActionType$6.FinishLoading: {
|
|
3677
|
-
return Object.assign(Object.assign({}, state), { loading: false,
|
|
3577
|
+
return Object.assign(Object.assign({}, state), { loading: false, logs: action.logs });
|
|
3678
3578
|
}
|
|
3679
3579
|
case ActionType$6.ToggleFilterDrawer: {
|
|
3680
3580
|
return Object.assign(Object.assign({}, state), { expandedFilterDrawer: (state.expandedFilterDrawer === action.filterDrawer
|
|
@@ -3702,6 +3602,15 @@ const reducer$7 = (state, action) => {
|
|
|
3702
3602
|
case ActionType$6.UpdateAdvancedFilterState: {
|
|
3703
3603
|
return Object.assign(Object.assign({}, state), { advancedFilterState: action.advancedFilterState });
|
|
3704
3604
|
}
|
|
3605
|
+
case ActionType$6.IncrementPageNumber: {
|
|
3606
|
+
return Object.assign(Object.assign({}, state), { pageNumber: state.pageNumber + 1 });
|
|
3607
|
+
}
|
|
3608
|
+
case ActionType$6.DecrementPageNumber: {
|
|
3609
|
+
return Object.assign(Object.assign({}, state), { pageNumber: state.pageNumber - 1 });
|
|
3610
|
+
}
|
|
3611
|
+
case ActionType$6.SetHasAnotherPage: {
|
|
3612
|
+
return Object.assign(Object.assign({}, state), { hasAnotherPage: action.hasAnotherPage });
|
|
3613
|
+
}
|
|
3705
3614
|
default: {
|
|
3706
3615
|
return state;
|
|
3707
3616
|
}
|
|
@@ -3819,115 +3728,74 @@ const LogReviewer = (props) => {
|
|
|
3819
3728
|
// Initial state
|
|
3820
3729
|
const initialState = {
|
|
3821
3730
|
loading: true,
|
|
3822
|
-
|
|
3731
|
+
logs: [],
|
|
3823
3732
|
expandedFilterDrawer: undefined,
|
|
3824
3733
|
dateFilterState: initDateFilterState,
|
|
3825
3734
|
contextFilterState: initContextFilterState,
|
|
3826
3735
|
tagFilterState: initTagFilterState,
|
|
3827
3736
|
actionErrorFilterState: initActionErrorFilterState,
|
|
3828
3737
|
advancedFilterState: initAdvancedFilterState,
|
|
3738
|
+
pageNumber: 1,
|
|
3739
|
+
hasAnotherPage: false,
|
|
3829
3740
|
};
|
|
3830
3741
|
// Initialize state
|
|
3831
3742
|
const [state, dispatch] = React.useReducer(reducer$7, initialState);
|
|
3832
3743
|
// Destructure common state
|
|
3833
|
-
const { loading,
|
|
3744
|
+
const { loading, logs, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, pageNumber, hasAnotherPage, } = state;
|
|
3834
3745
|
/*------------------------------------------------------------------------*/
|
|
3835
3746
|
/* ------------------------- Component Functions ------------------------ */
|
|
3836
3747
|
/*------------------------------------------------------------------------*/
|
|
3837
3748
|
/**
|
|
3838
|
-
*
|
|
3839
|
-
* start or end date and the existing logMap
|
|
3840
|
-
* @author Gabe Abrams
|
|
3841
|
-
* @param newDateFilterState the new date filter state
|
|
3842
|
-
* @returns list of year/month combos that need to be loaded
|
|
3843
|
-
*/
|
|
3844
|
-
const listMonthsToLoad = (newDateFilterState) => {
|
|
3845
|
-
// List of year/month combos that need to be loaded
|
|
3846
|
-
const toLoad = [];
|
|
3847
|
-
// Loop through dates
|
|
3848
|
-
let { year, month } = newDateFilterState.startDate;
|
|
3849
|
-
while (
|
|
3850
|
-
// Earlier year
|
|
3851
|
-
(year < newDateFilterState.endDate.year)
|
|
3852
|
-
// Current year but included month
|
|
3853
|
-
|| (year === newDateFilterState.endDate.year
|
|
3854
|
-
&& month <= newDateFilterState.endDate.month)) {
|
|
3855
|
-
// Add to list if not already loaded
|
|
3856
|
-
if (!logMap[year]
|
|
3857
|
-
|| !logMap[year][month]) {
|
|
3858
|
-
toLoad.push({
|
|
3859
|
-
year,
|
|
3860
|
-
month,
|
|
3861
|
-
});
|
|
3862
|
-
}
|
|
3863
|
-
// Increment
|
|
3864
|
-
month += 1;
|
|
3865
|
-
if (month > 12) {
|
|
3866
|
-
month -= 12;
|
|
3867
|
-
year += 1;
|
|
3868
|
-
}
|
|
3869
|
-
}
|
|
3870
|
-
// Return
|
|
3871
|
-
return toLoad;
|
|
3872
|
-
};
|
|
3873
|
-
/**
|
|
3874
|
-
* Handle updated start/end dates (updates state, loads if necessary)
|
|
3875
|
-
* @author Gabe Abrams
|
|
3876
|
-
* @param newDateFilterState the new date filter state
|
|
3749
|
+
* Fetch logs from the server based on current filters
|
|
3877
3750
|
*/
|
|
3878
|
-
const
|
|
3879
|
-
|
|
3880
|
-
dispatch({
|
|
3881
|
-
type: ActionType$6.UpdateDateFilterState,
|
|
3882
|
-
dateFilterState: newDateFilterState,
|
|
3883
|
-
});
|
|
3884
|
-
// Check which year/month combos we need to load
|
|
3885
|
-
const toLoad = listMonthsToLoad(newDateFilterState);
|
|
3886
|
-
// If nothing to load, finished
|
|
3887
|
-
if (toLoad.length === 0) {
|
|
3888
|
-
return;
|
|
3889
|
-
}
|
|
3890
|
-
// Start loading
|
|
3891
|
-
dispatch({
|
|
3892
|
-
type: ActionType$6.StartLoading,
|
|
3893
|
-
});
|
|
3894
|
-
// Load required months
|
|
3751
|
+
const fetchLogs = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
3752
|
+
dispatch({ type: ActionType$6.StartLoading });
|
|
3895
3753
|
try {
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3754
|
+
// Prepare filter parameters
|
|
3755
|
+
const filters = {
|
|
3756
|
+
dateFilterState,
|
|
3757
|
+
contextFilterState,
|
|
3758
|
+
tagFilterState,
|
|
3759
|
+
actionErrorFilterState,
|
|
3760
|
+
advancedFilterState,
|
|
3761
|
+
};
|
|
3762
|
+
// Send filters to the server
|
|
3763
|
+
let fetchedLogs = [];
|
|
3764
|
+
// Get logs from server
|
|
3765
|
+
const response = yield visitServerEndpoint({
|
|
3766
|
+
path: LOG_REVIEW_GET_LOGS_ROUTE,
|
|
3767
|
+
method: 'GET',
|
|
3768
|
+
params: {
|
|
3769
|
+
pageNumber,
|
|
3770
|
+
filters,
|
|
3771
|
+
},
|
|
3772
|
+
});
|
|
3773
|
+
fetchedLogs = fetchedLogs.concat(response.items);
|
|
3774
|
+
dispatch({
|
|
3775
|
+
type: ActionType$6.SetHasAnotherPage,
|
|
3776
|
+
hasAnotherPage: response.hasAnotherPage,
|
|
3777
|
+
});
|
|
3778
|
+
// Update logs in state
|
|
3779
|
+
dispatch({
|
|
3780
|
+
type: ActionType$6.FinishLoading,
|
|
3781
|
+
logs: fetchedLogs,
|
|
3782
|
+
});
|
|
3910
3783
|
}
|
|
3911
3784
|
catch (err) {
|
|
3912
3785
|
return showFatalError(err);
|
|
3913
3786
|
}
|
|
3914
|
-
// Finish loading
|
|
3915
|
-
dispatch({
|
|
3916
|
-
type: ActionType$6.FinishLoading,
|
|
3917
|
-
logMap,
|
|
3918
|
-
});
|
|
3919
3787
|
});
|
|
3920
3788
|
/*------------------------------------------------------------------------*/
|
|
3921
3789
|
/* ------------------------- Lifecycle Functions ------------------------ */
|
|
3922
3790
|
/*------------------------------------------------------------------------*/
|
|
3923
3791
|
/**
|
|
3924
|
-
*
|
|
3925
|
-
* @author Gabe Abrams
|
|
3792
|
+
* Fetch logs whenever page number changes
|
|
3926
3793
|
*/
|
|
3927
3794
|
React.useEffect(() => {
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3795
|
+
fetchLogs();
|
|
3796
|
+
}, [
|
|
3797
|
+
pageNumber,
|
|
3798
|
+
]);
|
|
3931
3799
|
/*------------------------------------------------------------------------*/
|
|
3932
3800
|
/* ------------------------------- Render ------------------------------- */
|
|
3933
3801
|
/*------------------------------------------------------------------------*/
|
|
@@ -3942,703 +3810,481 @@ const LogReviewer = (props) => {
|
|
|
3942
3810
|
React__default["default"].createElement(LoadingSpinner, null)));
|
|
3943
3811
|
}
|
|
3944
3812
|
/* ------------ Review UI ----------- */
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3813
|
+
/*----------------------------------------*/
|
|
3814
|
+
/* ------------ Pagination -------------- */
|
|
3815
|
+
/*----------------------------------------*/
|
|
3816
|
+
const paginationControls = logs.length > 0 && (React__default["default"].createElement("div", { className: "text-center mt-3" },
|
|
3817
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary me-2", disabled: pageNumber <= 1, onClick: () => {
|
|
3818
|
+
dispatch({
|
|
3819
|
+
type: ActionType$6.DecrementPageNumber,
|
|
3820
|
+
});
|
|
3821
|
+
} },
|
|
3822
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faArrowLeft, className: "me-2" }),
|
|
3823
|
+
"Previous Page"),
|
|
3824
|
+
React__default["default"].createElement("span", { className: "mx-3" },
|
|
3825
|
+
"Page",
|
|
3826
|
+
' ',
|
|
3827
|
+
pageNumber),
|
|
3828
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary ms-2", disabled: !hasAnotherPage, onClick: () => {
|
|
3829
|
+
dispatch({
|
|
3830
|
+
type: ActionType$6.IncrementPageNumber,
|
|
3831
|
+
});
|
|
3832
|
+
} },
|
|
3833
|
+
"Next Page",
|
|
3834
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faArrowRight, className: "ms-2" }))));
|
|
3835
|
+
/*----------------------------------------*/
|
|
3836
|
+
/* --------------- Filters -------------- */
|
|
3837
|
+
/*----------------------------------------*/
|
|
3838
|
+
// Filter toggle
|
|
3839
|
+
const filterToggles = (React__default["default"].createElement("div", { className: "LogReviewer-filter-toggles" },
|
|
3840
|
+
React__default["default"].createElement("h3", { className: "m-0" }, "Filters:"),
|
|
3841
|
+
React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
|
|
3842
|
+
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: () => {
|
|
3843
|
+
dispatch({
|
|
3844
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3845
|
+
filterDrawer: FilterDrawer.Date,
|
|
3846
|
+
});
|
|
3847
|
+
} },
|
|
3848
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCalendar, className: "me-2" }),
|
|
3849
|
+
"Date"),
|
|
3850
|
+
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: () => {
|
|
3851
|
+
dispatch({
|
|
3852
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3853
|
+
filterDrawer: FilterDrawer.Context,
|
|
3854
|
+
});
|
|
3855
|
+
} },
|
|
3856
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "me-2" }),
|
|
3857
|
+
"Context"),
|
|
3858
|
+
(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: () => {
|
|
3859
|
+
dispatch({
|
|
3860
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3861
|
+
filterDrawer: FilterDrawer.Tag,
|
|
3862
|
+
});
|
|
3863
|
+
} },
|
|
3864
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTag, className: "me-2" }),
|
|
3865
|
+
"Tag")),
|
|
3866
|
+
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: () => {
|
|
3867
|
+
dispatch({
|
|
3868
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3869
|
+
filterDrawer: FilterDrawer.Action,
|
|
3870
|
+
});
|
|
3871
|
+
} },
|
|
3872
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faHammer, className: "me-2" }),
|
|
3873
|
+
"Action"),
|
|
3874
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle advanced filter drawer", onClick: () => {
|
|
3875
|
+
dispatch({
|
|
3876
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3877
|
+
filterDrawer: FilterDrawer.Advanced,
|
|
3878
|
+
});
|
|
3879
|
+
} },
|
|
3880
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faList, className: "me-2" }),
|
|
3881
|
+
"Advanced"),
|
|
3882
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-reset-filters-button", className: "btn btn-light", "aria-label": "reset filters", onClick: () => {
|
|
3883
|
+
dispatch({
|
|
3884
|
+
type: ActionType$6.ResetFilters,
|
|
3885
|
+
initActionErrorFilterState,
|
|
3886
|
+
initAdvancedFilterState,
|
|
3887
|
+
initContextFilterState,
|
|
3888
|
+
initDateFilterState,
|
|
3889
|
+
initTagFilterState,
|
|
3890
|
+
});
|
|
3891
|
+
} },
|
|
3892
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes }),
|
|
3893
|
+
' ',
|
|
3894
|
+
"Reset"),
|
|
3895
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-submit-filters-button", className: "btn btn-primary ms-2", "aria-label": "submit filters", onClick: () => {
|
|
3896
|
+
dispatch({
|
|
3897
|
+
type: ActionType$6.HideFilterDrawer,
|
|
3898
|
+
});
|
|
3899
|
+
fetchLogs();
|
|
3900
|
+
} },
|
|
3901
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faSearch }),
|
|
3902
|
+
' ',
|
|
3903
|
+
"Filter"))));
|
|
3904
|
+
// Filter drawer
|
|
3905
|
+
let filterDrawer;
|
|
3906
|
+
if (expandedFilterDrawer) {
|
|
3907
|
+
if (expandedFilterDrawer === FilterDrawer.Date) {
|
|
3908
|
+
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Date" },
|
|
3909
|
+
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: 36, onChange: (month, day, year) => {
|
|
3910
|
+
dateFilterState.startDate = { month, day, year };
|
|
3986
3911
|
dispatch({
|
|
3987
|
-
type: ActionType$6.
|
|
3988
|
-
|
|
3912
|
+
type: ActionType$6.UpdateDateFilterState,
|
|
3913
|
+
dateFilterState,
|
|
3989
3914
|
});
|
|
3990
|
-
} },
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3915
|
+
} }),
|
|
3916
|
+
' ',
|
|
3917
|
+
"to",
|
|
3918
|
+
' ',
|
|
3919
|
+
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) => {
|
|
3920
|
+
if (year < dateFilterState.startDate.year
|
|
3921
|
+
|| (year === dateFilterState.startDate.year
|
|
3922
|
+
&& month < dateFilterState.startDate.month)
|
|
3923
|
+
|| (year === dateFilterState.startDate.year
|
|
3924
|
+
&& month === dateFilterState.startDate.month
|
|
3925
|
+
&& day < dateFilterState.startDate.day)) {
|
|
3926
|
+
return alert('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
3927
|
+
}
|
|
3928
|
+
dateFilterState.endDate = { month, day, year };
|
|
3994
3929
|
dispatch({
|
|
3995
|
-
type: ActionType$6.
|
|
3996
|
-
|
|
3997
|
-
initAdvancedFilterState,
|
|
3998
|
-
initContextFilterState,
|
|
3999
|
-
initDateFilterState,
|
|
4000
|
-
initTagFilterState,
|
|
3930
|
+
type: ActionType$6.UpdateDateFilterState,
|
|
3931
|
+
dateFilterState,
|
|
4001
3932
|
});
|
|
4002
|
-
} }
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
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) => {
|
|
4019
|
-
if (year < dateFilterState.startDate.year
|
|
4020
|
-
|| (year === dateFilterState.startDate.year
|
|
4021
|
-
&& month < dateFilterState.startDate.month)
|
|
4022
|
-
|| (year === dateFilterState.startDate.year
|
|
4023
|
-
&& month === dateFilterState.startDate.month
|
|
4024
|
-
&& day < dateFilterState.startDate.day)) {
|
|
4025
|
-
return alert('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
4026
|
-
}
|
|
4027
|
-
dateFilterState.endDate = { month, day, year };
|
|
4028
|
-
handleDateRangeUpdated(dateFilterState);
|
|
4029
|
-
} })));
|
|
4030
|
-
}
|
|
4031
|
-
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
4032
|
-
// Create item picker items
|
|
4033
|
-
const builtInPickableItem = {
|
|
4034
|
-
id: 'built-in-contexts',
|
|
4035
|
-
name: 'Auto-logged',
|
|
4036
|
-
isGroup: true,
|
|
4037
|
-
children: [],
|
|
4038
|
-
};
|
|
4039
|
-
const pickableItems = [];
|
|
4040
|
-
Object.keys(contextMap)
|
|
4041
|
-
.forEach((context) => {
|
|
4042
|
-
const value = contextMap[context];
|
|
4043
|
-
if (typeof value === 'string') {
|
|
4044
|
-
// No subcategories
|
|
4045
|
-
const item = {
|
|
4046
|
-
id: context,
|
|
4047
|
-
name: genHumanReadableName(context),
|
|
4048
|
-
isGroup: false,
|
|
4049
|
-
checked: !!contextFilterState[context],
|
|
4050
|
-
};
|
|
4051
|
-
// Add built-in items to its own folder
|
|
4052
|
-
const isBuiltIn = context in LogBuiltInMetadata.Context;
|
|
4053
|
-
if (isBuiltIn) {
|
|
4054
|
-
// Add to built-in pickable item
|
|
4055
|
-
builtInPickableItem.children.push(item);
|
|
4056
|
-
}
|
|
4057
|
-
else {
|
|
4058
|
-
// Add to pickable items list
|
|
4059
|
-
pickableItems.push(item);
|
|
4060
|
-
}
|
|
4061
|
-
return;
|
|
4062
|
-
}
|
|
4063
|
-
// Has subcategories
|
|
4064
|
-
const children = (Object.keys(value)
|
|
4065
|
-
// Remove parent name
|
|
4066
|
-
.filter((subcontext) => {
|
|
4067
|
-
return subcontext !== '_';
|
|
4068
|
-
})
|
|
4069
|
-
// Create child pickable items
|
|
4070
|
-
.map((subcontext) => {
|
|
4071
|
-
return {
|
|
4072
|
-
id: subcontext,
|
|
4073
|
-
name: genHumanReadableName(subcontext),
|
|
4074
|
-
isGroup: false,
|
|
4075
|
-
checked: contextFilterState[context][subcontext],
|
|
4076
|
-
};
|
|
4077
|
-
}));
|
|
3933
|
+
} })));
|
|
3934
|
+
}
|
|
3935
|
+
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
3936
|
+
// Create item picker items
|
|
3937
|
+
const builtInPickableItem = {
|
|
3938
|
+
id: 'built-in-contexts',
|
|
3939
|
+
name: 'Auto-logged',
|
|
3940
|
+
isGroup: true,
|
|
3941
|
+
children: [],
|
|
3942
|
+
};
|
|
3943
|
+
const pickableItems = [];
|
|
3944
|
+
Object.keys(contextMap)
|
|
3945
|
+
.forEach((context) => {
|
|
3946
|
+
const value = contextMap[context];
|
|
3947
|
+
if (typeof value === 'string') {
|
|
3948
|
+
// No subcategories
|
|
4078
3949
|
const item = {
|
|
4079
3950
|
id: context,
|
|
4080
3951
|
name: genHumanReadableName(context),
|
|
4081
|
-
isGroup:
|
|
4082
|
-
|
|
3952
|
+
isGroup: false,
|
|
3953
|
+
checked: !!contextFilterState[context],
|
|
4083
3954
|
};
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
3955
|
+
// Add built-in items to its own folder
|
|
3956
|
+
const isBuiltIn = context in LogBuiltInMetadata.Context;
|
|
3957
|
+
if (isBuiltIn) {
|
|
3958
|
+
// Add to built-in pickable item
|
|
3959
|
+
builtInPickableItem.children.push(item);
|
|
3960
|
+
}
|
|
3961
|
+
else {
|
|
3962
|
+
// Add to pickable items list
|
|
3963
|
+
pickableItems.push(item);
|
|
3964
|
+
}
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
// Has subcategories
|
|
3968
|
+
const children = (Object.keys(value)
|
|
3969
|
+
// Remove parent name
|
|
3970
|
+
.filter((subcontext) => {
|
|
3971
|
+
return subcontext !== '_';
|
|
3972
|
+
})
|
|
3973
|
+
// Create child pickable items
|
|
3974
|
+
.map((subcontext) => {
|
|
3975
|
+
return {
|
|
3976
|
+
id: subcontext,
|
|
3977
|
+
name: genHumanReadableName(subcontext),
|
|
3978
|
+
isGroup: false,
|
|
3979
|
+
checked: contextFilterState[context][subcontext],
|
|
3980
|
+
};
|
|
3981
|
+
}));
|
|
3982
|
+
const item = {
|
|
3983
|
+
id: context,
|
|
3984
|
+
name: genHumanReadableName(context),
|
|
3985
|
+
isGroup: true,
|
|
3986
|
+
children,
|
|
3987
|
+
};
|
|
3988
|
+
pickableItems.push(item);
|
|
3989
|
+
});
|
|
3990
|
+
// Add built-in contexts to end ofl ist
|
|
3991
|
+
pickableItems.push(builtInPickableItem);
|
|
3992
|
+
// Create filter UI
|
|
3993
|
+
filterDrawer = (React__default["default"].createElement(ItemPicker, { title: "Context", items: pickableItems, onChanged: (updatedItems) => {
|
|
3994
|
+
// Update our state
|
|
3995
|
+
updatedItems.forEach((pickableItem) => {
|
|
3996
|
+
if (pickableItem.isGroup) {
|
|
3997
|
+
// Has subcontexts
|
|
3998
|
+
if (pickableItem.id === 'built-in-contexts') {
|
|
3999
|
+
// Built-in
|
|
4000
|
+
// Treat as if these were top-level contexts
|
|
4001
|
+
pickableItem.children.forEach((subcontextItem) => {
|
|
4002
|
+
contextFilterState[subcontextItem.id] = ('checked' in subcontextItem
|
|
4003
|
+
&& subcontextItem.checked);
|
|
4004
|
+
});
|
|
4110
4005
|
}
|
|
4111
4006
|
else {
|
|
4112
|
-
//
|
|
4113
|
-
|
|
4007
|
+
// Not built-in
|
|
4008
|
+
pickableItem.children.forEach((subcontextItem) => {
|
|
4009
|
+
if (!subcontextItem.isGroup) {
|
|
4010
|
+
contextFilterState[pickableItem.id][subcontextItem.id] = (subcontextItem.checked);
|
|
4011
|
+
}
|
|
4012
|
+
});
|
|
4114
4013
|
}
|
|
4115
|
-
}
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
contextFilterState
|
|
4119
|
-
}
|
|
4120
|
-
}
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4014
|
+
}
|
|
4015
|
+
else {
|
|
4016
|
+
// No subcontexts
|
|
4017
|
+
contextFilterState[pickableItem.id] = (pickableItem.checked);
|
|
4018
|
+
}
|
|
4019
|
+
});
|
|
4020
|
+
dispatch({
|
|
4021
|
+
type: ActionType$6.UpdateContextFilterState,
|
|
4022
|
+
contextFilterState,
|
|
4023
|
+
});
|
|
4024
|
+
} }));
|
|
4025
|
+
}
|
|
4026
|
+
else if (expandedFilterDrawer === FilterDrawer.Tag) {
|
|
4027
|
+
// Create filter UI
|
|
4028
|
+
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Tags" },
|
|
4029
|
+
React__default["default"].createElement("div", null, "If any tags are selected, logs must contain at least one (but not necessarily all) of the selected tags."),
|
|
4030
|
+
React__default["default"].createElement("div", { className: "d-flex gap-1 flex-wrap" }, Object.keys((_d = LogMetadata.Tag) !== null && _d !== void 0 ? _d : {})
|
|
4031
|
+
.map((tag) => {
|
|
4032
|
+
const description = genHumanReadableName(tag);
|
|
4033
|
+
return (React__default["default"].createElement(CheckboxButton, { key: tag, id: `LogReviewer-tag-${tag}-checkbox`, text: description, ariaLabel: `require that logs be tagged with "${description}" or any other selected tag`, checked: tagFilterState[tag], onChanged: (checked) => {
|
|
4034
|
+
tagFilterState[tag] = checked;
|
|
4035
|
+
dispatch({
|
|
4036
|
+
type: ActionType$6.UpdateTagFilterState,
|
|
4037
|
+
tagFilterState,
|
|
4038
|
+
});
|
|
4039
|
+
} }));
|
|
4040
|
+
}))));
|
|
4041
|
+
}
|
|
4042
|
+
else if (expandedFilterDrawer === FilterDrawer.Action) {
|
|
4043
|
+
// Create filter UI
|
|
4044
|
+
filterDrawer = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4045
|
+
React__default["default"].createElement(TabBox, { title: "Log Type" },
|
|
4046
|
+
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
|
|
4047
|
+
actionErrorFilterState.type = undefined;
|
|
4048
|
+
dispatch({
|
|
4049
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4050
|
+
actionErrorFilterState,
|
|
4051
|
+
});
|
|
4052
|
+
}, ariaLabel: "show logs of all types", selected: actionErrorFilterState.type === undefined }),
|
|
4053
|
+
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
|
|
4054
|
+
actionErrorFilterState.type = LogType$1.Action;
|
|
4055
|
+
dispatch({
|
|
4056
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4057
|
+
actionErrorFilterState,
|
|
4058
|
+
});
|
|
4059
|
+
}, ariaLabel: "only show action logs", selected: actionErrorFilterState.type === LogType$1.Action }),
|
|
4060
|
+
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
|
|
4061
|
+
actionErrorFilterState.type = LogType$1.Error;
|
|
4062
|
+
dispatch({
|
|
4063
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4064
|
+
actionErrorFilterState,
|
|
4065
|
+
});
|
|
4066
|
+
}, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
|
|
4067
|
+
(actionErrorFilterState.type === undefined
|
|
4068
|
+
|| actionErrorFilterState.type === LogType$1.Action) && (React__default["default"].createElement(TabBox, { title: "Action Log Details" },
|
|
4069
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Action", className: "mb-2", wrapButtonsAndAddGaps: true }, Object.keys(LogAction$1)
|
|
4070
|
+
.map((action) => {
|
|
4071
|
+
const description = genHumanReadableName(action);
|
|
4072
|
+
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: true, checked: actionErrorFilterState.action[action], onChanged: (checked) => {
|
|
4073
|
+
actionErrorFilterState.action[action] = checked;
|
|
4131
4074
|
dispatch({
|
|
4132
|
-
type: ActionType$6.
|
|
4133
|
-
|
|
4075
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4076
|
+
actionErrorFilterState,
|
|
4134
4077
|
});
|
|
4135
4078
|
} }));
|
|
4136
|
-
}))
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
|
|
4143
|
-
actionErrorFilterState.type = undefined;
|
|
4079
|
+
})),
|
|
4080
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Target", wrapButtonsAndAddGaps: true }, Object.keys(targetMap)
|
|
4081
|
+
.map((target) => {
|
|
4082
|
+
const description = genHumanReadableName(target);
|
|
4083
|
+
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], noMarginOnRight: true, onChanged: (checked) => {
|
|
4084
|
+
actionErrorFilterState.target[target] = checked;
|
|
4144
4085
|
dispatch({
|
|
4145
4086
|
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4146
4087
|
actionErrorFilterState,
|
|
4147
4088
|
});
|
|
4148
|
-
}
|
|
4149
|
-
|
|
4150
|
-
|
|
4089
|
+
} }));
|
|
4090
|
+
})))),
|
|
4091
|
+
(actionErrorFilterState.type === undefined
|
|
4092
|
+
|| actionErrorFilterState.type === LogType$1.Error) && (React__default["default"].createElement(TabBox, { title: "Error Log Details" },
|
|
4093
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4094
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Error Message"),
|
|
4095
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for error message", value: actionErrorFilterState.errorMessage, placeholder: "e.g. undefined is not a function", onChange: (e) => {
|
|
4096
|
+
actionErrorFilterState.errorMessage = e.target.value;
|
|
4151
4097
|
dispatch({
|
|
4152
4098
|
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4153
4099
|
actionErrorFilterState,
|
|
4154
4100
|
});
|
|
4155
|
-
}
|
|
4156
|
-
|
|
4157
|
-
|
|
4101
|
+
} })),
|
|
4102
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4103
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Error Code"),
|
|
4104
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for error code", value: actionErrorFilterState.errorCode, placeholder: "e.g. GC22", onChange: (e) => {
|
|
4105
|
+
actionErrorFilterState.errorCode = ((e.target.value)
|
|
4106
|
+
.trim()
|
|
4107
|
+
.toUpperCase());
|
|
4158
4108
|
dispatch({
|
|
4159
4109
|
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4160
4110
|
actionErrorFilterState,
|
|
4161
4111
|
});
|
|
4162
|
-
}
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
React__default["default"].createElement("
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
.toUpperCase());
|
|
4204
|
-
dispatch({
|
|
4205
|
-
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4206
|
-
actionErrorFilterState,
|
|
4207
|
-
});
|
|
4208
|
-
} }))))));
|
|
4209
|
-
}
|
|
4210
|
-
else if (expandedFilterDrawer === FilterDrawer.Advanced) {
|
|
4211
|
-
// Create advanced filter ui
|
|
4212
|
-
filterDrawer = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4213
|
-
React__default["default"].createElement(TabBox, { title: "User" },
|
|
4214
|
-
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4215
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "User First Name"),
|
|
4216
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user first name", value: advancedFilterState.userFirstName, placeholder: "e.g. Divardo", onChange: (e) => {
|
|
4217
|
-
advancedFilterState.userFirstName = e.target.value;
|
|
4218
|
-
dispatch({
|
|
4219
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4220
|
-
advancedFilterState,
|
|
4221
|
-
});
|
|
4222
|
-
} })),
|
|
4223
|
-
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4224
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "User Last Name"),
|
|
4225
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user last name", value: advancedFilterState.userLastName, placeholder: "e.g. Calicci", onChange: (e) => {
|
|
4226
|
-
advancedFilterState.userLastName = e.target.value;
|
|
4227
|
-
dispatch({
|
|
4228
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4229
|
-
advancedFilterState,
|
|
4230
|
-
});
|
|
4231
|
-
} })),
|
|
4232
|
-
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4233
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "User Email"),
|
|
4234
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user email", value: advancedFilterState.userEmail, placeholder: "e.g. calicci@fas.harvard.edu", onChange: (e) => {
|
|
4235
|
-
advancedFilterState.userEmail = ((e.target.value)
|
|
4112
|
+
} }))))));
|
|
4113
|
+
}
|
|
4114
|
+
else if (expandedFilterDrawer === FilterDrawer.Advanced) {
|
|
4115
|
+
// Create advanced filter ui
|
|
4116
|
+
filterDrawer = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4117
|
+
React__default["default"].createElement(TabBox, { title: "User" },
|
|
4118
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4119
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User First Name"),
|
|
4120
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user first name", value: advancedFilterState.userFirstName, placeholder: "e.g. Divardo", onChange: (e) => {
|
|
4121
|
+
advancedFilterState.userFirstName = e.target.value;
|
|
4122
|
+
dispatch({
|
|
4123
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4124
|
+
advancedFilterState,
|
|
4125
|
+
});
|
|
4126
|
+
} })),
|
|
4127
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4128
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User Last Name"),
|
|
4129
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user last name", value: advancedFilterState.userLastName, placeholder: "e.g. Calicci", onChange: (e) => {
|
|
4130
|
+
advancedFilterState.userLastName = e.target.value;
|
|
4131
|
+
dispatch({
|
|
4132
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4133
|
+
advancedFilterState,
|
|
4134
|
+
});
|
|
4135
|
+
} })),
|
|
4136
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4137
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User Email"),
|
|
4138
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user email", value: advancedFilterState.userEmail, placeholder: "e.g. calicci@fas.harvard.edu", onChange: (e) => {
|
|
4139
|
+
advancedFilterState.userEmail = ((e.target.value)
|
|
4140
|
+
.trim());
|
|
4141
|
+
dispatch({
|
|
4142
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4143
|
+
advancedFilterState,
|
|
4144
|
+
});
|
|
4145
|
+
} })),
|
|
4146
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4147
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User Canvas Id"),
|
|
4148
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user canvas id", value: advancedFilterState.userId, placeholder: "e.g. 104985", onChange: (e) => {
|
|
4149
|
+
const { value } = e.target;
|
|
4150
|
+
// Only update if value contains only numbers
|
|
4151
|
+
if (/^\d+$/.test(value)) {
|
|
4152
|
+
advancedFilterState.userId = ((e.target.value)
|
|
4236
4153
|
.trim());
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
}
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
}
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
advancedFilterState
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4154
|
+
}
|
|
4155
|
+
dispatch({
|
|
4156
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4157
|
+
advancedFilterState,
|
|
4158
|
+
});
|
|
4159
|
+
} })),
|
|
4160
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Role" },
|
|
4161
|
+
React__default["default"].createElement(CheckboxButton, { text: "Students", onChanged: (checked) => {
|
|
4162
|
+
advancedFilterState.includeLearners = checked;
|
|
4163
|
+
dispatch({
|
|
4164
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4165
|
+
advancedFilterState,
|
|
4166
|
+
});
|
|
4167
|
+
}, checked: advancedFilterState.includeLearners, ariaLabel: "show logs from students" }),
|
|
4168
|
+
React__default["default"].createElement(CheckboxButton, { text: "Teaching Team Members", onChanged: (checked) => {
|
|
4169
|
+
advancedFilterState.includeTTMs = checked;
|
|
4170
|
+
dispatch({
|
|
4171
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4172
|
+
advancedFilterState,
|
|
4173
|
+
});
|
|
4174
|
+
}, checked: advancedFilterState.includeTTMs, ariaLabel: "show logs from teaching team members" }),
|
|
4175
|
+
React__default["default"].createElement(CheckboxButton, { text: "Admins", onChanged: (checked) => {
|
|
4176
|
+
advancedFilterState.includeAdmins = checked;
|
|
4177
|
+
dispatch({
|
|
4178
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4179
|
+
advancedFilterState,
|
|
4180
|
+
});
|
|
4181
|
+
}, checked: advancedFilterState.includeAdmins, ariaLabel: "show logs from admins" }))),
|
|
4182
|
+
React__default["default"].createElement(TabBox, { title: "Course" },
|
|
4183
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4184
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Course Name"),
|
|
4185
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for course name", value: advancedFilterState.courseName, placeholder: "e.g. GLC 200", onChange: (e) => {
|
|
4186
|
+
advancedFilterState.courseName = e.target.value;
|
|
4187
|
+
dispatch({
|
|
4188
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4189
|
+
advancedFilterState,
|
|
4190
|
+
});
|
|
4191
|
+
} })),
|
|
4192
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4193
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Course Canvas Id"),
|
|
4194
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for course canvas id", value: advancedFilterState.courseId, placeholder: "e.g. 15948", onChange: (e) => {
|
|
4195
|
+
const { value } = e.target;
|
|
4196
|
+
// Only update if value contains only numbers
|
|
4197
|
+
if (/^\d+$/.test(value)) {
|
|
4198
|
+
advancedFilterState.courseId = ((e.target.value)
|
|
4199
|
+
.trim());
|
|
4200
|
+
}
|
|
4201
|
+
dispatch({
|
|
4202
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4203
|
+
advancedFilterState,
|
|
4204
|
+
});
|
|
4205
|
+
} }))),
|
|
4206
|
+
React__default["default"].createElement(TabBox, { title: "Device" },
|
|
4207
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Device Type" },
|
|
4208
|
+
React__default["default"].createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
|
|
4209
|
+
advancedFilterState.isMobile = undefined;
|
|
4210
|
+
dispatch({
|
|
4211
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4212
|
+
advancedFilterState,
|
|
4213
|
+
});
|
|
4214
|
+
} }),
|
|
4215
|
+
React__default["default"].createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
|
|
4216
|
+
advancedFilterState.isMobile = true;
|
|
4217
|
+
dispatch({
|
|
4218
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4219
|
+
advancedFilterState,
|
|
4220
|
+
});
|
|
4221
|
+
} }),
|
|
4222
|
+
React__default["default"].createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
|
|
4223
|
+
advancedFilterState.isMobile = false;
|
|
4224
|
+
dispatch({
|
|
4225
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4226
|
+
advancedFilterState,
|
|
4227
|
+
});
|
|
4228
|
+
}, noMarginOnRight: true }))),
|
|
4229
|
+
React__default["default"].createElement(TabBox, { title: "Source" },
|
|
4230
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Source Type" },
|
|
4231
|
+
React__default["default"].createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
|
|
4232
|
+
advancedFilterState.source = undefined;
|
|
4233
|
+
dispatch({
|
|
4234
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4235
|
+
advancedFilterState,
|
|
4236
|
+
});
|
|
4237
|
+
} }),
|
|
4238
|
+
React__default["default"].createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
|
|
4239
|
+
advancedFilterState.source = LogSource$1.Client;
|
|
4240
|
+
dispatch({
|
|
4241
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4242
|
+
advancedFilterState,
|
|
4243
|
+
});
|
|
4244
|
+
} }),
|
|
4245
|
+
React__default["default"].createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
|
|
4246
|
+
advancedFilterState.source = LogSource$1.Server;
|
|
4247
|
+
dispatch({
|
|
4248
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4249
|
+
advancedFilterState,
|
|
4250
|
+
});
|
|
4251
|
+
}, noMarginOnRight: true })),
|
|
4252
|
+
advancedFilterState.source !== LogSource$1.Client && (React__default["default"].createElement("div", { className: "mt-2" },
|
|
4279
4253
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4280
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "
|
|
4281
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for
|
|
4282
|
-
advancedFilterState.courseName = e.target.value
|
|
4254
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Path"),
|
|
4255
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for server route path", value: advancedFilterState.routePath, placeholder: "e.g. /api/ttm/courses/12345", onChange: (e) => {
|
|
4256
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
4257
|
+
.trim());
|
|
4283
4258
|
dispatch({
|
|
4284
4259
|
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4285
4260
|
advancedFilterState,
|
|
4286
4261
|
});
|
|
4287
4262
|
} })),
|
|
4288
4263
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4289
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "
|
|
4290
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
if (/^\d+$/.test(value)) {
|
|
4294
|
-
advancedFilterState.courseId = ((e.target.value)
|
|
4295
|
-
.trim());
|
|
4296
|
-
}
|
|
4297
|
-
dispatch({
|
|
4298
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4299
|
-
advancedFilterState,
|
|
4300
|
-
});
|
|
4301
|
-
} }))),
|
|
4302
|
-
React__default["default"].createElement(TabBox, { title: "Device" },
|
|
4303
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Device Type" },
|
|
4304
|
-
React__default["default"].createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
|
|
4305
|
-
advancedFilterState.isMobile = undefined;
|
|
4306
|
-
dispatch({
|
|
4307
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4308
|
-
advancedFilterState,
|
|
4309
|
-
});
|
|
4310
|
-
} }),
|
|
4311
|
-
React__default["default"].createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
|
|
4312
|
-
advancedFilterState.isMobile = true;
|
|
4313
|
-
dispatch({
|
|
4314
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4315
|
-
advancedFilterState,
|
|
4316
|
-
});
|
|
4317
|
-
} }),
|
|
4318
|
-
React__default["default"].createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
|
|
4319
|
-
advancedFilterState.isMobile = false;
|
|
4320
|
-
dispatch({
|
|
4321
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4322
|
-
advancedFilterState,
|
|
4323
|
-
});
|
|
4324
|
-
}, noMarginOnRight: true }))),
|
|
4325
|
-
React__default["default"].createElement(TabBox, { title: "Source" },
|
|
4326
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Source Type" },
|
|
4327
|
-
React__default["default"].createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
|
|
4328
|
-
advancedFilterState.source = undefined;
|
|
4329
|
-
dispatch({
|
|
4330
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4331
|
-
advancedFilterState,
|
|
4332
|
-
});
|
|
4333
|
-
} }),
|
|
4334
|
-
React__default["default"].createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
|
|
4335
|
-
advancedFilterState.source = LogSource$1.Client;
|
|
4336
|
-
dispatch({
|
|
4337
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4338
|
-
advancedFilterState,
|
|
4339
|
-
});
|
|
4340
|
-
} }),
|
|
4341
|
-
React__default["default"].createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
|
|
4342
|
-
advancedFilterState.source = LogSource$1.Server;
|
|
4264
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
4265
|
+
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) => {
|
|
4266
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
4267
|
+
.trim());
|
|
4343
4268
|
dispatch({
|
|
4344
4269
|
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4345
4270
|
advancedFilterState,
|
|
4346
4271
|
});
|
|
4347
|
-
}
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
4361
|
-
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) => {
|
|
4362
|
-
advancedFilterState.courseName = ((e.target.value)
|
|
4363
|
-
.trim());
|
|
4364
|
-
dispatch({
|
|
4365
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4366
|
-
advancedFilterState,
|
|
4367
|
-
});
|
|
4368
|
-
} })))))));
|
|
4369
|
-
}
|
|
4370
|
-
}
|
|
4371
|
-
// Filters UI
|
|
4372
|
-
const filters = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4373
|
-
filterToggles,
|
|
4374
|
-
filterDrawer && (React__default["default"].createElement(Drawer, { customBackgroundColor: "#eee" }, filterDrawer))));
|
|
4375
|
-
// Actually filter the logs
|
|
4376
|
-
// > Perform filters
|
|
4377
|
-
const logs = [];
|
|
4378
|
-
Object.keys(logMap).forEach((year) => {
|
|
4379
|
-
Object.keys(logMap[year]).forEach((month) => {
|
|
4380
|
-
logMap[year][month].forEach((log) => {
|
|
4381
|
-
/* ----------- Date Filter ---------- */
|
|
4382
|
-
var _a;
|
|
4383
|
-
// Before start date
|
|
4384
|
-
if (
|
|
4385
|
-
// Previous year
|
|
4386
|
-
log.year < dateFilterState.startDate.year
|
|
4387
|
-
// Same year, earlier month
|
|
4388
|
-
|| ((log.year === dateFilterState.startDate.year)
|
|
4389
|
-
&& (log.month < dateFilterState.startDate.month))
|
|
4390
|
-
// Same year, same month, earlier day
|
|
4391
|
-
|| ((log.year === dateFilterState.startDate.year)
|
|
4392
|
-
&& (log.month === dateFilterState.startDate.month)
|
|
4393
|
-
&& (log.day < dateFilterState.startDate.day))) {
|
|
4394
|
-
return;
|
|
4395
|
-
}
|
|
4396
|
-
// After end date
|
|
4397
|
-
if (
|
|
4398
|
-
// Later year
|
|
4399
|
-
log.year > dateFilterState.endDate.year
|
|
4400
|
-
// Same year, later month
|
|
4401
|
-
|| ((log.year === dateFilterState.endDate.year)
|
|
4402
|
-
&& (log.month > dateFilterState.endDate.month))
|
|
4403
|
-
// Same year, same month, later day
|
|
4404
|
-
|| ((log.year === dateFilterState.endDate.year)
|
|
4405
|
-
&& (log.month === dateFilterState.endDate.month)
|
|
4406
|
-
&& (log.day > dateFilterState.endDate.day))) {
|
|
4407
|
-
return;
|
|
4408
|
-
}
|
|
4409
|
-
/* --------- Context Filter --------- */
|
|
4410
|
-
// Context doesn't match
|
|
4411
|
-
if (
|
|
4412
|
-
// Whole context is deselected
|
|
4413
|
-
contextFilterState[log.context] === false
|
|
4414
|
-
// None of the subcontexts are selected
|
|
4415
|
-
|| (
|
|
4416
|
-
// Has subcontexts
|
|
4417
|
-
typeof contextFilterState[log.context] !== 'boolean'
|
|
4418
|
-
// None of the subcontexts are selected
|
|
4419
|
-
&& Object.values((_a = contextFilterState[log.context]) !== null && _a !== void 0 ? _a : {})
|
|
4420
|
-
.every((isSelected) => {
|
|
4421
|
-
return !isSelected;
|
|
4422
|
-
}))) {
|
|
4423
|
-
return;
|
|
4424
|
-
}
|
|
4425
|
-
// Subcontext doesn't match
|
|
4426
|
-
if (
|
|
4427
|
-
// Log context is not "uncategorized" (no point in further filters)
|
|
4428
|
-
log.context !== LogBuiltInMetadata.Context.Uncategorized
|
|
4429
|
-
// Log has a subcontext
|
|
4430
|
-
&& log.subcontext
|
|
4431
|
-
// Context has subcontexts
|
|
4432
|
-
&& (contextFilterState[log.context]
|
|
4433
|
-
&& contextFilterState[log.context] !== false
|
|
4434
|
-
&& contextFilterState[log.context] !== true)
|
|
4435
|
-
// Subcontext is not selected
|
|
4436
|
-
&& !contextFilterState[log.context][log.subcontext]) {
|
|
4437
|
-
return;
|
|
4438
|
-
}
|
|
4439
|
-
/* -------------- Tags -------------- */
|
|
4440
|
-
// No tags match
|
|
4441
|
-
if (
|
|
4442
|
-
// At least one tag is required
|
|
4443
|
-
Object.values(tagFilterState)
|
|
4444
|
-
.filter((isSelected) => {
|
|
4445
|
-
return isSelected;
|
|
4446
|
-
})
|
|
4447
|
-
.length > 0
|
|
4448
|
-
// No tags match
|
|
4449
|
-
&& log.tags.every((tag) => {
|
|
4450
|
-
return !tagFilterState[tag];
|
|
4451
|
-
})) {
|
|
4452
|
-
return;
|
|
4453
|
-
}
|
|
4454
|
-
/* ------- Actions and Errors ------- */
|
|
4455
|
-
// Log type doesn't match
|
|
4456
|
-
if (
|
|
4457
|
-
// Filter won't allow all types
|
|
4458
|
-
actionErrorFilterState.type !== undefined
|
|
4459
|
-
// Log type doesn't match
|
|
4460
|
-
&& actionErrorFilterState.type !== log.type) {
|
|
4461
|
-
return;
|
|
4462
|
-
}
|
|
4463
|
-
// Filter errors
|
|
4464
|
-
if (log.type === LogType$1.Error) {
|
|
4465
|
-
// Message doesn't match
|
|
4466
|
-
if (
|
|
4467
|
-
// Message exists
|
|
4468
|
-
log.errorMessage
|
|
4469
|
-
// Message filter exists
|
|
4470
|
-
&& actionErrorFilterState.errorMessage.trim().length > 0
|
|
4471
|
-
// Message doesn't match
|
|
4472
|
-
&& log.errorMessage.toLowerCase().includes(actionErrorFilterState.errorMessage.trim().toLowerCase())) {
|
|
4473
|
-
return;
|
|
4474
|
-
}
|
|
4475
|
-
// Code doesn't match
|
|
4476
|
-
if (
|
|
4477
|
-
// Code exists
|
|
4478
|
-
log.errorCode
|
|
4479
|
-
// Code filter exists
|
|
4480
|
-
&& actionErrorFilterState.errorCode.trim().length > 0
|
|
4481
|
-
// Code doesn't match
|
|
4482
|
-
&& log.errorCode.toUpperCase().includes(actionErrorFilterState.errorCode.trim().toUpperCase())) {
|
|
4483
|
-
return;
|
|
4484
|
-
}
|
|
4485
|
-
}
|
|
4486
|
-
// Filter actions
|
|
4487
|
-
if (log.type === LogType$1.Action) {
|
|
4488
|
-
// Target isn't selected
|
|
4489
|
-
if (
|
|
4490
|
-
// Target exists
|
|
4491
|
-
log.target
|
|
4492
|
-
// Target isn't selected
|
|
4493
|
-
&& !actionErrorFilterState.target[log.target]) {
|
|
4494
|
-
return;
|
|
4495
|
-
}
|
|
4496
|
-
// Action
|
|
4497
|
-
if (
|
|
4498
|
-
// Action exists
|
|
4499
|
-
log.action
|
|
4500
|
-
// Action isn't selected
|
|
4501
|
-
&& !actionErrorFilterState.action[log.action]) {
|
|
4502
|
-
return;
|
|
4503
|
-
}
|
|
4504
|
-
}
|
|
4505
|
-
/* --------- Advanced Filter -------- */
|
|
4506
|
-
// First name doesn't match
|
|
4507
|
-
if (
|
|
4508
|
-
// First name exists
|
|
4509
|
-
log.userFirstName
|
|
4510
|
-
// First name query doesn't match
|
|
4511
|
-
&& !log.userFirstName.toLowerCase().includes(advancedFilterState.userFirstName.toLowerCase().trim())) {
|
|
4512
|
-
return;
|
|
4513
|
-
}
|
|
4514
|
-
// Last name doesn't match
|
|
4515
|
-
if (
|
|
4516
|
-
// Last name exists
|
|
4517
|
-
log.userLastName
|
|
4518
|
-
// Last name query doesn't match
|
|
4519
|
-
&& !log.userLastName.toLowerCase().includes(advancedFilterState.userLastName.toLowerCase().trim())) {
|
|
4520
|
-
return;
|
|
4521
|
-
}
|
|
4522
|
-
// Email doesn't match
|
|
4523
|
-
if (
|
|
4524
|
-
// Email exists
|
|
4525
|
-
log.userEmail
|
|
4526
|
-
// Email query doesn't match
|
|
4527
|
-
&& !log.userEmail.toLowerCase().includes(advancedFilterState.userEmail.toLowerCase().trim())) {
|
|
4528
|
-
return;
|
|
4529
|
-
}
|
|
4530
|
-
// User id doesn't match
|
|
4531
|
-
if (
|
|
4532
|
-
// User id exists
|
|
4533
|
-
log.userId
|
|
4534
|
-
// User id doesn't match
|
|
4535
|
-
&& !String(log.userId).includes(advancedFilterState.userId.trim())) {
|
|
4536
|
-
return;
|
|
4537
|
-
}
|
|
4538
|
-
// Learner not allowed
|
|
4539
|
-
if (
|
|
4540
|
-
// User is a learner
|
|
4541
|
-
log.isLearner
|
|
4542
|
-
// Learners aren't included
|
|
4543
|
-
&& !advancedFilterState.includeLearners) {
|
|
4544
|
-
return;
|
|
4545
|
-
}
|
|
4546
|
-
// TTM not allowed
|
|
4547
|
-
if (
|
|
4548
|
-
// User is a ttm
|
|
4549
|
-
log.isTTM
|
|
4550
|
-
// TTMs aren't included
|
|
4551
|
-
&& !advancedFilterState.includeTTMs) {
|
|
4552
|
-
return;
|
|
4553
|
-
}
|
|
4554
|
-
// Admin not allowed
|
|
4555
|
-
if (
|
|
4556
|
-
// User is an admin
|
|
4557
|
-
log.isAdmin
|
|
4558
|
-
// Admins aren't included
|
|
4559
|
-
&& !advancedFilterState.includeAdmins) {
|
|
4560
|
-
return;
|
|
4561
|
-
}
|
|
4562
|
-
// Course Id doesn't match
|
|
4563
|
-
if (
|
|
4564
|
-
// Course Id exists
|
|
4565
|
-
log.courseId
|
|
4566
|
-
// Course Id doesn't match
|
|
4567
|
-
&& !String(log.courseId).includes(advancedFilterState.courseId.trim())) {
|
|
4568
|
-
return;
|
|
4569
|
-
}
|
|
4570
|
-
// Course name doesn't match
|
|
4571
|
-
if (
|
|
4572
|
-
// Course name exists
|
|
4573
|
-
log.courseName
|
|
4574
|
-
// Course name doesn't match
|
|
4575
|
-
&& !String(log.courseName).includes(advancedFilterState.courseName.trim())) {
|
|
4576
|
-
return;
|
|
4577
|
-
}
|
|
4578
|
-
// Mobile filter doesn't match
|
|
4579
|
-
if (
|
|
4580
|
-
// Mobile filter exists
|
|
4581
|
-
advancedFilterState.isMobile !== undefined
|
|
4582
|
-
// Device info exists
|
|
4583
|
-
&& log.device
|
|
4584
|
-
// Mobile filter doesn't match
|
|
4585
|
-
&& (advancedFilterState.isMobile !== log.device.isMobile)) {
|
|
4586
|
-
return;
|
|
4587
|
-
}
|
|
4588
|
-
// Log source doesn't match
|
|
4589
|
-
if (
|
|
4590
|
-
// Source filter exists
|
|
4591
|
-
advancedFilterState.source !== undefined
|
|
4592
|
-
// Source info exists
|
|
4593
|
-
&& log.source
|
|
4594
|
-
// Source filter doesn't match
|
|
4595
|
-
&& (advancedFilterState.source !== log.source)) {
|
|
4596
|
-
return;
|
|
4597
|
-
}
|
|
4598
|
-
// Route path doesn't match (Only for server source)
|
|
4599
|
-
if (
|
|
4600
|
-
// Source is server
|
|
4601
|
-
(log.source === LogSource$1.Server)
|
|
4602
|
-
// Route path is being filtered
|
|
4603
|
-
&& (advancedFilterState.routePath.trim().length)
|
|
4604
|
-
// Route path doesn't match
|
|
4605
|
-
&& !(log.routePath.includes(advancedFilterState.routePath.trim()))) {
|
|
4606
|
-
return;
|
|
4607
|
-
}
|
|
4608
|
-
// Route template doesn't match (Only for server source)
|
|
4609
|
-
if (
|
|
4610
|
-
// Source is server
|
|
4611
|
-
(log.source === LogSource$1.Server)
|
|
4612
|
-
// Route template is being filtered
|
|
4613
|
-
&& (advancedFilterState.routeTemplate.trim().length)
|
|
4614
|
-
// Route template doesn't match
|
|
4615
|
-
&& !(log.routeTemplate.includes(advancedFilterState.routeTemplate.trim()))) {
|
|
4616
|
-
return;
|
|
4617
|
-
}
|
|
4618
|
-
/* -------------- Done -------------- */
|
|
4619
|
-
// Made it past all filters. Add to the list
|
|
4620
|
-
logs.push(log);
|
|
4621
|
-
});
|
|
4622
|
-
});
|
|
4623
|
-
});
|
|
4624
|
-
/*----------------------------------------*/
|
|
4625
|
-
/* ---------------- Data ---------------- */
|
|
4626
|
-
/*----------------------------------------*/
|
|
4627
|
-
// Nothing to show notice
|
|
4628
|
-
const noLogsNotice = (logs.length === 0
|
|
4629
|
-
? (React__default["default"].createElement("div", { className: "alert alert-warning text-center mt-2" },
|
|
4272
|
+
} })))))));
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
// Filters UI
|
|
4276
|
+
const filters = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4277
|
+
filterToggles,
|
|
4278
|
+
filterDrawer && (React__default["default"].createElement(Drawer, { customBackgroundColor: "#eee" }, filterDrawer))));
|
|
4279
|
+
// Main body
|
|
4280
|
+
body = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4281
|
+
filters,
|
|
4282
|
+
React__default["default"].createElement("div", { className: "mt-2" },
|
|
4283
|
+
React__default["default"].createElement(IntelliTable, { title: "Matching Logs:", csvName: `Logs from ${getHumanReadableDate()}`, id: "logs", data: logs, columns: columns }),
|
|
4284
|
+
logs.length === 0 && (React__default["default"].createElement("div", { className: "alert alert-warning text-center mt-2" },
|
|
4630
4285
|
React__default["default"].createElement("h4", { className: "m-1" }, "No Logs to Show"),
|
|
4631
|
-
React__default["default"].createElement("div", null, "Either your filters are too strict or no matching logs have been created yet.")))
|
|
4632
|
-
|
|
4633
|
-
// Create intelliTable
|
|
4634
|
-
const dataTable = (React__default["default"].createElement(IntelliTable, { title: "Matching Logs:", csvName: `Logs from ${getHumanReadableDate()}`, id: "logs", data: logs, columns: columns }));
|
|
4635
|
-
// Main body
|
|
4636
|
-
body = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4637
|
-
filters,
|
|
4638
|
-
React__default["default"].createElement("div", { className: "mt-2" },
|
|
4639
|
-
dataTable,
|
|
4640
|
-
noLogsNotice)));
|
|
4641
|
-
}
|
|
4286
|
+
React__default["default"].createElement("div", null, "Either your filters are too strict or no matching logs have been created yet."))),
|
|
4287
|
+
paginationControls)));
|
|
4642
4288
|
/* ---------- Wrap in Modal --------- */
|
|
4643
4289
|
return (React__default["default"].createElement("div", { className: "LogReviewer-outer-container" },
|
|
4644
4290
|
React__default["default"].createElement("style", null, style$2),
|
|
@@ -14150,32 +13796,188 @@ const initServer = (opts) => {
|
|
|
14150
13796
|
}),
|
|
14151
13797
|
}));
|
|
14152
13798
|
/**
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
opts.app.get(`${
|
|
13799
|
+
* Get filtered logs based on provided filters
|
|
13800
|
+
* @author Gabe Abrams, Yuen Ler Chow
|
|
13801
|
+
* @param pageNumber the page number to get
|
|
13802
|
+
* @param filters the filters to apply to the logs
|
|
13803
|
+
* @returns {Log[]} list of logs that match the filters
|
|
13804
|
+
*/
|
|
13805
|
+
opts.app.get(`${LOG_REVIEW_GET_LOGS_ROUTE}`, genRouteHandler({
|
|
14160
13806
|
paramTypes: {
|
|
14161
|
-
|
|
14162
|
-
|
|
13807
|
+
pageNumber: ParamType$1.Int,
|
|
13808
|
+
filters: ParamType$1.JSON,
|
|
14163
13809
|
},
|
|
14164
13810
|
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14165
13811
|
// Get user info
|
|
14166
|
-
const {
|
|
13812
|
+
const { pageNumber, userId, isAdmin, filters, } = params;
|
|
13813
|
+
const { dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, } = filters;
|
|
14167
13814
|
// Validate user
|
|
14168
13815
|
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
14169
13816
|
if (!canReview) {
|
|
14170
13817
|
throw new ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ReactKitErrorCode$1.NotAllowedToReviewLogs);
|
|
14171
13818
|
}
|
|
13819
|
+
// Build MongoDB query based on filters
|
|
13820
|
+
const query = {};
|
|
13821
|
+
/* -------------- Date Filter ------------- */
|
|
13822
|
+
// Convert start and end dates from the dateFilterState into timestamps
|
|
13823
|
+
const { startDate, endDate } = dateFilterState;
|
|
13824
|
+
const startTimestamp = new Date(startDate.year, startDate.month - 1, startDate.day).getTime();
|
|
13825
|
+
const endTimestamp = new Date(endDate.year, endDate.month - 1, endDate.day + 1).getTime() - 1;
|
|
13826
|
+
// Add a date range condition to the query
|
|
13827
|
+
query.timestamp = {
|
|
13828
|
+
$gte: startTimestamp,
|
|
13829
|
+
$lte: endTimestamp,
|
|
13830
|
+
};
|
|
13831
|
+
/* ------------ Context Filter ------------ */
|
|
13832
|
+
// Process context filters to include selected contexts and subcontexts
|
|
13833
|
+
const selectedContexts = [];
|
|
13834
|
+
const selectedSubcontexts = [];
|
|
13835
|
+
// Process each context filter
|
|
13836
|
+
Object.keys(contextFilterState).forEach((context) => {
|
|
13837
|
+
const value = contextFilterState[context];
|
|
13838
|
+
if (typeof value === 'boolean') {
|
|
13839
|
+
if (value) {
|
|
13840
|
+
selectedContexts.push(context);
|
|
13841
|
+
}
|
|
13842
|
+
}
|
|
13843
|
+
else {
|
|
13844
|
+
// At least one subcontext is selected
|
|
13845
|
+
const atLeastOneSubcontextSelected = (Object.values(value)
|
|
13846
|
+
.some((subcontextValue) => {
|
|
13847
|
+
return subcontextValue;
|
|
13848
|
+
}));
|
|
13849
|
+
if (atLeastOneSubcontextSelected) {
|
|
13850
|
+
selectedContexts.push(context);
|
|
13851
|
+
}
|
|
13852
|
+
// Add all selected subcontexts
|
|
13853
|
+
Object.keys(value).forEach((subcontext) => {
|
|
13854
|
+
if (value[subcontext]) {
|
|
13855
|
+
selectedSubcontexts.push(subcontext);
|
|
13856
|
+
}
|
|
13857
|
+
});
|
|
13858
|
+
}
|
|
13859
|
+
});
|
|
13860
|
+
// Add context and subcontext conditions to the query if any are selected
|
|
13861
|
+
if (selectedContexts.length > 0) {
|
|
13862
|
+
query.context = { $in: selectedContexts };
|
|
13863
|
+
}
|
|
13864
|
+
if (selectedSubcontexts.length > 0) {
|
|
13865
|
+
query.subcontext = { $in: selectedSubcontexts };
|
|
13866
|
+
}
|
|
13867
|
+
/* -------------- Tag Filter -------------- */
|
|
13868
|
+
const selectedTags = Object.keys(tagFilterState).filter((tag) => { return tagFilterState[tag]; });
|
|
13869
|
+
if (selectedTags.length > 0) {
|
|
13870
|
+
query.tags = { $in: selectedTags };
|
|
13871
|
+
}
|
|
13872
|
+
/* --------- Action/Error Filter ---------- */
|
|
13873
|
+
if (actionErrorFilterState.type) {
|
|
13874
|
+
query.type = actionErrorFilterState.type;
|
|
13875
|
+
}
|
|
13876
|
+
if (actionErrorFilterState.type === LogType$1.Error) {
|
|
13877
|
+
if (actionErrorFilterState.errorMessage) {
|
|
13878
|
+
// Add error message to the query.
|
|
13879
|
+
// $i is used for case-insensitive search, and $regex is used for partial matching
|
|
13880
|
+
query.errorMessage = {
|
|
13881
|
+
$regex: actionErrorFilterState.errorMessage,
|
|
13882
|
+
$options: 'i',
|
|
13883
|
+
};
|
|
13884
|
+
}
|
|
13885
|
+
if (actionErrorFilterState.errorCode) {
|
|
13886
|
+
query.errorCode = {
|
|
13887
|
+
$regex: actionErrorFilterState.errorCode,
|
|
13888
|
+
$options: 'i',
|
|
13889
|
+
};
|
|
13890
|
+
}
|
|
13891
|
+
}
|
|
13892
|
+
if (actionErrorFilterState.type === LogType$1.Action) {
|
|
13893
|
+
const selectedTargets = (Object.keys(actionErrorFilterState.target)
|
|
13894
|
+
.filter((target) => {
|
|
13895
|
+
return actionErrorFilterState.target[target];
|
|
13896
|
+
}));
|
|
13897
|
+
const selectedActions = (Object.keys(actionErrorFilterState.action)
|
|
13898
|
+
.filter((action) => {
|
|
13899
|
+
return actionErrorFilterState.action[action];
|
|
13900
|
+
}));
|
|
13901
|
+
if (selectedTargets.length > 0) {
|
|
13902
|
+
query.target = { $in: selectedTargets };
|
|
13903
|
+
}
|
|
13904
|
+
if (selectedActions.length > 0) {
|
|
13905
|
+
query.action = { $in: selectedActions };
|
|
13906
|
+
}
|
|
13907
|
+
}
|
|
13908
|
+
/* ------------ Advanced Filter ----------- */
|
|
13909
|
+
if (advancedFilterState.userFirstName) {
|
|
13910
|
+
query.userFirstName = {
|
|
13911
|
+
$regex: advancedFilterState.userFirstName,
|
|
13912
|
+
$options: 'i',
|
|
13913
|
+
};
|
|
13914
|
+
}
|
|
13915
|
+
if (advancedFilterState.userLastName) {
|
|
13916
|
+
query.userLastName = {
|
|
13917
|
+
$regex: advancedFilterState.userLastName,
|
|
13918
|
+
$options: 'i',
|
|
13919
|
+
};
|
|
13920
|
+
}
|
|
13921
|
+
if (advancedFilterState.userEmail) {
|
|
13922
|
+
query.userEmail = {
|
|
13923
|
+
$regex: advancedFilterState.userEmail,
|
|
13924
|
+
$options: 'i',
|
|
13925
|
+
};
|
|
13926
|
+
}
|
|
13927
|
+
if (advancedFilterState.userId) {
|
|
13928
|
+
query.userId = Number.parseInt(advancedFilterState.userId, 10);
|
|
13929
|
+
}
|
|
13930
|
+
const roles = [];
|
|
13931
|
+
if (advancedFilterState.includeLearners) {
|
|
13932
|
+
roles.push({ isLearner: true });
|
|
13933
|
+
}
|
|
13934
|
+
if (advancedFilterState.includeTTMs) {
|
|
13935
|
+
roles.push({ isTTM: true });
|
|
13936
|
+
}
|
|
13937
|
+
if (advancedFilterState.includeAdmins) {
|
|
13938
|
+
roles.push({ isAdmin: true });
|
|
13939
|
+
}
|
|
13940
|
+
// If any roles are selected, add them to the query
|
|
13941
|
+
if (roles.length > 0) {
|
|
13942
|
+
// The $or operator is used to match any of the roles
|
|
13943
|
+
// The $and operator is to ensure that other conditions in the query are met
|
|
13944
|
+
query.$and = [{ $or: roles }];
|
|
13945
|
+
}
|
|
13946
|
+
if (advancedFilterState.courseId) {
|
|
13947
|
+
query.courseId = Number.parseInt(advancedFilterState.courseId, 10);
|
|
13948
|
+
}
|
|
13949
|
+
if (advancedFilterState.courseName) {
|
|
13950
|
+
query.courseName = {
|
|
13951
|
+
$regex: advancedFilterState.courseName,
|
|
13952
|
+
$options: 'i',
|
|
13953
|
+
};
|
|
13954
|
+
}
|
|
13955
|
+
if (advancedFilterState.isMobile !== undefined) {
|
|
13956
|
+
query['device.isMobile'] = Boolean(advancedFilterState.isMobile);
|
|
13957
|
+
}
|
|
13958
|
+
if (advancedFilterState.source) {
|
|
13959
|
+
query.source = advancedFilterState.source;
|
|
13960
|
+
}
|
|
13961
|
+
if (advancedFilterState.routePath) {
|
|
13962
|
+
query.routePath = {
|
|
13963
|
+
$regex: advancedFilterState.routePath,
|
|
13964
|
+
$options: 'i',
|
|
13965
|
+
};
|
|
13966
|
+
}
|
|
13967
|
+
if (advancedFilterState.routeTemplate) {
|
|
13968
|
+
query.routeTemplate = {
|
|
13969
|
+
$regex: advancedFilterState.routeTemplate,
|
|
13970
|
+
$options: 'i',
|
|
13971
|
+
};
|
|
13972
|
+
}
|
|
14172
13973
|
// Query for logs
|
|
14173
|
-
const
|
|
14174
|
-
|
|
14175
|
-
|
|
13974
|
+
const response = yield _logCollection.findPaged({
|
|
13975
|
+
query,
|
|
13976
|
+
perPage: 50,
|
|
13977
|
+
pageNumber,
|
|
14176
13978
|
});
|
|
14177
|
-
// Return
|
|
14178
|
-
return
|
|
13979
|
+
// Return response
|
|
13980
|
+
return response;
|
|
14179
13981
|
}),
|
|
14180
13982
|
}));
|
|
14181
13983
|
};
|
|
@@ -16427,7 +16229,6 @@ exports.padDecimalZeros = padDecimalZeros;
|
|
|
16427
16229
|
exports.padZerosLeft = padZerosLeft;
|
|
16428
16230
|
exports.parallelLimit = parallelLimit;
|
|
16429
16231
|
exports.prefixWithAOrAn = prefixWithAOrAn;
|
|
16430
|
-
exports.prompt = prompt;
|
|
16431
16232
|
exports.roundToNumDecimals = roundToNumDecimals;
|
|
16432
16233
|
exports.setClientEventMetadataPopulator = setClientEventMetadataPopulator;
|
|
16433
16234
|
exports.showFatalError = showFatalError;
|