dce-reactkit 3.9.4-beta-logreviewer.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.
Files changed (31) hide show
  1. package/dist/cjs/index.js +105 -47
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
  4. package/dist/cjs/types/types/LogReviewerFilterState/ActionErrorFilterState.d.ts +13 -0
  5. package/dist/cjs/types/types/LogReviewerFilterState/AdvancedFilterState.d.ts +17 -0
  6. package/dist/cjs/types/types/LogReviewerFilterState/ContextFilterState.d.ts +6 -0
  7. package/dist/cjs/types/types/LogReviewerFilterState/DateFilterState.d.ts +13 -0
  8. package/dist/cjs/types/types/LogReviewerFilterState/TagFilterState.d.ts +4 -0
  9. package/dist/cjs/types/types/LogReviewerFilterState/index.d.ts +17 -0
  10. package/dist/esm/index.js +106 -48
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/types/constants/LOG_REVIEW_GET_LOGS_ROUTE.d.ts +6 -0
  13. package/dist/esm/types/types/LogReviewerFilterState/ActionErrorFilterState.d.ts +13 -0
  14. package/dist/esm/types/types/LogReviewerFilterState/AdvancedFilterState.d.ts +17 -0
  15. package/dist/esm/types/types/LogReviewerFilterState/ContextFilterState.d.ts +6 -0
  16. package/dist/esm/types/types/LogReviewerFilterState/DateFilterState.d.ts +13 -0
  17. package/dist/esm/types/types/LogReviewerFilterState/TagFilterState.d.ts +4 -0
  18. package/dist/esm/types/types/LogReviewerFilterState/index.d.ts +17 -0
  19. package/package.json +1 -1
  20. package/src/components/LogReviewer.tsx +40 -98
  21. package/src/constants/LOG_REVIEW_GET_LOGS_ROUTE.ts +9 -0
  22. package/src/server/initServer.ts +104 -40
  23. package/src/types/LogReviewerFilterState/ActionErrorFilterState.ts +21 -0
  24. package/src/types/LogReviewerFilterState/AdvancedFilterState.ts +33 -0
  25. package/src/types/LogReviewerFilterState/ContextFilterState.ts +13 -0
  26. package/src/types/LogReviewerFilterState/DateFilterState.ts +23 -0
  27. package/src/types/LogReviewerFilterState/TagFilterState.ts +6 -0
  28. package/src/types/LogReviewerFilterState/index.ts +24 -0
  29. package/dist/cjs/types/constants/LOG_REVIEW_ROUTE_PATH_PREFIX.d.ts +0 -6
  30. package/dist/esm/types/constants/LOG_REVIEW_ROUTE_PATH_PREFIX.d.ts +0 -6
  31. 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 storing client-side logs
2577
+ * Path of the route for getting logs for log review
2578
2578
  * @author Gabe Abrams
2579
2579
  */
2580
- const LOG_REVIEW_ROUTE_PATH_PREFIX = `/admin${ROUTE_PATH_PREFIX}/logs`;
2580
+ const LOG_REVIEW_GET_LOGS_ROUTE = `/admin${ROUTE_PATH_PREFIX}/logs`;
2581
2581
 
2582
2582
  /**
2583
2583
  * Source of a log event
@@ -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
  }
@@ -3750,8 +3753,7 @@ const LogReviewer = (props) => {
3750
3753
  try {
3751
3754
  // Prepare filter parameters
3752
3755
  const filters = {
3753
- startDate: dateFilterState.startDate,
3754
- endDate: dateFilterState.endDate,
3756
+ dateFilterState,
3755
3757
  contextFilterState,
3756
3758
  tagFilterState,
3757
3759
  actionErrorFilterState,
@@ -3759,8 +3761,9 @@ const LogReviewer = (props) => {
3759
3761
  };
3760
3762
  // Send filters to the server
3761
3763
  let fetchedLogs = [];
3764
+ // Get logs from server
3762
3765
  const response = yield visitServerEndpoint({
3763
- path: `${LOG_REVIEW_ROUTE_PATH_PREFIX}/logs`,
3766
+ path: LOG_REVIEW_GET_LOGS_ROUTE,
3764
3767
  method: 'GET',
3765
3768
  params: {
3766
3769
  pageNumber,
@@ -3786,16 +3789,12 @@ const LogReviewer = (props) => {
3786
3789
  /* ------------------------- Lifecycle Functions ------------------------ */
3787
3790
  /*------------------------------------------------------------------------*/
3788
3791
  /**
3789
- * Fetch logs whenever filters change
3792
+ * Fetch logs whenever page number changes
3790
3793
  */
3791
3794
  React.useEffect(() => {
3792
3795
  fetchLogs();
3793
3796
  }, [
3794
- dateFilterState,
3795
- contextFilterState,
3796
- tagFilterState,
3797
- actionErrorFilterState,
3798
- advancedFilterState,
3797
+ pageNumber,
3799
3798
  ]);
3800
3799
  /*------------------------------------------------------------------------*/
3801
3800
  /* ------------------------------- Render ------------------------------- */
@@ -3892,7 +3891,16 @@ const LogReviewer = (props) => {
3892
3891
  } },
3893
3892
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes }),
3894
3893
  ' ',
3895
- "Reset"))));
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"))));
3896
3904
  // Filter drawer
3897
3905
  let filterDrawer;
3898
3906
  if (expandedFilterDrawer) {
@@ -13790,9 +13798,11 @@ const initServer = (opts) => {
13790
13798
  /**
13791
13799
  * Get filtered logs based on provided filters
13792
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
13793
13803
  * @returns {Log[]} list of logs that match the filters
13794
13804
  */
13795
- opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/logs`, genRouteHandler({
13805
+ opts.app.get(`${LOG_REVIEW_GET_LOGS_ROUTE}`, genRouteHandler({
13796
13806
  paramTypes: {
13797
13807
  pageNumber: ParamType$1.Int,
13798
13808
  filters: ParamType$1.JSON,
@@ -13800,6 +13810,7 @@ const initServer = (opts) => {
13800
13810
  handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
13801
13811
  // Get user info
13802
13812
  const { pageNumber, userId, isAdmin, filters, } = params;
13813
+ const { dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, } = filters;
13803
13814
  // Validate user
13804
13815
  const canReview = yield canReviewLogs(userId, isAdmin);
13805
13816
  if (!canReview) {
@@ -13808,58 +13819,85 @@ const initServer = (opts) => {
13808
13819
  // Build MongoDB query based on filters
13809
13820
  const query = {};
13810
13821
  /* -------------- Date Filter ------------- */
13811
- const { startDate, endDate } = filters.dateFilterState;
13822
+ // Convert start and end dates from the dateFilterState into timestamps
13823
+ const { startDate, endDate } = dateFilterState;
13812
13824
  const startTimestamp = new Date(startDate.year, startDate.month - 1, startDate.day).getTime();
13813
13825
  const endTimestamp = new Date(endDate.year, endDate.month - 1, endDate.day + 1).getTime() - 1;
13826
+ // Add a date range condition to the query
13814
13827
  query.timestamp = {
13815
13828
  $gte: startTimestamp,
13816
13829
  $lte: endTimestamp,
13817
13830
  };
13818
13831
  /* ------------ Context Filter ------------ */
13819
- const { contextFilterState } = filters;
13820
- const contextConditions = [];
13832
+ // Process context filters to include selected contexts and subcontexts
13833
+ const selectedContexts = [];
13834
+ const selectedSubcontexts = [];
13835
+ // Process each context filter
13821
13836
  Object.keys(contextFilterState).forEach((context) => {
13822
13837
  const value = contextFilterState[context];
13823
13838
  if (typeof value === 'boolean') {
13824
13839
  if (value) {
13825
- // The entire context is selected
13826
- contextConditions.push({ context });
13840
+ selectedContexts.push(context);
13827
13841
  }
13828
13842
  }
13829
13843
  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
- });
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);
13837
13851
  }
13852
+ // Add all selected subcontexts
13853
+ Object.keys(value).forEach((subcontext) => {
13854
+ if (value[subcontext]) {
13855
+ selectedSubcontexts.push(subcontext);
13856
+ }
13857
+ });
13838
13858
  }
13839
13859
  });
13840
- if (contextConditions.length > 0) {
13841
- query.$or = contextConditions;
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 };
13842
13866
  }
13843
13867
  /* -------------- Tag Filter -------------- */
13844
- const { tagFilterState } = filters;
13845
13868
  const selectedTags = Object.keys(tagFilterState).filter((tag) => { return tagFilterState[tag]; });
13846
13869
  if (selectedTags.length > 0) {
13847
13870
  query.tags = { $in: selectedTags };
13848
13871
  }
13849
13872
  /* --------- Action/Error Filter ---------- */
13850
- const { actionErrorFilterState } = filters;
13851
13873
  if (actionErrorFilterState.type) {
13852
13874
  query.type = actionErrorFilterState.type;
13853
13875
  }
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' };
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
+ }
13859
13891
  }
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]; });
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
+ }));
13863
13901
  if (selectedTargets.length > 0) {
13864
13902
  query.target = { $in: selectedTargets };
13865
13903
  }
@@ -13868,18 +13906,26 @@ const initServer = (opts) => {
13868
13906
  }
13869
13907
  }
13870
13908
  /* ------------ Advanced Filter ----------- */
13871
- const { advancedFilterState } = filters;
13872
13909
  if (advancedFilterState.userFirstName) {
13873
- query.userFirstName = { $regex: advancedFilterState.userFirstName, $options: 'i' };
13910
+ query.userFirstName = {
13911
+ $regex: advancedFilterState.userFirstName,
13912
+ $options: 'i',
13913
+ };
13874
13914
  }
13875
13915
  if (advancedFilterState.userLastName) {
13876
- query.userLastName = { $regex: advancedFilterState.userLastName, $options: 'i' };
13916
+ query.userLastName = {
13917
+ $regex: advancedFilterState.userLastName,
13918
+ $options: 'i',
13919
+ };
13877
13920
  }
13878
13921
  if (advancedFilterState.userEmail) {
13879
- query.userEmail = { $regex: advancedFilterState.userEmail, $options: 'i' };
13922
+ query.userEmail = {
13923
+ $regex: advancedFilterState.userEmail,
13924
+ $options: 'i',
13925
+ };
13880
13926
  }
13881
13927
  if (advancedFilterState.userId) {
13882
- query.userId = parseInt(advancedFilterState.userId, 10);
13928
+ query.userId = Number.parseInt(advancedFilterState.userId, 10);
13883
13929
  }
13884
13930
  const roles = [];
13885
13931
  if (advancedFilterState.includeLearners) {
@@ -13891,26 +13937,38 @@ const initServer = (opts) => {
13891
13937
  if (advancedFilterState.includeAdmins) {
13892
13938
  roles.push({ isAdmin: true });
13893
13939
  }
13940
+ // If any roles are selected, add them to the query
13894
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
13895
13944
  query.$and = [{ $or: roles }];
13896
13945
  }
13897
13946
  if (advancedFilterState.courseId) {
13898
- query.courseId = parseInt(advancedFilterState.courseId, 10);
13947
+ query.courseId = Number.parseInt(advancedFilterState.courseId, 10);
13899
13948
  }
13900
13949
  if (advancedFilterState.courseName) {
13901
- query.courseName = { $regex: advancedFilterState.courseName, $options: 'i' };
13950
+ query.courseName = {
13951
+ $regex: advancedFilterState.courseName,
13952
+ $options: 'i',
13953
+ };
13902
13954
  }
13903
13955
  if (advancedFilterState.isMobile !== undefined) {
13904
- query['device.isMobile'] = advancedFilterState.isMobile;
13956
+ query['device.isMobile'] = Boolean(advancedFilterState.isMobile);
13905
13957
  }
13906
13958
  if (advancedFilterState.source) {
13907
13959
  query.source = advancedFilterState.source;
13908
13960
  }
13909
13961
  if (advancedFilterState.routePath) {
13910
- query.routePath = { $regex: advancedFilterState.routePath, $options: 'i' };
13962
+ query.routePath = {
13963
+ $regex: advancedFilterState.routePath,
13964
+ $options: 'i',
13965
+ };
13911
13966
  }
13912
13967
  if (advancedFilterState.routeTemplate) {
13913
- query.routeTemplate = { $regex: advancedFilterState.routeTemplate, $options: 'i' };
13968
+ query.routeTemplate = {
13969
+ $regex: advancedFilterState.routeTemplate,
13970
+ $options: 'i',
13971
+ };
13914
13972
  }
13915
13973
  // Query for logs
13916
13974
  const response = yield _logCollection.findPaged({