dce-reactkit 3.9.4-beta-logreviewer.1 → 3.9.4-beta-logreviewer.2
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 +602 -768
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +603 -769
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/LogReviewer.tsx +809 -1156
- package/src/server/initServer.ts +144 -17
package/dist/cjs/index.js
CHANGED
|
@@ -3537,7 +3537,7 @@ var ActionType$6;
|
|
|
3537
3537
|
(function (ActionType) {
|
|
3538
3538
|
// Show the loading bar
|
|
3539
3539
|
ActionType["StartLoading"] = "start-loading";
|
|
3540
|
-
// Finish loading
|
|
3540
|
+
// Finish loading logs
|
|
3541
3541
|
ActionType["FinishLoading"] = "finish-loading";
|
|
3542
3542
|
// Reset filters to initial values
|
|
3543
3543
|
ActionType["ResetFilters"] = "reset-filters";
|
|
@@ -3555,6 +3555,12 @@ var ActionType$6;
|
|
|
3555
3555
|
ActionType["UpdateActionErrorFilterState"] = "update-action-error-filter-state";
|
|
3556
3556
|
// Update the advanced filter state
|
|
3557
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";
|
|
3558
3564
|
})(ActionType$6 || (ActionType$6 = {}));
|
|
3559
3565
|
/**
|
|
3560
3566
|
* Reducer that executes actions
|
|
@@ -3568,7 +3574,7 @@ const reducer$7 = (state, action) => {
|
|
|
3568
3574
|
return Object.assign(Object.assign({}, state), { loading: true });
|
|
3569
3575
|
}
|
|
3570
3576
|
case ActionType$6.FinishLoading: {
|
|
3571
|
-
return Object.assign(Object.assign({}, state), { loading: false,
|
|
3577
|
+
return Object.assign(Object.assign({}, state), { loading: false, logs: action.logs });
|
|
3572
3578
|
}
|
|
3573
3579
|
case ActionType$6.ToggleFilterDrawer: {
|
|
3574
3580
|
return Object.assign(Object.assign({}, state), { expandedFilterDrawer: (state.expandedFilterDrawer === action.filterDrawer
|
|
@@ -3596,6 +3602,12 @@ const reducer$7 = (state, action) => {
|
|
|
3596
3602
|
case ActionType$6.UpdateAdvancedFilterState: {
|
|
3597
3603
|
return Object.assign(Object.assign({}, state), { advancedFilterState: action.advancedFilterState });
|
|
3598
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
|
+
}
|
|
3599
3611
|
default: {
|
|
3600
3612
|
return state;
|
|
3601
3613
|
}
|
|
@@ -3713,126 +3725,78 @@ const LogReviewer = (props) => {
|
|
|
3713
3725
|
// Initial state
|
|
3714
3726
|
const initialState = {
|
|
3715
3727
|
loading: true,
|
|
3716
|
-
|
|
3728
|
+
logs: [],
|
|
3717
3729
|
expandedFilterDrawer: undefined,
|
|
3718
3730
|
dateFilterState: initDateFilterState,
|
|
3719
3731
|
contextFilterState: initContextFilterState,
|
|
3720
3732
|
tagFilterState: initTagFilterState,
|
|
3721
3733
|
actionErrorFilterState: initActionErrorFilterState,
|
|
3722
3734
|
advancedFilterState: initAdvancedFilterState,
|
|
3735
|
+
pageNumber: 1,
|
|
3736
|
+
hasAnotherPage: false,
|
|
3723
3737
|
};
|
|
3724
3738
|
// Initialize state
|
|
3725
3739
|
const [state, dispatch] = React.useReducer(reducer$7, initialState);
|
|
3726
3740
|
// Destructure common state
|
|
3727
|
-
const { loading,
|
|
3741
|
+
const { loading, logs, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, pageNumber, hasAnotherPage, } = state;
|
|
3728
3742
|
/*------------------------------------------------------------------------*/
|
|
3729
3743
|
/* ------------------------- Component Functions ------------------------ */
|
|
3730
3744
|
/*------------------------------------------------------------------------*/
|
|
3731
3745
|
/**
|
|
3732
|
-
*
|
|
3733
|
-
* start or end date and the existing logMap
|
|
3734
|
-
* @author Gabe Abrams
|
|
3735
|
-
* @param newDateFilterState the new date filter state
|
|
3736
|
-
* @returns list of year/month combos that need to be loaded
|
|
3737
|
-
*/
|
|
3738
|
-
const listMonthsToLoad = (newDateFilterState) => {
|
|
3739
|
-
// List of year/month combos that need to be loaded
|
|
3740
|
-
const toLoad = [];
|
|
3741
|
-
// Loop through dates
|
|
3742
|
-
let { year, month } = newDateFilterState.startDate;
|
|
3743
|
-
while (
|
|
3744
|
-
// Earlier year
|
|
3745
|
-
(year < newDateFilterState.endDate.year)
|
|
3746
|
-
// Current year but included month
|
|
3747
|
-
|| (year === newDateFilterState.endDate.year
|
|
3748
|
-
&& month <= newDateFilterState.endDate.month)) {
|
|
3749
|
-
// Add to list if not already loaded
|
|
3750
|
-
if (!logMap[year]
|
|
3751
|
-
|| !logMap[year][month]) {
|
|
3752
|
-
toLoad.push({
|
|
3753
|
-
year,
|
|
3754
|
-
month,
|
|
3755
|
-
});
|
|
3756
|
-
}
|
|
3757
|
-
// Increment
|
|
3758
|
-
month += 1;
|
|
3759
|
-
if (month > 12) {
|
|
3760
|
-
month -= 12;
|
|
3761
|
-
year += 1;
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
|
-
// Return
|
|
3765
|
-
return toLoad;
|
|
3766
|
-
};
|
|
3767
|
-
/**
|
|
3768
|
-
* Handle updated start/end dates (updates state, loads if necessary)
|
|
3769
|
-
* @author Gabe Abrams
|
|
3770
|
-
* @param newDateFilterState the new date filter state
|
|
3746
|
+
* Fetch logs from the server based on current filters
|
|
3771
3747
|
*/
|
|
3772
|
-
const
|
|
3773
|
-
|
|
3774
|
-
dispatch({
|
|
3775
|
-
type: ActionType$6.UpdateDateFilterState,
|
|
3776
|
-
dateFilterState: newDateFilterState,
|
|
3777
|
-
});
|
|
3778
|
-
// Check which year/month combos we need to load
|
|
3779
|
-
const toLoad = listMonthsToLoad(newDateFilterState);
|
|
3780
|
-
// If nothing to load, finished
|
|
3781
|
-
if (toLoad.length === 0) {
|
|
3782
|
-
return;
|
|
3783
|
-
}
|
|
3784
|
-
// Start loading
|
|
3785
|
-
dispatch({
|
|
3786
|
-
type: ActionType$6.StartLoading,
|
|
3787
|
-
});
|
|
3788
|
-
// Load required months
|
|
3748
|
+
const fetchLogs = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
3749
|
+
dispatch({ type: ActionType$6.StartLoading });
|
|
3789
3750
|
try {
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3751
|
+
// Prepare filter parameters
|
|
3752
|
+
const filters = {
|
|
3753
|
+
startDate: dateFilterState.startDate,
|
|
3754
|
+
endDate: dateFilterState.endDate,
|
|
3755
|
+
contextFilterState,
|
|
3756
|
+
tagFilterState,
|
|
3757
|
+
actionErrorFilterState,
|
|
3758
|
+
advancedFilterState,
|
|
3759
|
+
};
|
|
3760
|
+
// Send filters to the server
|
|
3761
|
+
let fetchedLogs = [];
|
|
3762
|
+
const response = yield visitServerEndpoint({
|
|
3763
|
+
path: `${LOG_REVIEW_ROUTE_PATH_PREFIX}/logs`,
|
|
3764
|
+
method: 'GET',
|
|
3765
|
+
params: {
|
|
3766
|
+
pageNumber,
|
|
3767
|
+
filters,
|
|
3768
|
+
},
|
|
3769
|
+
});
|
|
3770
|
+
fetchedLogs = fetchedLogs.concat(response.items);
|
|
3771
|
+
dispatch({
|
|
3772
|
+
type: ActionType$6.SetHasAnotherPage,
|
|
3773
|
+
hasAnotherPage: response.hasAnotherPage,
|
|
3774
|
+
});
|
|
3775
|
+
// Update logs in state
|
|
3776
|
+
dispatch({
|
|
3777
|
+
type: ActionType$6.FinishLoading,
|
|
3778
|
+
logs: fetchedLogs,
|
|
3779
|
+
});
|
|
3815
3780
|
}
|
|
3816
3781
|
catch (err) {
|
|
3817
3782
|
return showFatalError(err);
|
|
3818
3783
|
}
|
|
3819
|
-
// Finish loading
|
|
3820
|
-
dispatch({
|
|
3821
|
-
type: ActionType$6.FinishLoading,
|
|
3822
|
-
logMap,
|
|
3823
|
-
});
|
|
3824
3784
|
});
|
|
3825
3785
|
/*------------------------------------------------------------------------*/
|
|
3826
3786
|
/* ------------------------- Lifecycle Functions ------------------------ */
|
|
3827
3787
|
/*------------------------------------------------------------------------*/
|
|
3828
3788
|
/**
|
|
3829
|
-
*
|
|
3830
|
-
* @author Gabe Abrams
|
|
3789
|
+
* Fetch logs whenever filters change
|
|
3831
3790
|
*/
|
|
3832
3791
|
React.useEffect(() => {
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3792
|
+
fetchLogs();
|
|
3793
|
+
}, [
|
|
3794
|
+
dateFilterState,
|
|
3795
|
+
contextFilterState,
|
|
3796
|
+
tagFilterState,
|
|
3797
|
+
actionErrorFilterState,
|
|
3798
|
+
advancedFilterState,
|
|
3799
|
+
]);
|
|
3836
3800
|
/*------------------------------------------------------------------------*/
|
|
3837
3801
|
/* ------------------------------- Render ------------------------------- */
|
|
3838
3802
|
/*------------------------------------------------------------------------*/
|
|
@@ -3847,703 +3811,472 @@ const LogReviewer = (props) => {
|
|
|
3847
3811
|
React__default["default"].createElement(LoadingSpinner, null)));
|
|
3848
3812
|
}
|
|
3849
3813
|
/* ------------ Review UI ----------- */
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3814
|
+
/*----------------------------------------*/
|
|
3815
|
+
/* ------------ Pagination -------------- */
|
|
3816
|
+
/*----------------------------------------*/
|
|
3817
|
+
const paginationControls = logs.length > 0 && (React__default["default"].createElement("div", { className: "text-center mt-3" },
|
|
3818
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary me-2", disabled: pageNumber <= 1, onClick: () => {
|
|
3819
|
+
dispatch({
|
|
3820
|
+
type: ActionType$6.DecrementPageNumber,
|
|
3821
|
+
});
|
|
3822
|
+
} },
|
|
3823
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faArrowLeft, className: "me-2" }),
|
|
3824
|
+
"Previous Page"),
|
|
3825
|
+
React__default["default"].createElement("span", { className: "mx-3" },
|
|
3826
|
+
"Page",
|
|
3827
|
+
' ',
|
|
3828
|
+
pageNumber),
|
|
3829
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary ms-2", disabled: !hasAnotherPage, onClick: () => {
|
|
3830
|
+
dispatch({
|
|
3831
|
+
type: ActionType$6.IncrementPageNumber,
|
|
3832
|
+
});
|
|
3833
|
+
} },
|
|
3834
|
+
"Next Page",
|
|
3835
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faArrowRight, className: "ms-2" }))));
|
|
3836
|
+
/*----------------------------------------*/
|
|
3837
|
+
/* --------------- Filters -------------- */
|
|
3838
|
+
/*----------------------------------------*/
|
|
3839
|
+
// Filter toggle
|
|
3840
|
+
const filterToggles = (React__default["default"].createElement("div", { className: "LogReviewer-filter-toggles" },
|
|
3841
|
+
React__default["default"].createElement("h3", { className: "m-0" }, "Filters:"),
|
|
3842
|
+
React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
|
|
3843
|
+
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: () => {
|
|
3844
|
+
dispatch({
|
|
3845
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3846
|
+
filterDrawer: FilterDrawer.Date,
|
|
3847
|
+
});
|
|
3848
|
+
} },
|
|
3849
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCalendar, className: "me-2" }),
|
|
3850
|
+
"Date"),
|
|
3851
|
+
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: () => {
|
|
3852
|
+
dispatch({
|
|
3853
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3854
|
+
filterDrawer: FilterDrawer.Context,
|
|
3855
|
+
});
|
|
3856
|
+
} },
|
|
3857
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "me-2" }),
|
|
3858
|
+
"Context"),
|
|
3859
|
+
(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: () => {
|
|
3860
|
+
dispatch({
|
|
3861
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3862
|
+
filterDrawer: FilterDrawer.Tag,
|
|
3863
|
+
});
|
|
3864
|
+
} },
|
|
3865
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTag, className: "me-2" }),
|
|
3866
|
+
"Tag")),
|
|
3867
|
+
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: () => {
|
|
3868
|
+
dispatch({
|
|
3869
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3870
|
+
filterDrawer: FilterDrawer.Action,
|
|
3871
|
+
});
|
|
3872
|
+
} },
|
|
3873
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faHammer, className: "me-2" }),
|
|
3874
|
+
"Action"),
|
|
3875
|
+
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: () => {
|
|
3876
|
+
dispatch({
|
|
3877
|
+
type: ActionType$6.ToggleFilterDrawer,
|
|
3878
|
+
filterDrawer: FilterDrawer.Advanced,
|
|
3879
|
+
});
|
|
3880
|
+
} },
|
|
3881
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faList, className: "me-2" }),
|
|
3882
|
+
"Advanced"),
|
|
3883
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-reset-filters-button", className: "btn btn-light", "aria-label": "reset filters", onClick: () => {
|
|
3884
|
+
dispatch({
|
|
3885
|
+
type: ActionType$6.ResetFilters,
|
|
3886
|
+
initActionErrorFilterState,
|
|
3887
|
+
initAdvancedFilterState,
|
|
3888
|
+
initContextFilterState,
|
|
3889
|
+
initDateFilterState,
|
|
3890
|
+
initTagFilterState,
|
|
3891
|
+
});
|
|
3892
|
+
} },
|
|
3893
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes }),
|
|
3894
|
+
' ',
|
|
3895
|
+
"Reset"))));
|
|
3896
|
+
// Filter drawer
|
|
3897
|
+
let filterDrawer;
|
|
3898
|
+
if (expandedFilterDrawer) {
|
|
3899
|
+
if (expandedFilterDrawer === FilterDrawer.Date) {
|
|
3900
|
+
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Date" },
|
|
3901
|
+
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) => {
|
|
3902
|
+
dateFilterState.startDate = { month, day, year };
|
|
3891
3903
|
dispatch({
|
|
3892
|
-
type: ActionType$6.
|
|
3893
|
-
|
|
3904
|
+
type: ActionType$6.UpdateDateFilterState,
|
|
3905
|
+
dateFilterState,
|
|
3894
3906
|
});
|
|
3895
|
-
} },
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3907
|
+
} }),
|
|
3908
|
+
' ',
|
|
3909
|
+
"to",
|
|
3910
|
+
' ',
|
|
3911
|
+
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) => {
|
|
3912
|
+
if (year < dateFilterState.startDate.year
|
|
3913
|
+
|| (year === dateFilterState.startDate.year
|
|
3914
|
+
&& month < dateFilterState.startDate.month)
|
|
3915
|
+
|| (year === dateFilterState.startDate.year
|
|
3916
|
+
&& month === dateFilterState.startDate.month
|
|
3917
|
+
&& day < dateFilterState.startDate.day)) {
|
|
3918
|
+
return alert('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
3919
|
+
}
|
|
3920
|
+
dateFilterState.endDate = { month, day, year };
|
|
3899
3921
|
dispatch({
|
|
3900
|
-
type: ActionType$6.
|
|
3901
|
-
|
|
3902
|
-
initAdvancedFilterState,
|
|
3903
|
-
initContextFilterState,
|
|
3904
|
-
initDateFilterState,
|
|
3905
|
-
initTagFilterState,
|
|
3922
|
+
type: ActionType$6.UpdateDateFilterState,
|
|
3923
|
+
dateFilterState,
|
|
3906
3924
|
});
|
|
3907
|
-
} }
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
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) => {
|
|
3924
|
-
if (year < dateFilterState.startDate.year
|
|
3925
|
-
|| (year === dateFilterState.startDate.year
|
|
3926
|
-
&& month < dateFilterState.startDate.month)
|
|
3927
|
-
|| (year === dateFilterState.startDate.year
|
|
3928
|
-
&& month === dateFilterState.startDate.month
|
|
3929
|
-
&& day < dateFilterState.startDate.day)) {
|
|
3930
|
-
return alert('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
3931
|
-
}
|
|
3932
|
-
dateFilterState.endDate = { month, day, year };
|
|
3933
|
-
handleDateRangeUpdated(dateFilterState);
|
|
3934
|
-
} })));
|
|
3935
|
-
}
|
|
3936
|
-
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
3937
|
-
// Create item picker items
|
|
3938
|
-
const builtInPickableItem = {
|
|
3939
|
-
id: 'built-in-contexts',
|
|
3940
|
-
name: 'Auto-logged',
|
|
3941
|
-
isGroup: true,
|
|
3942
|
-
children: [],
|
|
3943
|
-
};
|
|
3944
|
-
const pickableItems = [];
|
|
3945
|
-
Object.keys(contextMap)
|
|
3946
|
-
.forEach((context) => {
|
|
3947
|
-
const value = contextMap[context];
|
|
3948
|
-
if (typeof value === 'string') {
|
|
3949
|
-
// No subcategories
|
|
3950
|
-
const item = {
|
|
3951
|
-
id: context,
|
|
3952
|
-
name: genHumanReadableName(context),
|
|
3953
|
-
isGroup: false,
|
|
3954
|
-
checked: !!contextFilterState[context],
|
|
3955
|
-
};
|
|
3956
|
-
// Add built-in items to its own folder
|
|
3957
|
-
const isBuiltIn = context in LogBuiltInMetadata.Context;
|
|
3958
|
-
if (isBuiltIn) {
|
|
3959
|
-
// Add to built-in pickable item
|
|
3960
|
-
builtInPickableItem.children.push(item);
|
|
3961
|
-
}
|
|
3962
|
-
else {
|
|
3963
|
-
// Add to pickable items list
|
|
3964
|
-
pickableItems.push(item);
|
|
3965
|
-
}
|
|
3966
|
-
return;
|
|
3967
|
-
}
|
|
3968
|
-
// Has subcategories
|
|
3969
|
-
const children = (Object.keys(value)
|
|
3970
|
-
// Remove parent name
|
|
3971
|
-
.filter((subcontext) => {
|
|
3972
|
-
return subcontext !== '_';
|
|
3973
|
-
})
|
|
3974
|
-
// Create child pickable items
|
|
3975
|
-
.map((subcontext) => {
|
|
3976
|
-
return {
|
|
3977
|
-
id: subcontext,
|
|
3978
|
-
name: genHumanReadableName(subcontext),
|
|
3979
|
-
isGroup: false,
|
|
3980
|
-
checked: contextFilterState[context][subcontext],
|
|
3981
|
-
};
|
|
3982
|
-
}));
|
|
3925
|
+
} })));
|
|
3926
|
+
}
|
|
3927
|
+
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
3928
|
+
// Create item picker items
|
|
3929
|
+
const builtInPickableItem = {
|
|
3930
|
+
id: 'built-in-contexts',
|
|
3931
|
+
name: 'Auto-logged',
|
|
3932
|
+
isGroup: true,
|
|
3933
|
+
children: [],
|
|
3934
|
+
};
|
|
3935
|
+
const pickableItems = [];
|
|
3936
|
+
Object.keys(contextMap)
|
|
3937
|
+
.forEach((context) => {
|
|
3938
|
+
const value = contextMap[context];
|
|
3939
|
+
if (typeof value === 'string') {
|
|
3940
|
+
// No subcategories
|
|
3983
3941
|
const item = {
|
|
3984
3942
|
id: context,
|
|
3985
3943
|
name: genHumanReadableName(context),
|
|
3986
|
-
isGroup:
|
|
3987
|
-
|
|
3944
|
+
isGroup: false,
|
|
3945
|
+
checked: !!contextFilterState[context],
|
|
3988
3946
|
};
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
3947
|
+
// Add built-in items to its own folder
|
|
3948
|
+
const isBuiltIn = context in LogBuiltInMetadata.Context;
|
|
3949
|
+
if (isBuiltIn) {
|
|
3950
|
+
// Add to built-in pickable item
|
|
3951
|
+
builtInPickableItem.children.push(item);
|
|
3952
|
+
}
|
|
3953
|
+
else {
|
|
3954
|
+
// Add to pickable items list
|
|
3955
|
+
pickableItems.push(item);
|
|
3956
|
+
}
|
|
3957
|
+
return;
|
|
3958
|
+
}
|
|
3959
|
+
// Has subcategories
|
|
3960
|
+
const children = (Object.keys(value)
|
|
3961
|
+
// Remove parent name
|
|
3962
|
+
.filter((subcontext) => {
|
|
3963
|
+
return subcontext !== '_';
|
|
3964
|
+
})
|
|
3965
|
+
// Create child pickable items
|
|
3966
|
+
.map((subcontext) => {
|
|
3967
|
+
return {
|
|
3968
|
+
id: subcontext,
|
|
3969
|
+
name: genHumanReadableName(subcontext),
|
|
3970
|
+
isGroup: false,
|
|
3971
|
+
checked: contextFilterState[context][subcontext],
|
|
3972
|
+
};
|
|
3973
|
+
}));
|
|
3974
|
+
const item = {
|
|
3975
|
+
id: context,
|
|
3976
|
+
name: genHumanReadableName(context),
|
|
3977
|
+
isGroup: true,
|
|
3978
|
+
children,
|
|
3979
|
+
};
|
|
3980
|
+
pickableItems.push(item);
|
|
3981
|
+
});
|
|
3982
|
+
// Add built-in contexts to end ofl ist
|
|
3983
|
+
pickableItems.push(builtInPickableItem);
|
|
3984
|
+
// Create filter UI
|
|
3985
|
+
filterDrawer = (React__default["default"].createElement(ItemPicker, { title: "Context", items: pickableItems, onChanged: (updatedItems) => {
|
|
3986
|
+
// Update our state
|
|
3987
|
+
updatedItems.forEach((pickableItem) => {
|
|
3988
|
+
if (pickableItem.isGroup) {
|
|
3989
|
+
// Has subcontexts
|
|
3990
|
+
if (pickableItem.id === 'built-in-contexts') {
|
|
3991
|
+
// Built-in
|
|
3992
|
+
// Treat as if these were top-level contexts
|
|
3993
|
+
pickableItem.children.forEach((subcontextItem) => {
|
|
3994
|
+
contextFilterState[subcontextItem.id] = ('checked' in subcontextItem
|
|
3995
|
+
&& subcontextItem.checked);
|
|
3996
|
+
});
|
|
4015
3997
|
}
|
|
4016
3998
|
else {
|
|
4017
|
-
//
|
|
4018
|
-
|
|
3999
|
+
// Not built-in
|
|
4000
|
+
pickableItem.children.forEach((subcontextItem) => {
|
|
4001
|
+
if (!subcontextItem.isGroup) {
|
|
4002
|
+
contextFilterState[pickableItem.id][subcontextItem.id] = (subcontextItem.checked);
|
|
4003
|
+
}
|
|
4004
|
+
});
|
|
4019
4005
|
}
|
|
4020
|
-
}
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
contextFilterState
|
|
4024
|
-
}
|
|
4025
|
-
}
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4006
|
+
}
|
|
4007
|
+
else {
|
|
4008
|
+
// No subcontexts
|
|
4009
|
+
contextFilterState[pickableItem.id] = (pickableItem.checked);
|
|
4010
|
+
}
|
|
4011
|
+
});
|
|
4012
|
+
dispatch({
|
|
4013
|
+
type: ActionType$6.UpdateContextFilterState,
|
|
4014
|
+
contextFilterState,
|
|
4015
|
+
});
|
|
4016
|
+
} }));
|
|
4017
|
+
}
|
|
4018
|
+
else if (expandedFilterDrawer === FilterDrawer.Tag) {
|
|
4019
|
+
// Create filter UI
|
|
4020
|
+
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Tags" },
|
|
4021
|
+
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."),
|
|
4022
|
+
React__default["default"].createElement("div", { className: "d-flex gap-1 flex-wrap" }, Object.keys((_d = LogMetadata.Tag) !== null && _d !== void 0 ? _d : {})
|
|
4023
|
+
.map((tag) => {
|
|
4024
|
+
const description = genHumanReadableName(tag);
|
|
4025
|
+
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) => {
|
|
4026
|
+
tagFilterState[tag] = checked;
|
|
4027
|
+
dispatch({
|
|
4028
|
+
type: ActionType$6.UpdateTagFilterState,
|
|
4029
|
+
tagFilterState,
|
|
4030
|
+
});
|
|
4031
|
+
} }));
|
|
4032
|
+
}))));
|
|
4033
|
+
}
|
|
4034
|
+
else if (expandedFilterDrawer === FilterDrawer.Action) {
|
|
4035
|
+
// Create filter UI
|
|
4036
|
+
filterDrawer = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4037
|
+
React__default["default"].createElement(TabBox, { title: "Log Type" },
|
|
4038
|
+
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
|
|
4039
|
+
actionErrorFilterState.type = undefined;
|
|
4040
|
+
dispatch({
|
|
4041
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4042
|
+
actionErrorFilterState,
|
|
4043
|
+
});
|
|
4044
|
+
}, ariaLabel: "show logs of all types", selected: actionErrorFilterState.type === undefined }),
|
|
4045
|
+
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
|
|
4046
|
+
actionErrorFilterState.type = LogType$1.Action;
|
|
4047
|
+
dispatch({
|
|
4048
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4049
|
+
actionErrorFilterState,
|
|
4050
|
+
});
|
|
4051
|
+
}, ariaLabel: "only show action logs", selected: actionErrorFilterState.type === LogType$1.Action }),
|
|
4052
|
+
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
|
|
4053
|
+
actionErrorFilterState.type = LogType$1.Error;
|
|
4054
|
+
dispatch({
|
|
4055
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4056
|
+
actionErrorFilterState,
|
|
4057
|
+
});
|
|
4058
|
+
}, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
|
|
4059
|
+
(actionErrorFilterState.type === undefined
|
|
4060
|
+
|| actionErrorFilterState.type === LogType$1.Action) && (React__default["default"].createElement(TabBox, { title: "Action Log Details" },
|
|
4061
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Action", className: "mb-2", wrapButtonsAndAddGaps: true }, Object.keys(LogAction$1)
|
|
4062
|
+
.map((action) => {
|
|
4063
|
+
const description = genHumanReadableName(action);
|
|
4064
|
+
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) => {
|
|
4065
|
+
actionErrorFilterState.action[action] = checked;
|
|
4036
4066
|
dispatch({
|
|
4037
|
-
type: ActionType$6.
|
|
4038
|
-
|
|
4067
|
+
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4068
|
+
actionErrorFilterState,
|
|
4039
4069
|
});
|
|
4040
4070
|
} }));
|
|
4041
|
-
}))
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
|
|
4048
|
-
actionErrorFilterState.type = undefined;
|
|
4071
|
+
})),
|
|
4072
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Target", wrapButtonsAndAddGaps: true }, Object.keys(targetMap)
|
|
4073
|
+
.map((target) => {
|
|
4074
|
+
const description = genHumanReadableName(target);
|
|
4075
|
+
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) => {
|
|
4076
|
+
actionErrorFilterState.target[target] = checked;
|
|
4049
4077
|
dispatch({
|
|
4050
4078
|
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4051
4079
|
actionErrorFilterState,
|
|
4052
4080
|
});
|
|
4053
|
-
}
|
|
4054
|
-
|
|
4055
|
-
|
|
4081
|
+
} }));
|
|
4082
|
+
})))),
|
|
4083
|
+
(actionErrorFilterState.type === undefined
|
|
4084
|
+
|| actionErrorFilterState.type === LogType$1.Error) && (React__default["default"].createElement(TabBox, { title: "Error Log Details" },
|
|
4085
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4086
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Error Message"),
|
|
4087
|
+
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) => {
|
|
4088
|
+
actionErrorFilterState.errorMessage = e.target.value;
|
|
4056
4089
|
dispatch({
|
|
4057
4090
|
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4058
4091
|
actionErrorFilterState,
|
|
4059
4092
|
});
|
|
4060
|
-
}
|
|
4061
|
-
|
|
4062
|
-
|
|
4093
|
+
} })),
|
|
4094
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4095
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Error Code"),
|
|
4096
|
+
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) => {
|
|
4097
|
+
actionErrorFilterState.errorCode = ((e.target.value)
|
|
4098
|
+
.trim()
|
|
4099
|
+
.toUpperCase());
|
|
4063
4100
|
dispatch({
|
|
4064
4101
|
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4065
4102
|
actionErrorFilterState,
|
|
4066
4103
|
});
|
|
4067
|
-
}
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
React__default["default"].createElement("
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
.toUpperCase());
|
|
4109
|
-
dispatch({
|
|
4110
|
-
type: ActionType$6.UpdateActionErrorFilterState,
|
|
4111
|
-
actionErrorFilterState,
|
|
4112
|
-
});
|
|
4113
|
-
} }))))));
|
|
4114
|
-
}
|
|
4115
|
-
else if (expandedFilterDrawer === FilterDrawer.Advanced) {
|
|
4116
|
-
// Create advanced filter ui
|
|
4117
|
-
filterDrawer = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4118
|
-
React__default["default"].createElement(TabBox, { title: "User" },
|
|
4119
|
-
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4120
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "User First Name"),
|
|
4121
|
-
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) => {
|
|
4122
|
-
advancedFilterState.userFirstName = e.target.value;
|
|
4123
|
-
dispatch({
|
|
4124
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4125
|
-
advancedFilterState,
|
|
4126
|
-
});
|
|
4127
|
-
} })),
|
|
4128
|
-
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4129
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "User Last Name"),
|
|
4130
|
-
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) => {
|
|
4131
|
-
advancedFilterState.userLastName = e.target.value;
|
|
4132
|
-
dispatch({
|
|
4133
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4134
|
-
advancedFilterState,
|
|
4135
|
-
});
|
|
4136
|
-
} })),
|
|
4137
|
-
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4138
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "User Email"),
|
|
4139
|
-
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) => {
|
|
4140
|
-
advancedFilterState.userEmail = ((e.target.value)
|
|
4104
|
+
} }))))));
|
|
4105
|
+
}
|
|
4106
|
+
else if (expandedFilterDrawer === FilterDrawer.Advanced) {
|
|
4107
|
+
// Create advanced filter ui
|
|
4108
|
+
filterDrawer = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4109
|
+
React__default["default"].createElement(TabBox, { title: "User" },
|
|
4110
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4111
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User First Name"),
|
|
4112
|
+
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) => {
|
|
4113
|
+
advancedFilterState.userFirstName = e.target.value;
|
|
4114
|
+
dispatch({
|
|
4115
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4116
|
+
advancedFilterState,
|
|
4117
|
+
});
|
|
4118
|
+
} })),
|
|
4119
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4120
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User Last Name"),
|
|
4121
|
+
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) => {
|
|
4122
|
+
advancedFilterState.userLastName = e.target.value;
|
|
4123
|
+
dispatch({
|
|
4124
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4125
|
+
advancedFilterState,
|
|
4126
|
+
});
|
|
4127
|
+
} })),
|
|
4128
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4129
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User Email"),
|
|
4130
|
+
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) => {
|
|
4131
|
+
advancedFilterState.userEmail = ((e.target.value)
|
|
4132
|
+
.trim());
|
|
4133
|
+
dispatch({
|
|
4134
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4135
|
+
advancedFilterState,
|
|
4136
|
+
});
|
|
4137
|
+
} })),
|
|
4138
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4139
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "User Canvas Id"),
|
|
4140
|
+
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) => {
|
|
4141
|
+
const { value } = e.target;
|
|
4142
|
+
// Only update if value contains only numbers
|
|
4143
|
+
if (/^\d+$/.test(value)) {
|
|
4144
|
+
advancedFilterState.userId = ((e.target.value)
|
|
4141
4145
|
.trim());
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
}
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
advancedFilterState
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4146
|
+
}
|
|
4147
|
+
dispatch({
|
|
4148
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4149
|
+
advancedFilterState,
|
|
4150
|
+
});
|
|
4151
|
+
} })),
|
|
4152
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Role" },
|
|
4153
|
+
React__default["default"].createElement(CheckboxButton, { text: "Students", onChanged: (checked) => {
|
|
4154
|
+
advancedFilterState.includeLearners = checked;
|
|
4155
|
+
dispatch({
|
|
4156
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4157
|
+
advancedFilterState,
|
|
4158
|
+
});
|
|
4159
|
+
}, checked: advancedFilterState.includeLearners, ariaLabel: "show logs from students" }),
|
|
4160
|
+
React__default["default"].createElement(CheckboxButton, { text: "Teaching Team Members", onChanged: (checked) => {
|
|
4161
|
+
advancedFilterState.includeTTMs = checked;
|
|
4162
|
+
dispatch({
|
|
4163
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4164
|
+
advancedFilterState,
|
|
4165
|
+
});
|
|
4166
|
+
}, checked: advancedFilterState.includeTTMs, ariaLabel: "show logs from teaching team members" }),
|
|
4167
|
+
React__default["default"].createElement(CheckboxButton, { text: "Admins", onChanged: (checked) => {
|
|
4168
|
+
advancedFilterState.includeAdmins = checked;
|
|
4169
|
+
dispatch({
|
|
4170
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4171
|
+
advancedFilterState,
|
|
4172
|
+
});
|
|
4173
|
+
}, checked: advancedFilterState.includeAdmins, ariaLabel: "show logs from admins" }))),
|
|
4174
|
+
React__default["default"].createElement(TabBox, { title: "Course" },
|
|
4175
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4176
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Course Name"),
|
|
4177
|
+
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) => {
|
|
4178
|
+
advancedFilterState.courseName = e.target.value;
|
|
4179
|
+
dispatch({
|
|
4180
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4181
|
+
advancedFilterState,
|
|
4182
|
+
});
|
|
4183
|
+
} })),
|
|
4184
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4185
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Course Canvas Id"),
|
|
4186
|
+
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) => {
|
|
4187
|
+
const { value } = e.target;
|
|
4188
|
+
// Only update if value contains only numbers
|
|
4189
|
+
if (/^\d+$/.test(value)) {
|
|
4190
|
+
advancedFilterState.courseId = ((e.target.value)
|
|
4191
|
+
.trim());
|
|
4192
|
+
}
|
|
4193
|
+
dispatch({
|
|
4194
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4195
|
+
advancedFilterState,
|
|
4196
|
+
});
|
|
4197
|
+
} }))),
|
|
4198
|
+
React__default["default"].createElement(TabBox, { title: "Device" },
|
|
4199
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Device Type" },
|
|
4200
|
+
React__default["default"].createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
|
|
4201
|
+
advancedFilterState.isMobile = undefined;
|
|
4202
|
+
dispatch({
|
|
4203
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4204
|
+
advancedFilterState,
|
|
4205
|
+
});
|
|
4206
|
+
} }),
|
|
4207
|
+
React__default["default"].createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
|
|
4208
|
+
advancedFilterState.isMobile = true;
|
|
4209
|
+
dispatch({
|
|
4210
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4211
|
+
advancedFilterState,
|
|
4212
|
+
});
|
|
4213
|
+
} }),
|
|
4214
|
+
React__default["default"].createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
|
|
4215
|
+
advancedFilterState.isMobile = false;
|
|
4216
|
+
dispatch({
|
|
4217
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4218
|
+
advancedFilterState,
|
|
4219
|
+
});
|
|
4220
|
+
}, noMarginOnRight: true }))),
|
|
4221
|
+
React__default["default"].createElement(TabBox, { title: "Source" },
|
|
4222
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Source Type" },
|
|
4223
|
+
React__default["default"].createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
|
|
4224
|
+
advancedFilterState.source = undefined;
|
|
4225
|
+
dispatch({
|
|
4226
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4227
|
+
advancedFilterState,
|
|
4228
|
+
});
|
|
4229
|
+
} }),
|
|
4230
|
+
React__default["default"].createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
|
|
4231
|
+
advancedFilterState.source = LogSource$1.Client;
|
|
4232
|
+
dispatch({
|
|
4233
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4234
|
+
advancedFilterState,
|
|
4235
|
+
});
|
|
4236
|
+
} }),
|
|
4237
|
+
React__default["default"].createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
|
|
4238
|
+
advancedFilterState.source = LogSource$1.Server;
|
|
4239
|
+
dispatch({
|
|
4240
|
+
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4241
|
+
advancedFilterState,
|
|
4242
|
+
});
|
|
4243
|
+
}, noMarginOnRight: true })),
|
|
4244
|
+
advancedFilterState.source !== LogSource$1.Client && (React__default["default"].createElement("div", { className: "mt-2" },
|
|
4184
4245
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4185
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "
|
|
4186
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for
|
|
4187
|
-
advancedFilterState.courseName = e.target.value
|
|
4246
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Path"),
|
|
4247
|
+
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) => {
|
|
4248
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
4249
|
+
.trim());
|
|
4188
4250
|
dispatch({
|
|
4189
4251
|
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4190
4252
|
advancedFilterState,
|
|
4191
4253
|
});
|
|
4192
4254
|
} })),
|
|
4193
4255
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
4194
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "
|
|
4195
|
-
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
if (/^\d+$/.test(value)) {
|
|
4199
|
-
advancedFilterState.courseId = ((e.target.value)
|
|
4200
|
-
.trim());
|
|
4201
|
-
}
|
|
4202
|
-
dispatch({
|
|
4203
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4204
|
-
advancedFilterState,
|
|
4205
|
-
});
|
|
4206
|
-
} }))),
|
|
4207
|
-
React__default["default"].createElement(TabBox, { title: "Device" },
|
|
4208
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Device Type" },
|
|
4209
|
-
React__default["default"].createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
|
|
4210
|
-
advancedFilterState.isMobile = undefined;
|
|
4211
|
-
dispatch({
|
|
4212
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4213
|
-
advancedFilterState,
|
|
4214
|
-
});
|
|
4215
|
-
} }),
|
|
4216
|
-
React__default["default"].createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
|
|
4217
|
-
advancedFilterState.isMobile = true;
|
|
4218
|
-
dispatch({
|
|
4219
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4220
|
-
advancedFilterState,
|
|
4221
|
-
});
|
|
4222
|
-
} }),
|
|
4223
|
-
React__default["default"].createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
|
|
4224
|
-
advancedFilterState.isMobile = false;
|
|
4225
|
-
dispatch({
|
|
4226
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4227
|
-
advancedFilterState,
|
|
4228
|
-
});
|
|
4229
|
-
}, noMarginOnRight: true }))),
|
|
4230
|
-
React__default["default"].createElement(TabBox, { title: "Source" },
|
|
4231
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Source Type" },
|
|
4232
|
-
React__default["default"].createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
|
|
4233
|
-
advancedFilterState.source = undefined;
|
|
4234
|
-
dispatch({
|
|
4235
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4236
|
-
advancedFilterState,
|
|
4237
|
-
});
|
|
4238
|
-
} }),
|
|
4239
|
-
React__default["default"].createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
|
|
4240
|
-
advancedFilterState.source = LogSource$1.Client;
|
|
4241
|
-
dispatch({
|
|
4242
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4243
|
-
advancedFilterState,
|
|
4244
|
-
});
|
|
4245
|
-
} }),
|
|
4246
|
-
React__default["default"].createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
|
|
4247
|
-
advancedFilterState.source = LogSource$1.Server;
|
|
4256
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
4257
|
+
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) => {
|
|
4258
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
4259
|
+
.trim());
|
|
4248
4260
|
dispatch({
|
|
4249
4261
|
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4250
4262
|
advancedFilterState,
|
|
4251
4263
|
});
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
4266
|
-
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) => {
|
|
4267
|
-
advancedFilterState.courseName = ((e.target.value)
|
|
4268
|
-
.trim());
|
|
4269
|
-
dispatch({
|
|
4270
|
-
type: ActionType$6.UpdateAdvancedFilterState,
|
|
4271
|
-
advancedFilterState,
|
|
4272
|
-
});
|
|
4273
|
-
} })))))));
|
|
4274
|
-
}
|
|
4275
|
-
}
|
|
4276
|
-
// Filters UI
|
|
4277
|
-
const filters = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4278
|
-
filterToggles,
|
|
4279
|
-
filterDrawer && (React__default["default"].createElement(Drawer, { customBackgroundColor: "#eee" }, filterDrawer))));
|
|
4280
|
-
// Actually filter the logs
|
|
4281
|
-
// > Perform filters
|
|
4282
|
-
const logs = [];
|
|
4283
|
-
Object.keys(logMap).forEach((year) => {
|
|
4284
|
-
Object.keys(logMap[year]).forEach((month) => {
|
|
4285
|
-
logMap[year][month].forEach((log) => {
|
|
4286
|
-
/* ----------- Date Filter ---------- */
|
|
4287
|
-
var _a;
|
|
4288
|
-
// Before start date
|
|
4289
|
-
if (
|
|
4290
|
-
// Previous year
|
|
4291
|
-
log.year < dateFilterState.startDate.year
|
|
4292
|
-
// Same year, earlier month
|
|
4293
|
-
|| ((log.year === dateFilterState.startDate.year)
|
|
4294
|
-
&& (log.month < dateFilterState.startDate.month))
|
|
4295
|
-
// Same year, same month, earlier day
|
|
4296
|
-
|| ((log.year === dateFilterState.startDate.year)
|
|
4297
|
-
&& (log.month === dateFilterState.startDate.month)
|
|
4298
|
-
&& (log.day < dateFilterState.startDate.day))) {
|
|
4299
|
-
return;
|
|
4300
|
-
}
|
|
4301
|
-
// After end date
|
|
4302
|
-
if (
|
|
4303
|
-
// Later year
|
|
4304
|
-
log.year > dateFilterState.endDate.year
|
|
4305
|
-
// Same year, later month
|
|
4306
|
-
|| ((log.year === dateFilterState.endDate.year)
|
|
4307
|
-
&& (log.month > dateFilterState.endDate.month))
|
|
4308
|
-
// Same year, same month, later day
|
|
4309
|
-
|| ((log.year === dateFilterState.endDate.year)
|
|
4310
|
-
&& (log.month === dateFilterState.endDate.month)
|
|
4311
|
-
&& (log.day > dateFilterState.endDate.day))) {
|
|
4312
|
-
return;
|
|
4313
|
-
}
|
|
4314
|
-
/* --------- Context Filter --------- */
|
|
4315
|
-
// Context doesn't match
|
|
4316
|
-
if (
|
|
4317
|
-
// Whole context is deselected
|
|
4318
|
-
contextFilterState[log.context] === false
|
|
4319
|
-
// None of the subcontexts are selected
|
|
4320
|
-
|| (
|
|
4321
|
-
// Has subcontexts
|
|
4322
|
-
typeof contextFilterState[log.context] !== 'boolean'
|
|
4323
|
-
// None of the subcontexts are selected
|
|
4324
|
-
&& Object.values((_a = contextFilterState[log.context]) !== null && _a !== void 0 ? _a : {})
|
|
4325
|
-
.every((isSelected) => {
|
|
4326
|
-
return !isSelected;
|
|
4327
|
-
}))) {
|
|
4328
|
-
return;
|
|
4329
|
-
}
|
|
4330
|
-
// Subcontext doesn't match
|
|
4331
|
-
if (
|
|
4332
|
-
// Log context is not "uncategorized" (no point in further filters)
|
|
4333
|
-
log.context !== LogBuiltInMetadata.Context.Uncategorized
|
|
4334
|
-
// Log has a subcontext
|
|
4335
|
-
&& log.subcontext
|
|
4336
|
-
// Context has subcontexts
|
|
4337
|
-
&& (contextFilterState[log.context]
|
|
4338
|
-
&& contextFilterState[log.context] !== false
|
|
4339
|
-
&& contextFilterState[log.context] !== true)
|
|
4340
|
-
// Subcontext is not selected
|
|
4341
|
-
&& !contextFilterState[log.context][log.subcontext]) {
|
|
4342
|
-
return;
|
|
4343
|
-
}
|
|
4344
|
-
/* -------------- Tags -------------- */
|
|
4345
|
-
// No tags match
|
|
4346
|
-
if (
|
|
4347
|
-
// At least one tag is required
|
|
4348
|
-
Object.values(tagFilterState)
|
|
4349
|
-
.filter((isSelected) => {
|
|
4350
|
-
return isSelected;
|
|
4351
|
-
})
|
|
4352
|
-
.length > 0
|
|
4353
|
-
// No tags match
|
|
4354
|
-
&& log.tags.every((tag) => {
|
|
4355
|
-
return !tagFilterState[tag];
|
|
4356
|
-
})) {
|
|
4357
|
-
return;
|
|
4358
|
-
}
|
|
4359
|
-
/* ------- Actions and Errors ------- */
|
|
4360
|
-
// Log type doesn't match
|
|
4361
|
-
if (
|
|
4362
|
-
// Filter won't allow all types
|
|
4363
|
-
actionErrorFilterState.type !== undefined
|
|
4364
|
-
// Log type doesn't match
|
|
4365
|
-
&& actionErrorFilterState.type !== log.type) {
|
|
4366
|
-
return;
|
|
4367
|
-
}
|
|
4368
|
-
// Filter errors
|
|
4369
|
-
if (log.type === LogType$1.Error) {
|
|
4370
|
-
// Message doesn't match
|
|
4371
|
-
if (
|
|
4372
|
-
// Message exists
|
|
4373
|
-
log.errorMessage
|
|
4374
|
-
// Message filter exists
|
|
4375
|
-
&& actionErrorFilterState.errorMessage.trim().length > 0
|
|
4376
|
-
// Message doesn't match
|
|
4377
|
-
&& log.errorMessage.toLowerCase().includes(actionErrorFilterState.errorMessage.trim().toLowerCase())) {
|
|
4378
|
-
return;
|
|
4379
|
-
}
|
|
4380
|
-
// Code doesn't match
|
|
4381
|
-
if (
|
|
4382
|
-
// Code exists
|
|
4383
|
-
log.errorCode
|
|
4384
|
-
// Code filter exists
|
|
4385
|
-
&& actionErrorFilterState.errorCode.trim().length > 0
|
|
4386
|
-
// Code doesn't match
|
|
4387
|
-
&& log.errorCode.toUpperCase().includes(actionErrorFilterState.errorCode.trim().toUpperCase())) {
|
|
4388
|
-
return;
|
|
4389
|
-
}
|
|
4390
|
-
}
|
|
4391
|
-
// Filter actions
|
|
4392
|
-
if (log.type === LogType$1.Action) {
|
|
4393
|
-
// Target isn't selected
|
|
4394
|
-
if (
|
|
4395
|
-
// Target exists
|
|
4396
|
-
log.target
|
|
4397
|
-
// Target isn't selected
|
|
4398
|
-
&& !actionErrorFilterState.target[log.target]) {
|
|
4399
|
-
return;
|
|
4400
|
-
}
|
|
4401
|
-
// Action
|
|
4402
|
-
if (
|
|
4403
|
-
// Action exists
|
|
4404
|
-
log.action
|
|
4405
|
-
// Action isn't selected
|
|
4406
|
-
&& !actionErrorFilterState.action[log.action]) {
|
|
4407
|
-
return;
|
|
4408
|
-
}
|
|
4409
|
-
}
|
|
4410
|
-
/* --------- Advanced Filter -------- */
|
|
4411
|
-
// First name doesn't match
|
|
4412
|
-
if (
|
|
4413
|
-
// First name exists
|
|
4414
|
-
log.userFirstName
|
|
4415
|
-
// First name query doesn't match
|
|
4416
|
-
&& !log.userFirstName.toLowerCase().includes(advancedFilterState.userFirstName.toLowerCase().trim())) {
|
|
4417
|
-
return;
|
|
4418
|
-
}
|
|
4419
|
-
// Last name doesn't match
|
|
4420
|
-
if (
|
|
4421
|
-
// Last name exists
|
|
4422
|
-
log.userLastName
|
|
4423
|
-
// Last name query doesn't match
|
|
4424
|
-
&& !log.userLastName.toLowerCase().includes(advancedFilterState.userLastName.toLowerCase().trim())) {
|
|
4425
|
-
return;
|
|
4426
|
-
}
|
|
4427
|
-
// Email doesn't match
|
|
4428
|
-
if (
|
|
4429
|
-
// Email exists
|
|
4430
|
-
log.userEmail
|
|
4431
|
-
// Email query doesn't match
|
|
4432
|
-
&& !log.userEmail.toLowerCase().includes(advancedFilterState.userEmail.toLowerCase().trim())) {
|
|
4433
|
-
return;
|
|
4434
|
-
}
|
|
4435
|
-
// User id doesn't match
|
|
4436
|
-
if (
|
|
4437
|
-
// User id exists
|
|
4438
|
-
log.userId
|
|
4439
|
-
// User id doesn't match
|
|
4440
|
-
&& !String(log.userId).includes(advancedFilterState.userId.trim())) {
|
|
4441
|
-
return;
|
|
4442
|
-
}
|
|
4443
|
-
// Learner not allowed
|
|
4444
|
-
if (
|
|
4445
|
-
// User is a learner
|
|
4446
|
-
log.isLearner
|
|
4447
|
-
// Learners aren't included
|
|
4448
|
-
&& !advancedFilterState.includeLearners) {
|
|
4449
|
-
return;
|
|
4450
|
-
}
|
|
4451
|
-
// TTM not allowed
|
|
4452
|
-
if (
|
|
4453
|
-
// User is a ttm
|
|
4454
|
-
log.isTTM
|
|
4455
|
-
// TTMs aren't included
|
|
4456
|
-
&& !advancedFilterState.includeTTMs) {
|
|
4457
|
-
return;
|
|
4458
|
-
}
|
|
4459
|
-
// Admin not allowed
|
|
4460
|
-
if (
|
|
4461
|
-
// User is an admin
|
|
4462
|
-
log.isAdmin
|
|
4463
|
-
// Admins aren't included
|
|
4464
|
-
&& !advancedFilterState.includeAdmins) {
|
|
4465
|
-
return;
|
|
4466
|
-
}
|
|
4467
|
-
// Course Id doesn't match
|
|
4468
|
-
if (
|
|
4469
|
-
// Course Id exists
|
|
4470
|
-
log.courseId
|
|
4471
|
-
// Course Id doesn't match
|
|
4472
|
-
&& !String(log.courseId).includes(advancedFilterState.courseId.trim())) {
|
|
4473
|
-
return;
|
|
4474
|
-
}
|
|
4475
|
-
// Course name doesn't match
|
|
4476
|
-
if (
|
|
4477
|
-
// Course name exists
|
|
4478
|
-
log.courseName
|
|
4479
|
-
// Course name doesn't match
|
|
4480
|
-
&& !String(log.courseName).includes(advancedFilterState.courseName.trim())) {
|
|
4481
|
-
return;
|
|
4482
|
-
}
|
|
4483
|
-
// Mobile filter doesn't match
|
|
4484
|
-
if (
|
|
4485
|
-
// Mobile filter exists
|
|
4486
|
-
advancedFilterState.isMobile !== undefined
|
|
4487
|
-
// Device info exists
|
|
4488
|
-
&& log.device
|
|
4489
|
-
// Mobile filter doesn't match
|
|
4490
|
-
&& (advancedFilterState.isMobile !== log.device.isMobile)) {
|
|
4491
|
-
return;
|
|
4492
|
-
}
|
|
4493
|
-
// Log source doesn't match
|
|
4494
|
-
if (
|
|
4495
|
-
// Source filter exists
|
|
4496
|
-
advancedFilterState.source !== undefined
|
|
4497
|
-
// Source info exists
|
|
4498
|
-
&& log.source
|
|
4499
|
-
// Source filter doesn't match
|
|
4500
|
-
&& (advancedFilterState.source !== log.source)) {
|
|
4501
|
-
return;
|
|
4502
|
-
}
|
|
4503
|
-
// Route path doesn't match (Only for server source)
|
|
4504
|
-
if (
|
|
4505
|
-
// Source is server
|
|
4506
|
-
(log.source === LogSource$1.Server)
|
|
4507
|
-
// Route path is being filtered
|
|
4508
|
-
&& (advancedFilterState.routePath.trim().length)
|
|
4509
|
-
// Route path doesn't match
|
|
4510
|
-
&& !(log.routePath.includes(advancedFilterState.routePath.trim()))) {
|
|
4511
|
-
return;
|
|
4512
|
-
}
|
|
4513
|
-
// Route template doesn't match (Only for server source)
|
|
4514
|
-
if (
|
|
4515
|
-
// Source is server
|
|
4516
|
-
(log.source === LogSource$1.Server)
|
|
4517
|
-
// Route template is being filtered
|
|
4518
|
-
&& (advancedFilterState.routeTemplate.trim().length)
|
|
4519
|
-
// Route template doesn't match
|
|
4520
|
-
&& !(log.routeTemplate.includes(advancedFilterState.routeTemplate.trim()))) {
|
|
4521
|
-
return;
|
|
4522
|
-
}
|
|
4523
|
-
/* -------------- Done -------------- */
|
|
4524
|
-
// Made it past all filters. Add to the list
|
|
4525
|
-
logs.push(log);
|
|
4526
|
-
});
|
|
4527
|
-
});
|
|
4528
|
-
});
|
|
4529
|
-
/*----------------------------------------*/
|
|
4530
|
-
/* ---------------- Data ---------------- */
|
|
4531
|
-
/*----------------------------------------*/
|
|
4532
|
-
// Nothing to show notice
|
|
4533
|
-
const noLogsNotice = (logs.length === 0
|
|
4534
|
-
? (React__default["default"].createElement("div", { className: "alert alert-warning text-center mt-2" },
|
|
4264
|
+
} })))))));
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
// Filters UI
|
|
4268
|
+
const filters = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4269
|
+
filterToggles,
|
|
4270
|
+
filterDrawer && (React__default["default"].createElement(Drawer, { customBackgroundColor: "#eee" }, filterDrawer))));
|
|
4271
|
+
// Main body
|
|
4272
|
+
body = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4273
|
+
filters,
|
|
4274
|
+
React__default["default"].createElement("div", { className: "mt-2" },
|
|
4275
|
+
React__default["default"].createElement(IntelliTable, { title: "Matching Logs:", csvName: `Logs from ${getHumanReadableDate()}`, id: "logs", data: logs, columns: columns }),
|
|
4276
|
+
logs.length === 0 && (React__default["default"].createElement("div", { className: "alert alert-warning text-center mt-2" },
|
|
4535
4277
|
React__default["default"].createElement("h4", { className: "m-1" }, "No Logs to Show"),
|
|
4536
|
-
React__default["default"].createElement("div", null, "Either your filters are too strict or no matching logs have been created yet.")))
|
|
4537
|
-
|
|
4538
|
-
// Create intelliTable
|
|
4539
|
-
const dataTable = (React__default["default"].createElement(IntelliTable, { title: "Matching Logs:", csvName: `Logs from ${getHumanReadableDate()}`, id: "logs", data: logs, columns: columns }));
|
|
4540
|
-
// Main body
|
|
4541
|
-
body = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4542
|
-
filters,
|
|
4543
|
-
React__default["default"].createElement("div", { className: "mt-2" },
|
|
4544
|
-
dataTable,
|
|
4545
|
-
noLogsNotice)));
|
|
4546
|
-
}
|
|
4278
|
+
React__default["default"].createElement("div", null, "Either your filters are too strict or no matching logs have been created yet."))),
|
|
4279
|
+
paginationControls)));
|
|
4547
4280
|
/* ---------- Wrap in Modal --------- */
|
|
4548
4281
|
return (React__default["default"].createElement("div", { className: "LogReviewer-outer-container" },
|
|
4549
4282
|
React__default["default"].createElement("style", null, style$2),
|
|
@@ -14055,33 +13788,134 @@ const initServer = (opts) => {
|
|
|
14055
13788
|
}),
|
|
14056
13789
|
}));
|
|
14057
13790
|
/**
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14061
|
-
|
|
14062
|
-
|
|
14063
|
-
*/
|
|
14064
|
-
opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler({
|
|
13791
|
+
* Get filtered logs based on provided filters
|
|
13792
|
+
* @author Gabe Abrams, Yuen Ler Chow
|
|
13793
|
+
* @returns {Log[]} list of logs that match the filters
|
|
13794
|
+
*/
|
|
13795
|
+
opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/logs`, genRouteHandler({
|
|
14065
13796
|
paramTypes: {
|
|
14066
|
-
year: ParamType$1.Int,
|
|
14067
|
-
month: ParamType$1.Int,
|
|
14068
13797
|
pageNumber: ParamType$1.Int,
|
|
13798
|
+
filters: ParamType$1.JSON,
|
|
14069
13799
|
},
|
|
14070
13800
|
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14071
13801
|
// Get user info
|
|
14072
|
-
const {
|
|
13802
|
+
const { pageNumber, userId, isAdmin, filters, } = params;
|
|
14073
13803
|
// Validate user
|
|
14074
13804
|
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
14075
13805
|
if (!canReview) {
|
|
14076
13806
|
throw new ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ReactKitErrorCode$1.NotAllowedToReviewLogs);
|
|
14077
13807
|
}
|
|
13808
|
+
// Build MongoDB query based on filters
|
|
13809
|
+
const query = {};
|
|
13810
|
+
/* -------------- Date Filter ------------- */
|
|
13811
|
+
const { startDate, endDate } = filters.dateFilterState;
|
|
13812
|
+
const startTimestamp = new Date(startDate.year, startDate.month - 1, startDate.day).getTime();
|
|
13813
|
+
const endTimestamp = new Date(endDate.year, endDate.month - 1, endDate.day + 1).getTime() - 1;
|
|
13814
|
+
query.timestamp = {
|
|
13815
|
+
$gte: startTimestamp,
|
|
13816
|
+
$lte: endTimestamp,
|
|
13817
|
+
};
|
|
13818
|
+
/* ------------ Context Filter ------------ */
|
|
13819
|
+
const { contextFilterState } = filters;
|
|
13820
|
+
const contextConditions = [];
|
|
13821
|
+
Object.keys(contextFilterState).forEach((context) => {
|
|
13822
|
+
const value = contextFilterState[context];
|
|
13823
|
+
if (typeof value === 'boolean') {
|
|
13824
|
+
if (value) {
|
|
13825
|
+
// The entire context is selected
|
|
13826
|
+
contextConditions.push({ context });
|
|
13827
|
+
}
|
|
13828
|
+
}
|
|
13829
|
+
else {
|
|
13830
|
+
// The context has subcontexts
|
|
13831
|
+
const subcontexts = Object.keys(value).filter((subcontext) => { return value[subcontext]; });
|
|
13832
|
+
if (subcontexts.length > 0) {
|
|
13833
|
+
contextConditions.push({
|
|
13834
|
+
context,
|
|
13835
|
+
subcontext: { $in: subcontexts },
|
|
13836
|
+
});
|
|
13837
|
+
}
|
|
13838
|
+
}
|
|
13839
|
+
});
|
|
13840
|
+
if (contextConditions.length > 0) {
|
|
13841
|
+
query.$or = contextConditions;
|
|
13842
|
+
}
|
|
13843
|
+
/* -------------- Tag Filter -------------- */
|
|
13844
|
+
const { tagFilterState } = filters;
|
|
13845
|
+
const selectedTags = Object.keys(tagFilterState).filter((tag) => { return tagFilterState[tag]; });
|
|
13846
|
+
if (selectedTags.length > 0) {
|
|
13847
|
+
query.tags = { $in: selectedTags };
|
|
13848
|
+
}
|
|
13849
|
+
/* --------- Action/Error Filter ---------- */
|
|
13850
|
+
const { actionErrorFilterState } = filters;
|
|
13851
|
+
if (actionErrorFilterState.type) {
|
|
13852
|
+
query.type = actionErrorFilterState.type;
|
|
13853
|
+
}
|
|
13854
|
+
if (actionErrorFilterState.type === 'error' && actionErrorFilterState.errorMessage) {
|
|
13855
|
+
query.errorMessage = { $regex: actionErrorFilterState.errorMessage, $options: 'i' };
|
|
13856
|
+
}
|
|
13857
|
+
if (actionErrorFilterState.type === 'error' && actionErrorFilterState.errorCode) {
|
|
13858
|
+
query.errorCode = { $regex: actionErrorFilterState.errorCode, $options: 'i' };
|
|
13859
|
+
}
|
|
13860
|
+
if (actionErrorFilterState.type === 'action') {
|
|
13861
|
+
const selectedTargets = Object.keys(actionErrorFilterState.target).filter((target) => { return actionErrorFilterState.target[target]; });
|
|
13862
|
+
const selectedActions = Object.keys(actionErrorFilterState.action).filter((action) => { return actionErrorFilterState.action[action]; });
|
|
13863
|
+
if (selectedTargets.length > 0) {
|
|
13864
|
+
query.target = { $in: selectedTargets };
|
|
13865
|
+
}
|
|
13866
|
+
if (selectedActions.length > 0) {
|
|
13867
|
+
query.action = { $in: selectedActions };
|
|
13868
|
+
}
|
|
13869
|
+
}
|
|
13870
|
+
/* ------------ Advanced Filter ----------- */
|
|
13871
|
+
const { advancedFilterState } = filters;
|
|
13872
|
+
if (advancedFilterState.userFirstName) {
|
|
13873
|
+
query.userFirstName = { $regex: advancedFilterState.userFirstName, $options: 'i' };
|
|
13874
|
+
}
|
|
13875
|
+
if (advancedFilterState.userLastName) {
|
|
13876
|
+
query.userLastName = { $regex: advancedFilterState.userLastName, $options: 'i' };
|
|
13877
|
+
}
|
|
13878
|
+
if (advancedFilterState.userEmail) {
|
|
13879
|
+
query.userEmail = { $regex: advancedFilterState.userEmail, $options: 'i' };
|
|
13880
|
+
}
|
|
13881
|
+
if (advancedFilterState.userId) {
|
|
13882
|
+
query.userId = parseInt(advancedFilterState.userId, 10);
|
|
13883
|
+
}
|
|
13884
|
+
const roles = [];
|
|
13885
|
+
if (advancedFilterState.includeLearners) {
|
|
13886
|
+
roles.push({ isLearner: true });
|
|
13887
|
+
}
|
|
13888
|
+
if (advancedFilterState.includeTTMs) {
|
|
13889
|
+
roles.push({ isTTM: true });
|
|
13890
|
+
}
|
|
13891
|
+
if (advancedFilterState.includeAdmins) {
|
|
13892
|
+
roles.push({ isAdmin: true });
|
|
13893
|
+
}
|
|
13894
|
+
if (roles.length > 0) {
|
|
13895
|
+
query.$and = [{ $or: roles }];
|
|
13896
|
+
}
|
|
13897
|
+
if (advancedFilterState.courseId) {
|
|
13898
|
+
query.courseId = parseInt(advancedFilterState.courseId, 10);
|
|
13899
|
+
}
|
|
13900
|
+
if (advancedFilterState.courseName) {
|
|
13901
|
+
query.courseName = { $regex: advancedFilterState.courseName, $options: 'i' };
|
|
13902
|
+
}
|
|
13903
|
+
if (advancedFilterState.isMobile !== undefined) {
|
|
13904
|
+
query['device.isMobile'] = advancedFilterState.isMobile;
|
|
13905
|
+
}
|
|
13906
|
+
if (advancedFilterState.source) {
|
|
13907
|
+
query.source = advancedFilterState.source;
|
|
13908
|
+
}
|
|
13909
|
+
if (advancedFilterState.routePath) {
|
|
13910
|
+
query.routePath = { $regex: advancedFilterState.routePath, $options: 'i' };
|
|
13911
|
+
}
|
|
13912
|
+
if (advancedFilterState.routeTemplate) {
|
|
13913
|
+
query.routeTemplate = { $regex: advancedFilterState.routeTemplate, $options: 'i' };
|
|
13914
|
+
}
|
|
14078
13915
|
// Query for logs
|
|
14079
13916
|
const response = yield _logCollection.findPaged({
|
|
14080
|
-
query
|
|
14081
|
-
|
|
14082
|
-
month,
|
|
14083
|
-
},
|
|
14084
|
-
perPage: 1000,
|
|
13917
|
+
query,
|
|
13918
|
+
perPage: 50,
|
|
14085
13919
|
pageNumber,
|
|
14086
13920
|
});
|
|
14087
13921
|
// Return response
|