dce-reactkit 3.9.4-beta-logreviewer.2 → 3.9.4-beta-logreviewer.4
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 +112 -50
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
- 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/esm/index.js +113 -51
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
- 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/package.json +1 -1
- package/src/components/LogReviewer.tsx +49 -99
- package/src/constants/LOG_REVIEW_GET_LOGS_ROUTE.ts +9 -0
- package/src/server/initServer.ts +104 -40
- 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/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
|
@@ -2574,10 +2574,10 @@ const getHumanReadableDate = (dateOrTimestamp) => {
|
|
|
2574
2574
|
};
|
|
2575
2575
|
|
|
2576
2576
|
/**
|
|
2577
|
-
* Path of the route for
|
|
2577
|
+
* Path of the route for getting logs for log review
|
|
2578
2578
|
* @author Gabe Abrams
|
|
2579
2579
|
*/
|
|
2580
|
-
const
|
|
2580
|
+
const LOG_REVIEW_GET_LOGS_ROUTE = `/admin${ROUTE_PATH_PREFIX}/logs`;
|
|
2581
2581
|
|
|
2582
2582
|
/**
|
|
2583
2583
|
* Source of a log event
|
|
@@ -3585,7 +3585,7 @@ const reducer$7 = (state, action) => {
|
|
|
3585
3585
|
return Object.assign(Object.assign({}, state), { expandedFilterDrawer: undefined });
|
|
3586
3586
|
}
|
|
3587
3587
|
case ActionType$6.ResetFilters: {
|
|
3588
|
-
return Object.assign(Object.assign({}, state), { dateFilterState: action.initDateFilterState, contextFilterState: action.initContextFilterState, tagFilterState: action.initTagFilterState, actionErrorFilterState: action.initActionErrorFilterState, advancedFilterState: action.initAdvancedFilterState });
|
|
3588
|
+
return Object.assign(Object.assign({}, state), { dateFilterState: action.initDateFilterState, contextFilterState: action.initContextFilterState, tagFilterState: action.initTagFilterState, actionErrorFilterState: action.initActionErrorFilterState, advancedFilterState: action.initAdvancedFilterState, numTimesFiltersReset: state.numTimesFiltersReset + 1 });
|
|
3589
3589
|
}
|
|
3590
3590
|
case ActionType$6.UpdateDateFilterState: {
|
|
3591
3591
|
return Object.assign(Object.assign({}, state), { dateFilterState: action.dateFilterState });
|
|
@@ -3608,6 +3608,9 @@ const reducer$7 = (state, action) => {
|
|
|
3608
3608
|
case ActionType$6.DecrementPageNumber: {
|
|
3609
3609
|
return Object.assign(Object.assign({}, state), { pageNumber: state.pageNumber - 1 });
|
|
3610
3610
|
}
|
|
3611
|
+
case ActionType$6.SetHasAnotherPage: {
|
|
3612
|
+
return Object.assign(Object.assign({}, state), { hasAnotherPage: action.hasAnotherPage });
|
|
3613
|
+
}
|
|
3611
3614
|
default: {
|
|
3612
3615
|
return state;
|
|
3613
3616
|
}
|
|
@@ -3734,11 +3737,12 @@ const LogReviewer = (props) => {
|
|
|
3734
3737
|
advancedFilterState: initAdvancedFilterState,
|
|
3735
3738
|
pageNumber: 1,
|
|
3736
3739
|
hasAnotherPage: false,
|
|
3740
|
+
numTimesFiltersReset: 0,
|
|
3737
3741
|
};
|
|
3738
3742
|
// Initialize state
|
|
3739
3743
|
const [state, dispatch] = React.useReducer(reducer$7, initialState);
|
|
3740
3744
|
// Destructure common state
|
|
3741
|
-
const { loading, logs, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, pageNumber, hasAnotherPage, } = state;
|
|
3745
|
+
const { loading, logs, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, pageNumber, hasAnotherPage, numTimesFiltersReset, } = state;
|
|
3742
3746
|
/*------------------------------------------------------------------------*/
|
|
3743
3747
|
/* ------------------------- Component Functions ------------------------ */
|
|
3744
3748
|
/*------------------------------------------------------------------------*/
|
|
@@ -3750,8 +3754,7 @@ const LogReviewer = (props) => {
|
|
|
3750
3754
|
try {
|
|
3751
3755
|
// Prepare filter parameters
|
|
3752
3756
|
const filters = {
|
|
3753
|
-
|
|
3754
|
-
endDate: dateFilterState.endDate,
|
|
3757
|
+
dateFilterState,
|
|
3755
3758
|
contextFilterState,
|
|
3756
3759
|
tagFilterState,
|
|
3757
3760
|
actionErrorFilterState,
|
|
@@ -3759,8 +3762,9 @@ const LogReviewer = (props) => {
|
|
|
3759
3762
|
};
|
|
3760
3763
|
// Send filters to the server
|
|
3761
3764
|
let fetchedLogs = [];
|
|
3765
|
+
// Get logs from server
|
|
3762
3766
|
const response = yield visitServerEndpoint({
|
|
3763
|
-
path:
|
|
3767
|
+
path: LOG_REVIEW_GET_LOGS_ROUTE,
|
|
3764
3768
|
method: 'GET',
|
|
3765
3769
|
params: {
|
|
3766
3770
|
pageNumber,
|
|
@@ -3786,16 +3790,12 @@ const LogReviewer = (props) => {
|
|
|
3786
3790
|
/* ------------------------- Lifecycle Functions ------------------------ */
|
|
3787
3791
|
/*------------------------------------------------------------------------*/
|
|
3788
3792
|
/**
|
|
3789
|
-
* Fetch logs whenever filters
|
|
3793
|
+
* Fetch logs whenever page number changes or filters are reset
|
|
3790
3794
|
*/
|
|
3791
3795
|
React.useEffect(() => {
|
|
3792
3796
|
fetchLogs();
|
|
3793
3797
|
}, [
|
|
3794
|
-
|
|
3795
|
-
contextFilterState,
|
|
3796
|
-
tagFilterState,
|
|
3797
|
-
actionErrorFilterState,
|
|
3798
|
-
advancedFilterState,
|
|
3798
|
+
pageNumber, numTimesFiltersReset,
|
|
3799
3799
|
]);
|
|
3800
3800
|
/*------------------------------------------------------------------------*/
|
|
3801
3801
|
/* ------------------------------- Render ------------------------------- */
|
|
@@ -3889,10 +3889,22 @@ const LogReviewer = (props) => {
|
|
|
3889
3889
|
initDateFilterState,
|
|
3890
3890
|
initTagFilterState,
|
|
3891
3891
|
});
|
|
3892
|
+
dispatch({
|
|
3893
|
+
type: ActionType$6.HideFilterDrawer,
|
|
3894
|
+
});
|
|
3892
3895
|
} },
|
|
3893
3896
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes }),
|
|
3894
3897
|
' ',
|
|
3895
|
-
"Reset")
|
|
3898
|
+
"Reset"),
|
|
3899
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-submit-filters-button", className: "btn btn-primary ms-2", "aria-label": "submit filters", onClick: () => {
|
|
3900
|
+
dispatch({
|
|
3901
|
+
type: ActionType$6.HideFilterDrawer,
|
|
3902
|
+
});
|
|
3903
|
+
fetchLogs();
|
|
3904
|
+
} },
|
|
3905
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faSearch }),
|
|
3906
|
+
' ',
|
|
3907
|
+
"Filter"))));
|
|
3896
3908
|
// Filter drawer
|
|
3897
3909
|
let filterDrawer;
|
|
3898
3910
|
if (expandedFilterDrawer) {
|
|
@@ -4140,7 +4152,7 @@ const LogReviewer = (props) => {
|
|
|
4140
4152
|
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
4153
|
const { value } = e.target;
|
|
4142
4154
|
// Only update if value contains only numbers
|
|
4143
|
-
if (/^\d+$/.test(value)) {
|
|
4155
|
+
if (/^\d+$/.test(value) || value === '') {
|
|
4144
4156
|
advancedFilterState.userId = ((e.target.value)
|
|
4145
4157
|
.trim());
|
|
4146
4158
|
}
|
|
@@ -13790,9 +13802,11 @@ const initServer = (opts) => {
|
|
|
13790
13802
|
/**
|
|
13791
13803
|
* Get filtered logs based on provided filters
|
|
13792
13804
|
* @author Gabe Abrams, Yuen Ler Chow
|
|
13805
|
+
* @param pageNumber the page number to get
|
|
13806
|
+
* @param filters the filters to apply to the logs
|
|
13793
13807
|
* @returns {Log[]} list of logs that match the filters
|
|
13794
13808
|
*/
|
|
13795
|
-
opts.app.get(
|
|
13809
|
+
opts.app.get(LOG_REVIEW_GET_LOGS_ROUTE, genRouteHandler({
|
|
13796
13810
|
paramTypes: {
|
|
13797
13811
|
pageNumber: ParamType$1.Int,
|
|
13798
13812
|
filters: ParamType$1.JSON,
|
|
@@ -13800,6 +13814,7 @@ const initServer = (opts) => {
|
|
|
13800
13814
|
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13801
13815
|
// Get user info
|
|
13802
13816
|
const { pageNumber, userId, isAdmin, filters, } = params;
|
|
13817
|
+
const { dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, } = filters;
|
|
13803
13818
|
// Validate user
|
|
13804
13819
|
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
13805
13820
|
if (!canReview) {
|
|
@@ -13808,58 +13823,85 @@ const initServer = (opts) => {
|
|
|
13808
13823
|
// Build MongoDB query based on filters
|
|
13809
13824
|
const query = {};
|
|
13810
13825
|
/* -------------- Date Filter ------------- */
|
|
13811
|
-
|
|
13826
|
+
// Convert start and end dates from the dateFilterState into timestamps
|
|
13827
|
+
const { startDate, endDate } = dateFilterState;
|
|
13812
13828
|
const startTimestamp = new Date(startDate.year, startDate.month - 1, startDate.day).getTime();
|
|
13813
13829
|
const endTimestamp = new Date(endDate.year, endDate.month - 1, endDate.day + 1).getTime() - 1;
|
|
13830
|
+
// Add a date range condition to the query
|
|
13814
13831
|
query.timestamp = {
|
|
13815
13832
|
$gte: startTimestamp,
|
|
13816
13833
|
$lte: endTimestamp,
|
|
13817
13834
|
};
|
|
13818
13835
|
/* ------------ Context Filter ------------ */
|
|
13819
|
-
|
|
13820
|
-
const
|
|
13836
|
+
// Process context filters to include selected contexts and subcontexts
|
|
13837
|
+
const selectedContexts = [];
|
|
13838
|
+
const selectedSubcontexts = [];
|
|
13839
|
+
// Process each context filter
|
|
13821
13840
|
Object.keys(contextFilterState).forEach((context) => {
|
|
13822
13841
|
const value = contextFilterState[context];
|
|
13823
13842
|
if (typeof value === 'boolean') {
|
|
13824
13843
|
if (value) {
|
|
13825
|
-
|
|
13826
|
-
contextConditions.push({ context });
|
|
13844
|
+
selectedContexts.push(context);
|
|
13827
13845
|
}
|
|
13828
13846
|
}
|
|
13829
13847
|
else {
|
|
13830
|
-
//
|
|
13831
|
-
const
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13848
|
+
// At least one subcontext is selected
|
|
13849
|
+
const atLeastOneSubcontextSelected = (Object.values(value)
|
|
13850
|
+
.some((subcontextValue) => {
|
|
13851
|
+
return subcontextValue;
|
|
13852
|
+
}));
|
|
13853
|
+
if (atLeastOneSubcontextSelected) {
|
|
13854
|
+
selectedContexts.push(context);
|
|
13837
13855
|
}
|
|
13856
|
+
// Add all selected subcontexts
|
|
13857
|
+
Object.keys(value).forEach((subcontext) => {
|
|
13858
|
+
if (value[subcontext]) {
|
|
13859
|
+
selectedSubcontexts.push(subcontext);
|
|
13860
|
+
}
|
|
13861
|
+
});
|
|
13838
13862
|
}
|
|
13839
13863
|
});
|
|
13840
|
-
if
|
|
13841
|
-
|
|
13864
|
+
// Add context and subcontext conditions to the query if any are selected
|
|
13865
|
+
if (selectedContexts.length > 0) {
|
|
13866
|
+
query.context = { $in: selectedContexts };
|
|
13867
|
+
}
|
|
13868
|
+
if (selectedSubcontexts.length > 0) {
|
|
13869
|
+
query.subcontext = { $in: selectedSubcontexts };
|
|
13842
13870
|
}
|
|
13843
13871
|
/* -------------- Tag Filter -------------- */
|
|
13844
|
-
const { tagFilterState } = filters;
|
|
13845
13872
|
const selectedTags = Object.keys(tagFilterState).filter((tag) => { return tagFilterState[tag]; });
|
|
13846
13873
|
if (selectedTags.length > 0) {
|
|
13847
13874
|
query.tags = { $in: selectedTags };
|
|
13848
13875
|
}
|
|
13849
13876
|
/* --------- Action/Error Filter ---------- */
|
|
13850
|
-
const { actionErrorFilterState } = filters;
|
|
13851
13877
|
if (actionErrorFilterState.type) {
|
|
13852
13878
|
query.type = actionErrorFilterState.type;
|
|
13853
13879
|
}
|
|
13854
|
-
if (actionErrorFilterState.type ===
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13880
|
+
if (actionErrorFilterState.type === LogType$1.Error) {
|
|
13881
|
+
if (actionErrorFilterState.errorMessage) {
|
|
13882
|
+
// Add error message to the query.
|
|
13883
|
+
// $i is used for case-insensitive search, and $regex is used for partial matching
|
|
13884
|
+
query.errorMessage = {
|
|
13885
|
+
$regex: actionErrorFilterState.errorMessage,
|
|
13886
|
+
$options: 'i',
|
|
13887
|
+
};
|
|
13888
|
+
}
|
|
13889
|
+
if (actionErrorFilterState.errorCode) {
|
|
13890
|
+
query.errorCode = {
|
|
13891
|
+
$regex: actionErrorFilterState.errorCode,
|
|
13892
|
+
$options: 'i',
|
|
13893
|
+
};
|
|
13894
|
+
}
|
|
13859
13895
|
}
|
|
13860
|
-
if (actionErrorFilterState.type ===
|
|
13861
|
-
const selectedTargets = Object.keys(actionErrorFilterState.target)
|
|
13862
|
-
|
|
13896
|
+
if (actionErrorFilterState.type === LogType$1.Action) {
|
|
13897
|
+
const selectedTargets = (Object.keys(actionErrorFilterState.target)
|
|
13898
|
+
.filter((target) => {
|
|
13899
|
+
return actionErrorFilterState.target[target];
|
|
13900
|
+
}));
|
|
13901
|
+
const selectedActions = (Object.keys(actionErrorFilterState.action)
|
|
13902
|
+
.filter((action) => {
|
|
13903
|
+
return actionErrorFilterState.action[action];
|
|
13904
|
+
}));
|
|
13863
13905
|
if (selectedTargets.length > 0) {
|
|
13864
13906
|
query.target = { $in: selectedTargets };
|
|
13865
13907
|
}
|
|
@@ -13868,18 +13910,26 @@ const initServer = (opts) => {
|
|
|
13868
13910
|
}
|
|
13869
13911
|
}
|
|
13870
13912
|
/* ------------ Advanced Filter ----------- */
|
|
13871
|
-
const { advancedFilterState } = filters;
|
|
13872
13913
|
if (advancedFilterState.userFirstName) {
|
|
13873
|
-
query.userFirstName = {
|
|
13914
|
+
query.userFirstName = {
|
|
13915
|
+
$regex: advancedFilterState.userFirstName,
|
|
13916
|
+
$options: 'i',
|
|
13917
|
+
};
|
|
13874
13918
|
}
|
|
13875
13919
|
if (advancedFilterState.userLastName) {
|
|
13876
|
-
query.userLastName = {
|
|
13920
|
+
query.userLastName = {
|
|
13921
|
+
$regex: advancedFilterState.userLastName,
|
|
13922
|
+
$options: 'i',
|
|
13923
|
+
};
|
|
13877
13924
|
}
|
|
13878
13925
|
if (advancedFilterState.userEmail) {
|
|
13879
|
-
query.userEmail = {
|
|
13926
|
+
query.userEmail = {
|
|
13927
|
+
$regex: advancedFilterState.userEmail,
|
|
13928
|
+
$options: 'i',
|
|
13929
|
+
};
|
|
13880
13930
|
}
|
|
13881
13931
|
if (advancedFilterState.userId) {
|
|
13882
|
-
query.userId = parseInt(advancedFilterState.userId, 10);
|
|
13932
|
+
query.userId = Number.parseInt(advancedFilterState.userId, 10);
|
|
13883
13933
|
}
|
|
13884
13934
|
const roles = [];
|
|
13885
13935
|
if (advancedFilterState.includeLearners) {
|
|
@@ -13891,26 +13941,38 @@ const initServer = (opts) => {
|
|
|
13891
13941
|
if (advancedFilterState.includeAdmins) {
|
|
13892
13942
|
roles.push({ isAdmin: true });
|
|
13893
13943
|
}
|
|
13944
|
+
// If any roles are selected, add them to the query
|
|
13894
13945
|
if (roles.length > 0) {
|
|
13946
|
+
// The $or operator is used to match any of the roles
|
|
13947
|
+
// The $and operator is to ensure that other conditions in the query are met
|
|
13895
13948
|
query.$and = [{ $or: roles }];
|
|
13896
13949
|
}
|
|
13897
13950
|
if (advancedFilterState.courseId) {
|
|
13898
|
-
query.courseId = parseInt(advancedFilterState.courseId, 10);
|
|
13951
|
+
query.courseId = Number.parseInt(advancedFilterState.courseId, 10);
|
|
13899
13952
|
}
|
|
13900
13953
|
if (advancedFilterState.courseName) {
|
|
13901
|
-
query.courseName = {
|
|
13954
|
+
query.courseName = {
|
|
13955
|
+
$regex: advancedFilterState.courseName,
|
|
13956
|
+
$options: 'i',
|
|
13957
|
+
};
|
|
13902
13958
|
}
|
|
13903
13959
|
if (advancedFilterState.isMobile !== undefined) {
|
|
13904
|
-
query['device.isMobile'] = advancedFilterState.isMobile;
|
|
13960
|
+
query['device.isMobile'] = Boolean(advancedFilterState.isMobile);
|
|
13905
13961
|
}
|
|
13906
13962
|
if (advancedFilterState.source) {
|
|
13907
13963
|
query.source = advancedFilterState.source;
|
|
13908
13964
|
}
|
|
13909
13965
|
if (advancedFilterState.routePath) {
|
|
13910
|
-
query.routePath = {
|
|
13966
|
+
query.routePath = {
|
|
13967
|
+
$regex: advancedFilterState.routePath,
|
|
13968
|
+
$options: 'i',
|
|
13969
|
+
};
|
|
13911
13970
|
}
|
|
13912
13971
|
if (advancedFilterState.routeTemplate) {
|
|
13913
|
-
query.routeTemplate = {
|
|
13972
|
+
query.routeTemplate = {
|
|
13973
|
+
$regex: advancedFilterState.routeTemplate,
|
|
13974
|
+
$options: 'i',
|
|
13975
|
+
};
|
|
13914
13976
|
}
|
|
13915
13977
|
// Query for logs
|
|
13916
13978
|
const response = yield _logCollection.findPaged({
|