dce-reactkit 3.2.2-beta.2 → 3.2.2-beta.20
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 +338 -186
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/ButtonInputGroup.d.ts +1 -0
- package/dist/cjs/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts +2 -1
- package/dist/cjs/types/server/initServer.d.ts +1 -1
- package/dist/cjs/types/types/LogBuiltInMetadata.d.ts +1 -1
- package/dist/esm/index.js +338 -187
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/ButtonInputGroup.d.ts +1 -0
- package/dist/esm/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/types/server/initServer.d.ts +1 -1
- package/dist/esm/types/types/LogBuiltInMetadata.d.ts +1 -1
- package/dist/index.d.ts +12 -3
- package/package.json +1 -1
- package/src/components/ButtonInputGroup.tsx +4 -1
- package/src/components/IntelliTable.tsx +4 -4
- package/src/components/ItemPicker/index.tsx +4 -0
- package/src/components/LogReviewer.tsx +280 -130
- package/src/components/SimpleDateChooser.tsx +20 -7
- package/src/constants/LOG_REVIEW_STATUS_ROUTE.ts +1 -1
- package/src/helpers/genRouteHandler.ts +1 -1
- package/src/helpers/logClientEvent.tsx +6 -1
- package/src/index.ts +2 -0
- package/src/server/initServer.ts +93 -73
- package/src/types/LogBuiltInMetadata.ts +5 -5
package/dist/cjs/index.js
CHANGED
|
@@ -519,17 +519,29 @@ const LOG_ROUTE_PATH = `${ROUTE_PATH_PREFIX}/log`;
|
|
|
519
519
|
const LogBuiltInMetadata = {
|
|
520
520
|
// Contexts
|
|
521
521
|
Context: {
|
|
522
|
-
Uncategorized: '
|
|
523
|
-
ServerRenderedErrorPage: '
|
|
524
|
-
ServerEndpointError: '
|
|
525
|
-
ClientFatalError: '
|
|
522
|
+
Uncategorized: 'Uncategorized',
|
|
523
|
+
ServerRenderedErrorPage: 'ServerRenderedErrorPage',
|
|
524
|
+
ServerEndpointError: 'ServerEndpointError',
|
|
525
|
+
ClientFatalError: 'ClientFatalError',
|
|
526
526
|
},
|
|
527
527
|
// Targets
|
|
528
528
|
Target: {
|
|
529
|
-
|
|
529
|
+
NoTarget: 'NoTarget',
|
|
530
530
|
},
|
|
531
531
|
};
|
|
532
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Allowed log levels
|
|
535
|
+
* @author Gabe Abrams
|
|
536
|
+
*/
|
|
537
|
+
var LogLevel;
|
|
538
|
+
(function (LogLevel) {
|
|
539
|
+
LogLevel["Warn"] = "Warn";
|
|
540
|
+
LogLevel["Info"] = "Info";
|
|
541
|
+
LogLevel["Debug"] = "Debug";
|
|
542
|
+
})(LogLevel || (LogLevel = {}));
|
|
543
|
+
var LogLevel$1 = LogLevel;
|
|
544
|
+
|
|
533
545
|
// Keep track of whether or not session expiry has already been handled
|
|
534
546
|
let sessionAlreadyExpired = false;
|
|
535
547
|
/*------------------------------------------------------------------------*/
|
|
@@ -648,7 +660,7 @@ const visitServerEndpoint = (opts) => __awaiter(void 0, void 0, void 0, function
|
|
|
648
660
|
* @author Gabe Abrams
|
|
649
661
|
*/
|
|
650
662
|
const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
651
|
-
var _a, _b, _c, _d, _e, _f;
|
|
663
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
652
664
|
return visitServerEndpoint({
|
|
653
665
|
path: LOG_ROUTE_PATH,
|
|
654
666
|
method: 'POST',
|
|
@@ -657,8 +669,9 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
657
669
|
? opts.context
|
|
658
670
|
: ((_b = ((_a = opts.context) !== null && _a !== void 0 ? _a : {})._) !== null && _b !== void 0 ? _b : LogBuiltInMetadata.Context.Uncategorized)),
|
|
659
671
|
subcontext: ((_c = opts.subcontext) !== null && _c !== void 0 ? _c : LogBuiltInMetadata.Context.Uncategorized),
|
|
660
|
-
|
|
661
|
-
|
|
672
|
+
level: ((_d = opts.level) !== null && _d !== void 0 ? _d : LogLevel$1.Info),
|
|
673
|
+
tags: JSON.stringify((_e = opts.tags) !== null && _e !== void 0 ? _e : []),
|
|
674
|
+
metadata: JSON.stringify((_f = opts.metadata) !== null && _f !== void 0 ? _f : {}),
|
|
662
675
|
errorMessage: (opts.error
|
|
663
676
|
? opts.error.message
|
|
664
677
|
: undefined),
|
|
@@ -669,7 +682,7 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
669
682
|
? opts.error.stack
|
|
670
683
|
: undefined),
|
|
671
684
|
target: (opts.action
|
|
672
|
-
? ((
|
|
685
|
+
? ((_g = opts.target) !== null && _g !== void 0 ? _g : LogBuiltInMetadata.Target.NoTarget)
|
|
673
686
|
: undefined),
|
|
674
687
|
action: (opts.action
|
|
675
688
|
? opts.action
|
|
@@ -1175,14 +1188,14 @@ const ButtonInputGroup = (props) => {
|
|
|
1175
1188
|
/*------------------------------------------------------------------------*/
|
|
1176
1189
|
/* -------------- Props ------------- */
|
|
1177
1190
|
// Destructure all props
|
|
1178
|
-
const { label, minLabelWidth, children, } = props;
|
|
1191
|
+
const { label, minLabelWidth, children, className, } = props;
|
|
1179
1192
|
/*------------------------------------------------------------------------*/
|
|
1180
1193
|
/* Render */
|
|
1181
1194
|
/*------------------------------------------------------------------------*/
|
|
1182
1195
|
/*----------------------------------------*/
|
|
1183
1196
|
/* Main UI */
|
|
1184
1197
|
/*----------------------------------------*/
|
|
1185
|
-
return (React__default["default"].createElement("div", { className:
|
|
1198
|
+
return (React__default["default"].createElement("div", { className: `input-group ${className !== null && className !== void 0 ? className : ''}` },
|
|
1186
1199
|
React__default["default"].createElement("div", { className: "input-group-prepend d-flex w-100" },
|
|
1187
1200
|
React__default["default"].createElement("span", { className: "input-group-text", style: {
|
|
1188
1201
|
minWidth: (minLabelWidth !== null && minLabelWidth !== void 0 ? minLabelWidth : undefined),
|
|
@@ -1352,12 +1365,25 @@ const SimpleDateChooser = (props) => {
|
|
|
1352
1365
|
// Figure out which days are allowed
|
|
1353
1366
|
const days = [];
|
|
1354
1367
|
const numDaysInMonth = (new Date(year, month, 0)).getDate();
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1368
|
+
if (chooseFromPast) {
|
|
1369
|
+
// Past selection
|
|
1370
|
+
const numDaysToAdd = ((month === today.month)
|
|
1371
|
+
? today.day // Current month, only add up to today
|
|
1372
|
+
: numDaysInMonth // Past month, add all days
|
|
1373
|
+
);
|
|
1374
|
+
for (let day = 1; day <= numDaysToAdd; day++) {
|
|
1375
|
+
days.push(day);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
// Future selection: add all remaining days of the month
|
|
1380
|
+
const firstDay = (month === today.month
|
|
1381
|
+
? today.day // Current month: start at current date
|
|
1382
|
+
: 1 // Future month: start at beginning of month
|
|
1383
|
+
);
|
|
1384
|
+
for (let day = firstDay; day <= numDaysInMonth; day++) {
|
|
1385
|
+
days.push(day);
|
|
1386
|
+
}
|
|
1361
1387
|
}
|
|
1362
1388
|
choices.push({
|
|
1363
1389
|
choiceName: `${monthName} ${year}`,
|
|
@@ -2057,7 +2083,7 @@ const ItemPicker = (props) => {
|
|
|
2057
2083
|
/*------------------------------------------------------------------------*/
|
|
2058
2084
|
/* -------------- Props ------------- */
|
|
2059
2085
|
// Destructure all props
|
|
2060
|
-
const { title, items, onChanged, } = props;
|
|
2086
|
+
const { title, items, onChanged, noBottomMargin, } = props;
|
|
2061
2087
|
/*------------------------------------------------------------------------*/
|
|
2062
2088
|
/* Component Functions */
|
|
2063
2089
|
/*------------------------------------------------------------------------*/
|
|
@@ -2067,7 +2093,7 @@ const ItemPicker = (props) => {
|
|
|
2067
2093
|
/*----------------------------------------*/
|
|
2068
2094
|
/* Main UI */
|
|
2069
2095
|
/*----------------------------------------*/
|
|
2070
|
-
return (React__default["default"].createElement(TabBox, { title: title },
|
|
2096
|
+
return (React__default["default"].createElement(TabBox, { title: title, noBottomMargin: noBottomMargin },
|
|
2071
2097
|
React__default["default"].createElement("div", { style: { overflowX: 'auto' } },
|
|
2072
2098
|
React__default["default"].createElement(NestableItemList, { items: items, onChanged: onChanged }))));
|
|
2073
2099
|
};
|
|
@@ -2384,9 +2410,9 @@ const IntelliTable = (props) => {
|
|
|
2384
2410
|
// Create the cell UI
|
|
2385
2411
|
return (React__default["default"].createElement("th", { key: column.param, scope: "col", id: `IntelliTable-${id}-header-${column.param}` },
|
|
2386
2412
|
React__default["default"].createElement("div", { className: "d-flex align-items-center justify-content-center flex-row h-100" },
|
|
2387
|
-
React__default["default"].createElement("
|
|
2413
|
+
React__default["default"].createElement("span", { className: "text-nowrap" }, column.title),
|
|
2388
2414
|
React__default["default"].createElement("div", null,
|
|
2389
|
-
React__default["default"].createElement("button", { type: "button", className: "btn btn-light", "aria-label": sortButtonAriaLabel, onClick: () => {
|
|
2415
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-light btn-sm ms-1", "aria-label": sortButtonAriaLabel, onClick: () => {
|
|
2390
2416
|
dispatch({
|
|
2391
2417
|
type: ActionType$1.ToggleSortColumn,
|
|
2392
2418
|
param: column.param,
|
|
@@ -2534,7 +2560,7 @@ const IntelliTable = (props) => {
|
|
|
2534
2560
|
React__default["default"].createElement("h3", { className: "m-0" }, title),
|
|
2535
2561
|
React__default["default"].createElement("div", { className: "flex-grow-1 text-end" },
|
|
2536
2562
|
React__default["default"].createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: `${title}.csv`, csv: csv }),
|
|
2537
|
-
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary", "aria-label": `show panel for customizing which columns show in table ${title}`, id: `IntelliTable-${id}-show-column-customization-modal`, onClick: () => {
|
|
2563
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary ms-2", "aria-label": `show panel for customizing which columns show in table ${title}`, id: `IntelliTable-${id}-show-column-customization-modal`, onClick: () => {
|
|
2538
2564
|
dispatch({
|
|
2539
2565
|
type: ActionType$1.ToggleColVisCusModalVisibility,
|
|
2540
2566
|
});
|
|
@@ -2598,6 +2624,11 @@ const style = `
|
|
|
2598
2624
|
border: 0.05rem solid black;
|
|
2599
2625
|
border-radius: 0.5rem;
|
|
2600
2626
|
overflow: hidden;
|
|
2627
|
+
padding: 0.7rem;
|
|
2628
|
+
|
|
2629
|
+
/* Solid background */
|
|
2630
|
+
background-color: white;
|
|
2631
|
+
color: black;
|
|
2601
2632
|
|
|
2602
2633
|
/* Place contents in flex column */
|
|
2603
2634
|
flex-direction: column;
|
|
@@ -2624,6 +2655,27 @@ const style = `
|
|
|
2624
2655
|
/* Vertical scroll */
|
|
2625
2656
|
overflow-y: auto;
|
|
2626
2657
|
}
|
|
2658
|
+
|
|
2659
|
+
.LogReviewer-header-close-button {
|
|
2660
|
+
border: 0 !important;
|
|
2661
|
+
background-color: transparent !important;
|
|
2662
|
+
padding-top: 0 !important;
|
|
2663
|
+
padding-bottom: 0 !important;
|
|
2664
|
+
padding-right: 1em !important;
|
|
2665
|
+
margin: 0 !important;
|
|
2666
|
+
color: #444 !important;
|
|
2667
|
+
|
|
2668
|
+
right: 0 !important;
|
|
2669
|
+
position: absolute !important;
|
|
2670
|
+
}
|
|
2671
|
+
.LogReviewer-header-close-button:hover {
|
|
2672
|
+
border: 0 !important;
|
|
2673
|
+
background-color: transparent !important;
|
|
2674
|
+
padding-top: 0 !important;
|
|
2675
|
+
padding-bottom: 0 !important;
|
|
2676
|
+
margin: 0 !important;
|
|
2677
|
+
color: #000 !important;
|
|
2678
|
+
}
|
|
2627
2679
|
`;
|
|
2628
2680
|
/*------------------------------------------------------------------------*/
|
|
2629
2681
|
/* Static Functions */
|
|
@@ -2643,7 +2695,7 @@ const genHumanReadableName = (machineReadableName) => {
|
|
|
2643
2695
|
// Uppercase! Add a space before
|
|
2644
2696
|
humanReadableName += ' ';
|
|
2645
2697
|
}
|
|
2646
|
-
humanReadableName +=
|
|
2698
|
+
humanReadableName += char;
|
|
2647
2699
|
});
|
|
2648
2700
|
// Trim and return
|
|
2649
2701
|
return humanReadableName.trim();
|
|
@@ -2705,7 +2757,19 @@ const reducer = (state, action) => {
|
|
|
2705
2757
|
return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
|
|
2706
2758
|
}
|
|
2707
2759
|
case ActionType.UpdateTagFilterState: {
|
|
2708
|
-
|
|
2760
|
+
const { tagFilterState } = action;
|
|
2761
|
+
// Select all if every tag is deselected
|
|
2762
|
+
const numTagsSelected = (Object.values(tagFilterState)
|
|
2763
|
+
.filter((isSelected) => {
|
|
2764
|
+
return isSelected;
|
|
2765
|
+
})
|
|
2766
|
+
.length);
|
|
2767
|
+
if (numTagsSelected === 0) {
|
|
2768
|
+
Object.keys(tagFilterState).forEach((tag) => {
|
|
2769
|
+
tagFilterState[tag] = true;
|
|
2770
|
+
});
|
|
2771
|
+
}
|
|
2772
|
+
return Object.assign(Object.assign({}, state), { tagFilterState });
|
|
2709
2773
|
}
|
|
2710
2774
|
case ActionType.UpdateActionErrorFilterState: {
|
|
2711
2775
|
return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
|
|
@@ -2725,10 +2789,33 @@ const LogReviewer = (props) => {
|
|
|
2725
2789
|
/*------------------------------------------------------------------------*/
|
|
2726
2790
|
/* Setup */
|
|
2727
2791
|
/*------------------------------------------------------------------------*/
|
|
2728
|
-
var _a, _b, _c, _d, _e;
|
|
2792
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
2729
2793
|
/* -------------- Props ------------- */
|
|
2730
2794
|
// Destructure props
|
|
2731
2795
|
const { LogMetadata, onClose, } = props;
|
|
2796
|
+
// Add built-in LogMetadata
|
|
2797
|
+
// > Add "uncategorized" subcontext to each context
|
|
2798
|
+
Object.keys((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {}).forEach((context) => {
|
|
2799
|
+
if (LogMetadata.Context
|
|
2800
|
+
// Context has children already
|
|
2801
|
+
&& typeof LogMetadata.Context[context] !== 'string') {
|
|
2802
|
+
LogMetadata.Context[context][LogBuiltInMetadata.Context.Uncategorized] = (LogBuiltInMetadata.Context.Uncategorized);
|
|
2803
|
+
}
|
|
2804
|
+
});
|
|
2805
|
+
// > Add built-in contexts
|
|
2806
|
+
LogMetadata.Context = ((_b = LogMetadata.Context) !== null && _b !== void 0 ? _b : {});
|
|
2807
|
+
Object.keys(LogBuiltInMetadata.Context).forEach((context) => {
|
|
2808
|
+
if (LogMetadata.Context) {
|
|
2809
|
+
LogMetadata.Context[context] = context;
|
|
2810
|
+
}
|
|
2811
|
+
});
|
|
2812
|
+
// > Add built-in targets
|
|
2813
|
+
LogMetadata.Target = ((_c = LogMetadata.Target) !== null && _c !== void 0 ? _c : {});
|
|
2814
|
+
Object.keys(LogBuiltInMetadata.Target).forEach((target) => {
|
|
2815
|
+
if (LogMetadata.Target) {
|
|
2816
|
+
LogMetadata.Target[target] = target;
|
|
2817
|
+
}
|
|
2818
|
+
});
|
|
2732
2819
|
/* -------------- State ------------- */
|
|
2733
2820
|
// Create initial date filter state
|
|
2734
2821
|
const today = getTimeInfoInET();
|
|
@@ -2748,7 +2835,7 @@ const LogReviewer = (props) => {
|
|
|
2748
2835
|
};
|
|
2749
2836
|
// Create initial context filter state
|
|
2750
2837
|
const initContextFilterState = {};
|
|
2751
|
-
Object.keys((
|
|
2838
|
+
Object.keys((_d = LogMetadata.Context) !== null && _d !== void 0 ? _d : {}).forEach((context) => {
|
|
2752
2839
|
var _a, _b;
|
|
2753
2840
|
const contextValue = ((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {})[context];
|
|
2754
2841
|
if (typeof contextValue === 'string') {
|
|
@@ -2766,7 +2853,7 @@ const LogReviewer = (props) => {
|
|
|
2766
2853
|
});
|
|
2767
2854
|
// Create initial tag filter state
|
|
2768
2855
|
const initTagFilterState = {};
|
|
2769
|
-
Object.values((
|
|
2856
|
+
Object.values((_e = LogMetadata.Tag) !== null && _e !== void 0 ? _e : {}).forEach((tagValue) => {
|
|
2770
2857
|
initTagFilterState[tagValue] = true;
|
|
2771
2858
|
});
|
|
2772
2859
|
// Create advanced filter state
|
|
@@ -2793,12 +2880,16 @@ const LogReviewer = (props) => {
|
|
|
2793
2880
|
target: {},
|
|
2794
2881
|
action: {},
|
|
2795
2882
|
};
|
|
2796
|
-
Object.values((
|
|
2883
|
+
Object.values((_f = LogMetadata.Target) !== null && _f !== void 0 ? _f : {}).forEach((target) => {
|
|
2797
2884
|
initActionErrorFilterState.target[target] = true;
|
|
2798
2885
|
});
|
|
2799
2886
|
Object.values(LogAction$1).forEach((action) => {
|
|
2800
2887
|
initActionErrorFilterState.action[action] = true;
|
|
2801
2888
|
});
|
|
2889
|
+
// Add built-in targets
|
|
2890
|
+
Object.values(LogBuiltInMetadata.Target).forEach((target) => {
|
|
2891
|
+
initActionErrorFilterState.target[target] = true;
|
|
2892
|
+
});
|
|
2802
2893
|
// Initial state
|
|
2803
2894
|
const initialState = {
|
|
2804
2895
|
loading: true,
|
|
@@ -2832,15 +2923,18 @@ const LogReviewer = (props) => {
|
|
|
2832
2923
|
let month = newDateFilterState.startDate.month;
|
|
2833
2924
|
while (
|
|
2834
2925
|
// Earlier year
|
|
2835
|
-
(year
|
|
2926
|
+
(year < newDateFilterState.endDate.year)
|
|
2836
2927
|
// Current year but included month
|
|
2837
2928
|
|| (year === newDateFilterState.endDate.year
|
|
2838
2929
|
&& month <= newDateFilterState.endDate.month)) {
|
|
2839
|
-
// Add to list
|
|
2840
|
-
|
|
2841
|
-
year
|
|
2842
|
-
|
|
2843
|
-
|
|
2930
|
+
// Add to list if not already loaded
|
|
2931
|
+
if (!logMap[year]
|
|
2932
|
+
|| !logMap[year][month]) {
|
|
2933
|
+
toLoad.push({
|
|
2934
|
+
year,
|
|
2935
|
+
month,
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
2844
2938
|
// Increment
|
|
2845
2939
|
month += 1;
|
|
2846
2940
|
if (month > 12) {
|
|
@@ -2864,6 +2958,7 @@ const LogReviewer = (props) => {
|
|
|
2864
2958
|
});
|
|
2865
2959
|
// Check which year/month combos we need to load
|
|
2866
2960
|
const toLoad = listMonthsToLoad(newDateFilterState);
|
|
2961
|
+
console.log('Filter update:', newDateFilterState, toLoad, logMap);
|
|
2867
2962
|
// If nothing to load, finished
|
|
2868
2963
|
if (toLoad.length === 0) {
|
|
2869
2964
|
return;
|
|
@@ -2928,10 +3023,10 @@ const LogReviewer = (props) => {
|
|
|
2928
3023
|
/* Filters */
|
|
2929
3024
|
/*----------------------------------------*/
|
|
2930
3025
|
// Filter toggle
|
|
2931
|
-
const filterToggles = (React__default["default"].createElement("div", { className: "LogReviewer-filter-toggles
|
|
3026
|
+
const filterToggles = (React__default["default"].createElement("div", { className: "LogReviewer-filter-toggles" },
|
|
2932
3027
|
React__default["default"].createElement("h3", { className: "m-0" }, "Filters:"),
|
|
2933
|
-
React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons" },
|
|
2934
|
-
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-date-filter-drawer", className: `btn btn-${FilterDrawer.Date === expandedFilterDrawer} me-2`, "aria-label": "toggle date filter drawer", onClick: () => {
|
|
3028
|
+
React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
|
|
3029
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-date-filter-drawer", className: `btn btn-${FilterDrawer.Date === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle date filter drawer", onClick: () => {
|
|
2935
3030
|
dispatch({
|
|
2936
3031
|
type: ActionType.ToggleFilterDrawer,
|
|
2937
3032
|
filterDrawer: FilterDrawer.Date,
|
|
@@ -2939,7 +3034,7 @@ const LogReviewer = (props) => {
|
|
|
2939
3034
|
} },
|
|
2940
3035
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCalendar, className: "me-2" }),
|
|
2941
3036
|
"Date"),
|
|
2942
|
-
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-context-filter-drawer", className: `btn btn-${FilterDrawer.Context === expandedFilterDrawer} me-2`, "aria-label": "toggle context filter drawer", onClick: () => {
|
|
3037
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-context-filter-drawer", className: `btn btn-${FilterDrawer.Context === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle context filter drawer", onClick: () => {
|
|
2943
3038
|
dispatch({
|
|
2944
3039
|
type: ActionType.ToggleFilterDrawer,
|
|
2945
3040
|
filterDrawer: FilterDrawer.Context,
|
|
@@ -2947,15 +3042,15 @@ const LogReviewer = (props) => {
|
|
|
2947
3042
|
} },
|
|
2948
3043
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "me-2" }),
|
|
2949
3044
|
"Context"),
|
|
2950
|
-
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-tag-filter-drawer", className: `btn btn-${FilterDrawer.Tag === expandedFilterDrawer} me-2`, "aria-label": "toggle tag filter drawer", onClick: () => {
|
|
3045
|
+
(LogMetadata.Tag && Object.keys(LogMetadata.Tag).length > 0) && (React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-tag-filter-drawer", className: `btn btn-${FilterDrawer.Tag === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle tag filter drawer", onClick: () => {
|
|
2951
3046
|
dispatch({
|
|
2952
3047
|
type: ActionType.ToggleFilterDrawer,
|
|
2953
3048
|
filterDrawer: FilterDrawer.Tag,
|
|
2954
3049
|
});
|
|
2955
3050
|
} },
|
|
2956
3051
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTag, className: "me-2" }),
|
|
2957
|
-
"Tag"),
|
|
2958
|
-
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-action-filter-drawer", className: `btn btn-${FilterDrawer.Action === expandedFilterDrawer} me-2`, "aria-label": "toggle action and error filter drawer", onClick: () => {
|
|
3052
|
+
"Tag")),
|
|
3053
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-action-filter-drawer", className: `btn btn-${FilterDrawer.Action === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle action and error filter drawer", onClick: () => {
|
|
2959
3054
|
dispatch({
|
|
2960
3055
|
type: ActionType.ToggleFilterDrawer,
|
|
2961
3056
|
filterDrawer: FilterDrawer.Action,
|
|
@@ -2963,7 +3058,7 @@ const LogReviewer = (props) => {
|
|
|
2963
3058
|
} },
|
|
2964
3059
|
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faHammer, className: "me-2" }),
|
|
2965
3060
|
"Action"),
|
|
2966
|
-
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer}`, "aria-label": "toggle advanced filter drawer", onClick: () => {
|
|
3061
|
+
React__default["default"].createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer ? 'warning' : 'light'}`, "aria-label": "toggle advanced filter drawer", onClick: () => {
|
|
2967
3062
|
dispatch({
|
|
2968
3063
|
type: ActionType.ToggleFilterDrawer,
|
|
2969
3064
|
filterDrawer: FilterDrawer.Advanced,
|
|
@@ -2976,25 +3071,29 @@ const LogReviewer = (props) => {
|
|
|
2976
3071
|
if (expandedFilterDrawer) {
|
|
2977
3072
|
if (expandedFilterDrawer === FilterDrawer.Date) {
|
|
2978
3073
|
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Date" },
|
|
2979
|
-
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter start date", name: "filter-start-date", year: dateFilterState.startDate.year, month: dateFilterState.startDate.month, day: dateFilterState.startDate.day, onChange: (month, day, year) => {
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
dateFilterState: Object.assign(Object.assign({}, dateFilterState), { startDate: { month, day, year } }),
|
|
2983
|
-
});
|
|
3074
|
+
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter start date", name: "filter-start-date", year: dateFilterState.startDate.year, month: dateFilterState.startDate.month, day: dateFilterState.startDate.day, chooseFromPast: true, numMonthsToShow: 12, onChange: (month, day, year) => {
|
|
3075
|
+
dateFilterState.startDate = { month, day, year };
|
|
3076
|
+
handleDateRangeUpdated(dateFilterState);
|
|
2984
3077
|
} }),
|
|
2985
3078
|
' ',
|
|
2986
3079
|
"to",
|
|
2987
3080
|
' ',
|
|
2988
|
-
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter end date", name: "filter-end-date", year: dateFilterState.endDate.year, month: dateFilterState.endDate.month, day: dateFilterState.endDate.day, onChange: (month, day, year) => {
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
3081
|
+
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) => {
|
|
3082
|
+
if (year < dateFilterState.startDate.year
|
|
3083
|
+
|| (year === dateFilterState.startDate.year
|
|
3084
|
+
&& month < dateFilterState.startDate.month)
|
|
3085
|
+
|| (year === dateFilterState.startDate.year
|
|
3086
|
+
&& month === dateFilterState.startDate.month
|
|
3087
|
+
&& day < dateFilterState.startDate.day)) {
|
|
3088
|
+
return alert$1('Invalid Start Date', 'The start date cannot be before the end date.');
|
|
3089
|
+
}
|
|
3090
|
+
dateFilterState.endDate = { month, day, year };
|
|
3091
|
+
handleDateRangeUpdated(dateFilterState);
|
|
2993
3092
|
} })));
|
|
2994
3093
|
}
|
|
2995
3094
|
else if (expandedFilterDrawer === FilterDrawer.Context) {
|
|
2996
3095
|
// Create item picker items
|
|
2997
|
-
const pickableItems = (Object.keys((
|
|
3096
|
+
const pickableItems = (Object.keys((_g = LogMetadata.Context) !== null && _g !== void 0 ? _g : {})
|
|
2998
3097
|
.map((context) => {
|
|
2999
3098
|
var _a;
|
|
3000
3099
|
const value = ((_a = LogMetadata.Context) !== null && _a !== void 0 ? _a : {})[context];
|
|
@@ -3023,7 +3122,7 @@ const LogReviewer = (props) => {
|
|
|
3023
3122
|
}));
|
|
3024
3123
|
const item = {
|
|
3025
3124
|
id: context,
|
|
3026
|
-
name: context,
|
|
3125
|
+
name: genHumanReadableName(context),
|
|
3027
3126
|
isGroup: true,
|
|
3028
3127
|
children,
|
|
3029
3128
|
};
|
|
@@ -3031,6 +3130,8 @@ const LogReviewer = (props) => {
|
|
|
3031
3130
|
}));
|
|
3032
3131
|
// Create filter UI
|
|
3033
3132
|
filterDrawer = (React__default["default"].createElement(ItemPicker, { title: "Context", items: pickableItems, onChanged: (updatedItems) => {
|
|
3133
|
+
console.log('Items before:', pickableItems);
|
|
3134
|
+
console.log('Updated Items:', updatedItems);
|
|
3034
3135
|
// Update our state
|
|
3035
3136
|
updatedItems.forEach((pickableItem) => {
|
|
3036
3137
|
if (pickableItem.isGroup) {
|
|
@@ -3087,7 +3188,7 @@ const LogReviewer = (props) => {
|
|
|
3087
3188
|
}, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
|
|
3088
3189
|
(actionErrorFilterState.type === undefined
|
|
3089
3190
|
|| actionErrorFilterState.type === LogType$1.Action) && (React__default["default"].createElement(TabBox, { title: "Action Log Details" },
|
|
3090
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Action" }, Object.keys(LogAction$1)
|
|
3191
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Action", className: "mb-2" }, Object.keys(LogAction$1)
|
|
3091
3192
|
.map((action, i) => {
|
|
3092
3193
|
const description = genHumanReadableName(action);
|
|
3093
3194
|
return (React__default["default"].createElement(CheckboxButton, { id: `LogReviewer-action-${action}-checkbox`, text: description, ariaLabel: `include logs with action type "${description}" in results`, noMarginOnRight: i === Object.keys(LogAction$1).length - 1, onChanged: (checked) => {
|
|
@@ -3098,18 +3199,20 @@ const LogReviewer = (props) => {
|
|
|
3098
3199
|
});
|
|
3099
3200
|
} }));
|
|
3100
3201
|
})),
|
|
3101
|
-
React__default["default"].createElement(ButtonInputGroup, { label: "Target" },
|
|
3102
|
-
.
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3202
|
+
React__default["default"].createElement(ButtonInputGroup, { label: "Target" },
|
|
3203
|
+
(Object.keys((_h = LogMetadata.Target) !== null && _h !== void 0 ? _h : {}).length === 0) && (React__default["default"].createElement("div", null, "This app does not have any targets yet.")),
|
|
3204
|
+
Object.keys((_j = LogMetadata.Target) !== null && _j !== void 0 ? _j : {})
|
|
3205
|
+
.map((target, i) => {
|
|
3206
|
+
var _a;
|
|
3207
|
+
const description = genHumanReadableName(target);
|
|
3208
|
+
return (React__default["default"].createElement(CheckboxButton, { id: `LogReviewer-target-${target}-checkbox`, text: description, ariaLabel: `include logs with target "${description}" in results`, onChanged: (checked) => {
|
|
3209
|
+
actionErrorFilterState.target[target] = checked;
|
|
3210
|
+
dispatch({
|
|
3211
|
+
type: ActionType.UpdateActionErrorFilterState,
|
|
3212
|
+
actionErrorFilterState,
|
|
3213
|
+
});
|
|
3214
|
+
}, noMarginOnRight: i === Object.keys((_a = LogMetadata.Target) !== null && _a !== void 0 ? _a : {}).length - 1 }));
|
|
3215
|
+
})))),
|
|
3113
3216
|
(actionErrorFilterState.type === undefined
|
|
3114
3217
|
|| actionErrorFilterState.type === LogType$1.Error) && (React__default["default"].createElement(TabBox, { title: "Error Log Details" },
|
|
3115
3218
|
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
@@ -3271,26 +3374,27 @@ const LogReviewer = (props) => {
|
|
|
3271
3374
|
advancedFilterState,
|
|
3272
3375
|
});
|
|
3273
3376
|
}, noMarginOnRight: true })),
|
|
3274
|
-
React__default["default"].createElement("div", { className: "
|
|
3275
|
-
React__default["default"].createElement("
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
.
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
React__default["default"].createElement("
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
.
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3377
|
+
advancedFilterState.source !== LogSource$1.Client && (React__default["default"].createElement("div", { className: "mt-2" },
|
|
3378
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
3379
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Path"),
|
|
3380
|
+
React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for server route path", placeholder: "e.g. /api/ttm/courses/12345", value: advancedFilterState.routePath, onChange: (e) => {
|
|
3381
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
3382
|
+
.trim());
|
|
3383
|
+
dispatch({
|
|
3384
|
+
type: ActionType.UpdateAdvancedFilterState,
|
|
3385
|
+
advancedFilterState,
|
|
3386
|
+
});
|
|
3387
|
+
} })),
|
|
3388
|
+
React__default["default"].createElement("div", { className: "input-group mb-2" },
|
|
3389
|
+
React__default["default"].createElement("span", { className: "input-group-text" }, "Server Route Template"),
|
|
3390
|
+
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) => {
|
|
3391
|
+
advancedFilterState.courseName = ((e.target.value)
|
|
3392
|
+
.trim());
|
|
3393
|
+
dispatch({
|
|
3394
|
+
type: ActionType.UpdateAdvancedFilterState,
|
|
3395
|
+
advancedFilterState,
|
|
3396
|
+
});
|
|
3397
|
+
} })))))));
|
|
3294
3398
|
}
|
|
3295
3399
|
}
|
|
3296
3400
|
// Filters UI
|
|
@@ -3301,10 +3405,11 @@ const LogReviewer = (props) => {
|
|
|
3301
3405
|
// > Perform filters
|
|
3302
3406
|
const logs = [];
|
|
3303
3407
|
Object.keys(logMap).forEach((year) => {
|
|
3304
|
-
Object.keys(logMap).forEach((month) => {
|
|
3408
|
+
Object.keys(logMap[year]).forEach((month) => {
|
|
3305
3409
|
logMap[year][month].forEach((log) => {
|
|
3306
|
-
/* ----------- Date Filter ---------- */
|
|
3307
3410
|
var _a;
|
|
3411
|
+
/* ----------- Date Filter ---------- */
|
|
3412
|
+
console.log('Log:', log);
|
|
3308
3413
|
// Before start date
|
|
3309
3414
|
if (
|
|
3310
3415
|
// Previous year
|
|
@@ -3316,6 +3421,7 @@ const LogReviewer = (props) => {
|
|
|
3316
3421
|
|| ((log.year === dateFilterState.startDate.year)
|
|
3317
3422
|
&& (log.month === dateFilterState.startDate.month)
|
|
3318
3423
|
&& (log.day < dateFilterState.startDate.day))) {
|
|
3424
|
+
console.log('RULED OUT: START');
|
|
3319
3425
|
return;
|
|
3320
3426
|
}
|
|
3321
3427
|
// After end date
|
|
@@ -3329,6 +3435,7 @@ const LogReviewer = (props) => {
|
|
|
3329
3435
|
|| ((log.year === dateFilterState.endDate.year)
|
|
3330
3436
|
&& (log.month === dateFilterState.endDate.month)
|
|
3331
3437
|
&& (log.day > dateFilterState.endDate.day))) {
|
|
3438
|
+
console.log('RULED OUT: END');
|
|
3332
3439
|
return;
|
|
3333
3440
|
}
|
|
3334
3441
|
/* --------- Context Filter --------- */
|
|
@@ -3341,29 +3448,30 @@ const LogReviewer = (props) => {
|
|
|
3341
3448
|
.every((isSelected) => {
|
|
3342
3449
|
return !isSelected;
|
|
3343
3450
|
}))) {
|
|
3451
|
+
console.log('RULED OUT: CONTEXT');
|
|
3344
3452
|
return;
|
|
3345
3453
|
}
|
|
3346
3454
|
// Subcontext doesn't match
|
|
3347
3455
|
if (
|
|
3348
|
-
// Log
|
|
3349
|
-
log.
|
|
3456
|
+
// Log context is not "uncategorized" (no point in further filters)
|
|
3457
|
+
log.context !== LogBuiltInMetadata.Context.Uncategorized
|
|
3458
|
+
// Log has a subcontext
|
|
3459
|
+
&& log.subcontext
|
|
3350
3460
|
// Context has subcontexts
|
|
3351
3461
|
&& (contextFilterState[log.context]
|
|
3352
3462
|
&& contextFilterState[log.context] !== false
|
|
3353
3463
|
&& contextFilterState[log.context] !== true)
|
|
3354
3464
|
// Subcontext is not selected
|
|
3355
3465
|
&& !contextFilterState[log.context][log.subcontext]) {
|
|
3466
|
+
console.log('RULED OUT: SUBCONTEXT');
|
|
3356
3467
|
return;
|
|
3357
3468
|
}
|
|
3358
3469
|
/* -------------- Tags -------------- */
|
|
3359
3470
|
// No tags match
|
|
3360
|
-
if (
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
&& (log.tags.every((tag) => {
|
|
3365
|
-
return !tagFilterState[tag];
|
|
3366
|
-
}))) {
|
|
3471
|
+
if (log.tags.every((tag) => {
|
|
3472
|
+
return !tagFilterState[tag];
|
|
3473
|
+
})) {
|
|
3474
|
+
console.log('RULED OUT: TAGS');
|
|
3367
3475
|
return;
|
|
3368
3476
|
}
|
|
3369
3477
|
/* ------- Actions and Errors ------- */
|
|
@@ -3373,6 +3481,7 @@ const LogReviewer = (props) => {
|
|
|
3373
3481
|
actionErrorFilterState.type !== undefined
|
|
3374
3482
|
// Log type doesn't match
|
|
3375
3483
|
&& actionErrorFilterState.type !== log.type) {
|
|
3484
|
+
console.log('RULED OUT: TYPE');
|
|
3376
3485
|
return;
|
|
3377
3486
|
}
|
|
3378
3487
|
// Filter errors
|
|
@@ -3385,6 +3494,7 @@ const LogReviewer = (props) => {
|
|
|
3385
3494
|
&& actionErrorFilterState.errorMessage.trim().length > 0
|
|
3386
3495
|
// Message doesn't match
|
|
3387
3496
|
&& log.errorMessage.toLowerCase().includes(actionErrorFilterState.errorMessage.trim().toLowerCase())) {
|
|
3497
|
+
console.log('RULED OUT: ERROR MESSAGE');
|
|
3388
3498
|
return;
|
|
3389
3499
|
}
|
|
3390
3500
|
// Code doesn't match
|
|
@@ -3395,6 +3505,7 @@ const LogReviewer = (props) => {
|
|
|
3395
3505
|
&& actionErrorFilterState.errorCode.trim().length > 0
|
|
3396
3506
|
// Code doesn't match
|
|
3397
3507
|
&& log.errorCode.toUpperCase().includes(actionErrorFilterState.errorCode.trim().toUpperCase())) {
|
|
3508
|
+
console.log('RULED OUT: ERROR CODE');
|
|
3398
3509
|
return;
|
|
3399
3510
|
}
|
|
3400
3511
|
}
|
|
@@ -3406,6 +3517,7 @@ const LogReviewer = (props) => {
|
|
|
3406
3517
|
log.target
|
|
3407
3518
|
// Target isn't selected
|
|
3408
3519
|
&& !actionErrorFilterState.target[log.target]) {
|
|
3520
|
+
console.log('RULED OUT: TARGET');
|
|
3409
3521
|
return;
|
|
3410
3522
|
}
|
|
3411
3523
|
// Action
|
|
@@ -3414,6 +3526,7 @@ const LogReviewer = (props) => {
|
|
|
3414
3526
|
log.action
|
|
3415
3527
|
// Action isn't selected
|
|
3416
3528
|
&& !actionErrorFilterState.action[log.action]) {
|
|
3529
|
+
console.log('RULED OUT: ACTION');
|
|
3417
3530
|
return;
|
|
3418
3531
|
}
|
|
3419
3532
|
}
|
|
@@ -3424,6 +3537,7 @@ const LogReviewer = (props) => {
|
|
|
3424
3537
|
log.userFirstName
|
|
3425
3538
|
// First name query doesn't match
|
|
3426
3539
|
&& !log.userFirstName.toLowerCase().includes(advancedFilterState.userFirstName.toLowerCase().trim())) {
|
|
3540
|
+
console.log('RULED OUT: FIRST');
|
|
3427
3541
|
return;
|
|
3428
3542
|
}
|
|
3429
3543
|
// Last name doesn't match
|
|
@@ -3432,6 +3546,7 @@ const LogReviewer = (props) => {
|
|
|
3432
3546
|
log.userLastName
|
|
3433
3547
|
// Last name query doesn't match
|
|
3434
3548
|
&& !log.userLastName.toLowerCase().includes(advancedFilterState.userLastName.toLowerCase().trim())) {
|
|
3549
|
+
console.log('RULED OUT: LAST');
|
|
3435
3550
|
return;
|
|
3436
3551
|
}
|
|
3437
3552
|
// Email doesn't match
|
|
@@ -3440,6 +3555,7 @@ const LogReviewer = (props) => {
|
|
|
3440
3555
|
log.userEmail
|
|
3441
3556
|
// Email query doesn't match
|
|
3442
3557
|
&& !log.userEmail.toLowerCase().includes(advancedFilterState.userEmail.toLowerCase().trim())) {
|
|
3558
|
+
console.log('RULED OUT: EMAIL');
|
|
3443
3559
|
return;
|
|
3444
3560
|
}
|
|
3445
3561
|
// User id doesn't match
|
|
@@ -3448,6 +3564,7 @@ const LogReviewer = (props) => {
|
|
|
3448
3564
|
log.userId
|
|
3449
3565
|
// User id doesn't match
|
|
3450
3566
|
&& !String(log.userId).includes(advancedFilterState.userId.trim())) {
|
|
3567
|
+
console.log('RULED OUT: USER ID');
|
|
3451
3568
|
return;
|
|
3452
3569
|
}
|
|
3453
3570
|
// Learner not allowed
|
|
@@ -3456,6 +3573,7 @@ const LogReviewer = (props) => {
|
|
|
3456
3573
|
log.isLearner
|
|
3457
3574
|
// Learners aren't included
|
|
3458
3575
|
&& !advancedFilterState.includeLearners) {
|
|
3576
|
+
console.log('RULED OUT: LEARNER');
|
|
3459
3577
|
return;
|
|
3460
3578
|
}
|
|
3461
3579
|
// TTM not allowed
|
|
@@ -3464,6 +3582,7 @@ const LogReviewer = (props) => {
|
|
|
3464
3582
|
log.isTTM
|
|
3465
3583
|
// TTMs aren't included
|
|
3466
3584
|
&& !advancedFilterState.includeTTMs) {
|
|
3585
|
+
console.log('RULED OUT: TTM');
|
|
3467
3586
|
return;
|
|
3468
3587
|
}
|
|
3469
3588
|
// Admin not allowed
|
|
@@ -3472,6 +3591,7 @@ const LogReviewer = (props) => {
|
|
|
3472
3591
|
log.isAdmin
|
|
3473
3592
|
// Admins aren't included
|
|
3474
3593
|
&& !advancedFilterState.includeAdmins) {
|
|
3594
|
+
console.log('RULED OUT: ADMIN');
|
|
3475
3595
|
return;
|
|
3476
3596
|
}
|
|
3477
3597
|
// Course Id doesn't match
|
|
@@ -3480,6 +3600,7 @@ const LogReviewer = (props) => {
|
|
|
3480
3600
|
log.courseId
|
|
3481
3601
|
// Course Id doesn't match
|
|
3482
3602
|
&& !String(log.courseId).includes(advancedFilterState.courseId.trim())) {
|
|
3603
|
+
console.log('RULED OUT: COURSE ID');
|
|
3483
3604
|
return;
|
|
3484
3605
|
}
|
|
3485
3606
|
// Course name doesn't match
|
|
@@ -3488,6 +3609,7 @@ const LogReviewer = (props) => {
|
|
|
3488
3609
|
log.courseName
|
|
3489
3610
|
// Course name doesn't match
|
|
3490
3611
|
&& !String(log.courseName).includes(advancedFilterState.courseName.trim())) {
|
|
3612
|
+
console.log('RULED OUT: COURSE NAME');
|
|
3491
3613
|
return;
|
|
3492
3614
|
}
|
|
3493
3615
|
// Mobile filter doesn't match
|
|
@@ -3498,6 +3620,7 @@ const LogReviewer = (props) => {
|
|
|
3498
3620
|
&& log.device
|
|
3499
3621
|
// Mobile filter doesn't match
|
|
3500
3622
|
&& (advancedFilterState.isMobile === log.device.isMobile)) {
|
|
3623
|
+
console.log('RULED OUT: MOBILE');
|
|
3501
3624
|
return;
|
|
3502
3625
|
}
|
|
3503
3626
|
// Log source doesn't match
|
|
@@ -3508,6 +3631,7 @@ const LogReviewer = (props) => {
|
|
|
3508
3631
|
&& log.source
|
|
3509
3632
|
// Source filter doesn't match
|
|
3510
3633
|
&& (advancedFilterState.source !== log.source)) {
|
|
3634
|
+
console.log('RULED OUT: SOURCE');
|
|
3511
3635
|
return;
|
|
3512
3636
|
}
|
|
3513
3637
|
// Route path doesn't match (Only for server source)
|
|
@@ -3518,6 +3642,7 @@ const LogReviewer = (props) => {
|
|
|
3518
3642
|
&& (advancedFilterState.routePath.trim().length)
|
|
3519
3643
|
// Route path doesn't match
|
|
3520
3644
|
&& !(log.routePath.includes(advancedFilterState.routePath.trim()))) {
|
|
3645
|
+
console.log('RULED OUT: PATH');
|
|
3521
3646
|
return;
|
|
3522
3647
|
}
|
|
3523
3648
|
// Route template doesn't match (Only for server source)
|
|
@@ -3528,6 +3653,7 @@ const LogReviewer = (props) => {
|
|
|
3528
3653
|
&& (advancedFilterState.routeTemplate.trim().length)
|
|
3529
3654
|
// Route template doesn't match
|
|
3530
3655
|
&& !(log.routeTemplate.includes(advancedFilterState.routeTemplate.trim()))) {
|
|
3656
|
+
console.log('RULED OUT: TEMPLATE');
|
|
3531
3657
|
return;
|
|
3532
3658
|
}
|
|
3533
3659
|
/* -------------- Done -------------- */
|
|
@@ -3727,11 +3853,17 @@ const LogReviewer = (props) => {
|
|
|
3727
3853
|
},
|
|
3728
3854
|
];
|
|
3729
3855
|
// Create intelliTable
|
|
3730
|
-
const dataTable = (
|
|
3856
|
+
const dataTable = (logs.length === 0
|
|
3857
|
+
? (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
3858
|
+
React__default["default"].createElement("h3", { className: "m-0" }, "Matching Logs:"),
|
|
3859
|
+
React__default["default"].createElement("div", { className: "alert alert-warning text-center" },
|
|
3860
|
+
React__default["default"].createElement("h4", { className: "m-1" }, "No Logs to Show"),
|
|
3861
|
+
React__default["default"].createElement("div", null, "Either your filters are too strict or no matching logs have been created yet."))))
|
|
3862
|
+
: (React__default["default"].createElement(IntelliTable, { title: "Matching Logs:", id: "logs", data: logs, columns: columns })));
|
|
3731
3863
|
// Main body
|
|
3732
3864
|
body = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
3733
3865
|
filters,
|
|
3734
|
-
dataTable));
|
|
3866
|
+
React__default["default"].createElement("div", { className: "mt-2" }, dataTable)));
|
|
3735
3867
|
}
|
|
3736
3868
|
/* ---------- Wrap in Modal --------- */
|
|
3737
3869
|
return (React__default["default"].createElement("div", { className: "LogReviewer-outer-container" },
|
|
@@ -3739,14 +3871,10 @@ const LogReviewer = (props) => {
|
|
|
3739
3871
|
React__default["default"].createElement("div", { className: "LogReviewer-inner-container" },
|
|
3740
3872
|
React__default["default"].createElement("div", { className: "LogReviewer-header" },
|
|
3741
3873
|
React__default["default"].createElement("div", { className: "LogReviewer-header-title" },
|
|
3742
|
-
React__default["default"].createElement("
|
|
3743
|
-
React__default["default"].createElement("
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
padding: 0,
|
|
3747
|
-
margin: 0,
|
|
3748
|
-
} },
|
|
3749
|
-
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes }))),
|
|
3874
|
+
React__default["default"].createElement("h3", { className: "text-center m-0" }, "Log Review Dashboard")),
|
|
3875
|
+
React__default["default"].createElement("div", { style: { width: 0 } },
|
|
3876
|
+
React__default["default"].createElement("button", { type: "button", className: "LogReviewer-header-close-button btn btn-dark btn-lg pe-0", "aria-label": "close log reviewer panel", onClick: onClose },
|
|
3877
|
+
React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faTimes })))),
|
|
3750
3878
|
React__default["default"].createElement("div", { className: "LogReviewer-contents" }, body))));
|
|
3751
3879
|
};
|
|
3752
3880
|
|
|
@@ -3892,7 +4020,7 @@ const padZerosLeft = (num, numDigits) => {
|
|
|
3892
4020
|
* access to log review
|
|
3893
4021
|
* @author Gabe Abrams
|
|
3894
4022
|
*/
|
|
3895
|
-
const LOG_REVIEW_STATUS_ROUTE =
|
|
4023
|
+
const LOG_REVIEW_STATUS_ROUTE = `${ROUTE_PATH_PREFIX}/logs/access_allowed`;
|
|
3896
4024
|
|
|
3897
4025
|
// Stored copy of caccl functions
|
|
3898
4026
|
let _cacclGetLaunchInfo;
|
|
@@ -3934,7 +4062,7 @@ const internalGetLogCollection = () => {
|
|
|
3934
4062
|
* @param opts.getLaunchInfo CACCL LTI's get launch info function
|
|
3935
4063
|
* @param [opts.logCollection] mongo collection from dce-mango to use for
|
|
3936
4064
|
* storing logs. If none is included, logs are written to the console
|
|
3937
|
-
* @param [opts.logReviewAdmins=all
|
|
4065
|
+
* @param [opts.logReviewAdmins=all] info on which admins can review
|
|
3938
4066
|
* logs from the client. If not included, all Canvas admins are allowed to
|
|
3939
4067
|
* review logs. If null, no Canvas admins are allowed to review logs.
|
|
3940
4068
|
* If an array of Canvas userIds (numbers), only Canvas admins with those
|
|
@@ -4017,71 +4145,81 @@ const initServer = (opts) => {
|
|
|
4017
4145
|
/*----------------------------------------*/
|
|
4018
4146
|
/* Log Reviewer */
|
|
4019
4147
|
/*----------------------------------------*/
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4148
|
+
/**
|
|
4149
|
+
* Check if a given user is allowed to review logs
|
|
4150
|
+
* @author Gabe Abrams
|
|
4151
|
+
* @param userId the id of the user
|
|
4152
|
+
* @param isAdmin if true, the user is an admin
|
|
4153
|
+
* @returns true if the user can review logs
|
|
4154
|
+
*/
|
|
4155
|
+
const canReviewLogs = (userId, isAdmin) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4156
|
+
// Immediately deny access if user is not an admin
|
|
4157
|
+
if (!isAdmin) {
|
|
4158
|
+
return false;
|
|
4159
|
+
}
|
|
4160
|
+
// If all admins are allowed, we're done
|
|
4161
|
+
if (!opts.logReviewAdmins) {
|
|
4162
|
+
return true;
|
|
4163
|
+
}
|
|
4164
|
+
// Do a dynamic check
|
|
4165
|
+
try {
|
|
4166
|
+
// Array of userIds
|
|
4167
|
+
if (Array.isArray(opts.logReviewAdmins)) {
|
|
4168
|
+
return opts.logReviewAdmins.some((allowedId) => {
|
|
4169
|
+
return (userId === allowedId);
|
|
4170
|
+
});
|
|
4039
4171
|
}
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4172
|
+
// Must be a collection
|
|
4173
|
+
const matches = yield opts.logReviewAdmins.find({ userId });
|
|
4174
|
+
// Make sure at least one entry matches
|
|
4175
|
+
return matches.length > 0;
|
|
4176
|
+
}
|
|
4177
|
+
catch (err) {
|
|
4178
|
+
// If an error occurred, simply return false
|
|
4179
|
+
return false;
|
|
4180
|
+
}
|
|
4181
|
+
});
|
|
4182
|
+
/**
|
|
4183
|
+
* Check if the current user has access to logs
|
|
4184
|
+
* @author Gabe Abrams
|
|
4185
|
+
* @returns {boolean} true if user has access
|
|
4186
|
+
*/
|
|
4187
|
+
opts.app.get(LOG_REVIEW_STATUS_ROUTE, genRouteHandler({
|
|
4188
|
+
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4189
|
+
const { userId, isAdmin } = params;
|
|
4190
|
+
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
4191
|
+
return canReview;
|
|
4192
|
+
}),
|
|
4193
|
+
}));
|
|
4194
|
+
/**
|
|
4195
|
+
* Get all logs for a certain month
|
|
4196
|
+
* @author Gabe Abrams
|
|
4197
|
+
* @param {number} year the year to query (e.g. 2022)
|
|
4198
|
+
* @param {number} month the month to query (e.g. 1 = January)
|
|
4199
|
+
* @returns {Log[]} list of logs from the given month
|
|
4200
|
+
*/
|
|
4201
|
+
opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler({
|
|
4202
|
+
paramTypes: {
|
|
4203
|
+
year: ParamType$1.Int,
|
|
4204
|
+
month: ParamType$1.Int,
|
|
4205
|
+
},
|
|
4206
|
+
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4207
|
+
// Get user info
|
|
4208
|
+
const { year, month, userId, isAdmin, } = params;
|
|
4209
|
+
// Validate user
|
|
4210
|
+
const canReview = yield canReviewLogs(userId, isAdmin);
|
|
4211
|
+
if (!canReview) {
|
|
4212
|
+
throw new ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ReactKitErrorCode$1.NotAllowedToReviewLogs);
|
|
4043
4213
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
const canReview = yield canReviewLogs(userId);
|
|
4054
|
-
return canReview;
|
|
4055
|
-
}),
|
|
4056
|
-
}));
|
|
4057
|
-
/**
|
|
4058
|
-
* Get all logs for a certain month
|
|
4059
|
-
* @author Gabe Abrams
|
|
4060
|
-
* @param {number} year the year to query (e.g. 2022)
|
|
4061
|
-
* @param {number} month the month to query (e.g. 1 = January)
|
|
4062
|
-
* @returns {Log[]} list of logs from the given month
|
|
4063
|
-
*/
|
|
4064
|
-
opts.app.post(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler({
|
|
4065
|
-
paramTypes: {
|
|
4066
|
-
year: ParamType$1.Int,
|
|
4067
|
-
month: ParamType$1.Int,
|
|
4068
|
-
},
|
|
4069
|
-
handler: ({ params }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4070
|
-
// Get user info
|
|
4071
|
-
const { userId } = params;
|
|
4072
|
-
// Validate user
|
|
4073
|
-
// isAdmin is already checked because path starts with '/admin'
|
|
4074
|
-
const canReview = yield canReviewLogs(userId);
|
|
4075
|
-
if (!canReview) {
|
|
4076
|
-
throw new ErrorWithCode('You cannot access this resource because you do not have the appropriate permissions.', ReactKitErrorCode$1.NotAllowedToReviewLogs);
|
|
4077
|
-
}
|
|
4078
|
-
// Query for logs
|
|
4079
|
-
const logs = yield _logCollection.find({ userId });
|
|
4080
|
-
// Return logs
|
|
4081
|
-
return logs;
|
|
4082
|
-
}),
|
|
4083
|
-
}));
|
|
4084
|
-
}
|
|
4214
|
+
// Query for logs
|
|
4215
|
+
const logs = yield _logCollection.find({
|
|
4216
|
+
year,
|
|
4217
|
+
month,
|
|
4218
|
+
});
|
|
4219
|
+
// Return logs
|
|
4220
|
+
return logs;
|
|
4221
|
+
}),
|
|
4222
|
+
}));
|
|
4085
4223
|
};
|
|
4086
4224
|
|
|
4087
4225
|
// Import shared types
|
|
@@ -4381,18 +4519,6 @@ const parseUserAgent = (userAgent) => {
|
|
|
4381
4519
|
};
|
|
4382
4520
|
};
|
|
4383
4521
|
|
|
4384
|
-
/**
|
|
4385
|
-
* Allowed log levels
|
|
4386
|
-
* @author Gabe Abrams
|
|
4387
|
-
*/
|
|
4388
|
-
var LogLevel;
|
|
4389
|
-
(function (LogLevel) {
|
|
4390
|
-
LogLevel["Warn"] = "Warn";
|
|
4391
|
-
LogLevel["Info"] = "Info";
|
|
4392
|
-
LogLevel["Debug"] = "Debug";
|
|
4393
|
-
})(LogLevel || (LogLevel = {}));
|
|
4394
|
-
var LogLevel$1 = LogLevel;
|
|
4395
|
-
|
|
4396
4522
|
/**
|
|
4397
4523
|
* Generate an express API route handler
|
|
4398
4524
|
* @author Gabe Abrams
|
|
@@ -4765,7 +4891,7 @@ const genRouteHandler = (opts) => {
|
|
|
4765
4891
|
}
|
|
4766
4892
|
: {
|
|
4767
4893
|
type: LogType$1.Action,
|
|
4768
|
-
target: ((_m = opts.target) !== null && _m !== void 0 ? _m : LogBuiltInMetadata.Target.
|
|
4894
|
+
target: ((_m = opts.target) !== null && _m !== void 0 ? _m : LogBuiltInMetadata.Target.NoTarget),
|
|
4769
4895
|
action: ((_o = opts.action) !== null && _o !== void 0 ? _o : LogAction$1.Unknown),
|
|
4770
4896
|
});
|
|
4771
4897
|
// Source-specific info
|
|
@@ -5132,6 +5258,31 @@ const initLogCollection = (Collection) => {
|
|
|
5132
5258
|
});
|
|
5133
5259
|
};
|
|
5134
5260
|
|
|
5261
|
+
// Cache user's ability
|
|
5262
|
+
let canReview = undefined;
|
|
5263
|
+
/**
|
|
5264
|
+
* Check if the current user can review logs
|
|
5265
|
+
* @author Gabe Abrams
|
|
5266
|
+
* @returns true if current user can review logs
|
|
5267
|
+
*/
|
|
5268
|
+
const canReviewLogs = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
5269
|
+
// If cached, use that value
|
|
5270
|
+
if (canReview !== undefined) {
|
|
5271
|
+
return canReview;
|
|
5272
|
+
}
|
|
5273
|
+
// Ask on server
|
|
5274
|
+
try {
|
|
5275
|
+
canReview = !!(yield visitServerEndpoint({
|
|
5276
|
+
path: LOG_REVIEW_STATUS_ROUTE,
|
|
5277
|
+
method: 'GET',
|
|
5278
|
+
}));
|
|
5279
|
+
}
|
|
5280
|
+
catch (err) {
|
|
5281
|
+
canReview = false;
|
|
5282
|
+
}
|
|
5283
|
+
return canReview;
|
|
5284
|
+
});
|
|
5285
|
+
|
|
5135
5286
|
/**
|
|
5136
5287
|
* Days of the week
|
|
5137
5288
|
* @author Gabe Abrams
|
|
@@ -5184,6 +5335,7 @@ exports.Variant = Variant$1;
|
|
|
5184
5335
|
exports.abbreviate = abbreviate;
|
|
5185
5336
|
exports.alert = alert$1;
|
|
5186
5337
|
exports.avg = avg;
|
|
5338
|
+
exports.canReviewLogs = canReviewLogs;
|
|
5187
5339
|
exports.ceilToNumDecimals = ceilToNumDecimals;
|
|
5188
5340
|
exports.confirm = confirm;
|
|
5189
5341
|
exports.floorToNumDecimals = floorToNumDecimals;
|