dce-reactkit 3.12.1-beta-cross-server.2 → 3.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -1
- package/README.md +0 -20
- package/dist/cjs/index.js +356 -406
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/cjs/types/components/Modal/ModalProps.d.ts +2 -0
- package/dist/cjs/types/components/TabBox.d.ts +1 -0
- package/dist/cjs/types/helpers/genRouteHandler.d.ts +10 -10
- package/dist/cjs/types/helpers/getWordCount.d.ts +10 -0
- package/dist/cjs/types/helpers/visitEndpointOnAnotherServer/index.d.ts +13 -15
- package/dist/cjs/types/helpers/visitEndpointOnAnotherServer/sendServerToServerRequest.d.ts +6 -0
- package/dist/cjs/types/index.d.ts +2 -3
- package/dist/cjs/types/server/initServer.d.ts +0 -11
- package/dist/cjs/types/types/ReactKitErrorCode.d.ts +1 -13
- package/dist/esm/index.js +357 -406
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/esm/types/components/Modal/ModalProps.d.ts +2 -0
- package/dist/esm/types/components/TabBox.d.ts +1 -0
- package/dist/esm/types/helpers/genRouteHandler.d.ts +10 -10
- package/dist/esm/types/helpers/getWordCount.d.ts +10 -0
- package/dist/esm/types/helpers/visitEndpointOnAnotherServer/index.d.ts +13 -15
- package/dist/esm/types/helpers/visitEndpointOnAnotherServer/sendServerToServerRequest.d.ts +6 -0
- package/dist/esm/types/index.d.ts +2 -3
- package/dist/esm/types/server/initServer.d.ts +0 -11
- package/dist/esm/types/types/ReactKitErrorCode.d.ts +1 -13
- package/dist/index.d.ts +39 -62
- package/package.json +2 -5
- package/src/components/IntelliTable.tsx +1 -1
- package/src/components/ItemPicker/NestableItemList.tsx +1 -0
- package/src/components/ItemPicker/index.tsx +96 -0
- package/src/components/Modal/ModalProps.ts +4 -0
- package/src/components/Modal/index.tsx +59 -20
- package/src/components/TabBox.tsx +27 -9
- package/src/helpers/genRouteHandler.ts +95 -55
- package/src/helpers/getWordCount.ts +26 -0
- package/src/helpers/visitEndpointOnAnotherServer/index.ts +41 -42
- package/src/helpers/visitEndpointOnAnotherServer/sendServerToServerRequest.ts +5 -3
- package/src/index.ts +2 -4
- package/src/server/initServer.ts +0 -18
- package/src/types/ReactKitErrorCode.tsx +1 -13
- package/dist/cjs/types/helpers/dataSigner.d.ts +0 -38
- package/dist/cjs/types/server/initCrossServerCredentialCollection.d.ts +0 -8
- package/dist/cjs/types/types/CrossServerCredential.d.ts +0 -11
- package/dist/esm/types/helpers/dataSigner.d.ts +0 -38
- package/dist/esm/types/server/initCrossServerCredentialCollection.d.ts +0 -8
- package/dist/esm/types/types/CrossServerCredential.d.ts +0 -11
- package/genEncodedSecret.ts +0 -28
- package/src/helpers/dataSigner.ts +0 -232
- package/src/server/initCrossServerCredentialCollection.ts +0 -16
- package/src/types/CrossServerCredential.ts +0 -16
package/dist/esm/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default, { useState, useRef, useEffect, useReducer, forwardRef, useContext, useLayoutEffect, createContext, useMemo, useCallback, Component, Fragment } from 'react';
|
|
3
|
-
import { faExclamationTriangle,
|
|
3
|
+
import { faExclamationTriangle, faCircle, faHourglassEnd, faDotCircle, faCheckSquare, faHourglass, faClipboard, faChevronDown, faChevronRight, faCloudDownloadAlt, faMinus, faCheckCircle, faXmarkCircle, faSort, faSortDown, faSortUp, faCalendar, faTag, faHammer, faList, faTimes, faSave, faTrash, faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
|
|
4
4
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
5
5
|
import ReactDOM, { createPortal } from 'react-dom';
|
|
6
6
|
import { faCircle as faCircle$1, faSquareMinus, faSquare } from '@fortawesome/free-regular-svg-icons';
|
|
7
|
-
import { createHash } from 'crypto';
|
|
8
|
-
import jwt from 'jwt-simple';
|
|
9
7
|
import qs from 'qs';
|
|
10
8
|
|
|
11
9
|
/******************************************************************************
|
|
@@ -33,7 +31,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
33
31
|
});
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
// Highest error code =
|
|
34
|
+
// Highest error code = DRK18
|
|
37
35
|
/**
|
|
38
36
|
* List of error codes built into the react kit
|
|
39
37
|
* @author Gabe Abrams
|
|
@@ -59,18 +57,6 @@ var ReactKitErrorCode;
|
|
|
59
57
|
ReactKitErrorCode["NotConnected"] = "DRK14";
|
|
60
58
|
ReactKitErrorCode["SelfSigned"] = "DRK15";
|
|
61
59
|
ReactKitErrorCode["ResponseParseError"] = "DRK16";
|
|
62
|
-
ReactKitErrorCode["PackUnparseable"] = "DRK28";
|
|
63
|
-
ReactKitErrorCode["PackInvalidMethod"] = "DRK19";
|
|
64
|
-
ReactKitErrorCode["PackInvalidPath"] = "DRK20";
|
|
65
|
-
ReactKitErrorCode["PackInvalidCollection"] = "DRK21";
|
|
66
|
-
ReactKitErrorCode["PackInvalidCredential"] = "DRK23";
|
|
67
|
-
ReactKitErrorCode["PackInvalidScope"] = "DRK22";
|
|
68
|
-
ReactKitErrorCode["PackInvalidTimestamp"] = "DRK24";
|
|
69
|
-
ReactKitErrorCode["PackInvalidSignature"] = "DRK25";
|
|
70
|
-
ReactKitErrorCode["PackInvalidBody"] = "DRK26";
|
|
71
|
-
ReactKitErrorCode["CrossServerNoCredentialsToSignWith"] = "DRK27";
|
|
72
|
-
ReactKitErrorCode["CrossServerNoPack"] = "DRK29";
|
|
73
|
-
ReactKitErrorCode["CrossServerNoCredentialEncodingSalt"] = "DRK30";
|
|
74
60
|
})(ReactKitErrorCode || (ReactKitErrorCode = {}));
|
|
75
61
|
var ReactKitErrorCode$1 = ReactKitErrorCode;
|
|
76
62
|
|
|
@@ -202,6 +188,98 @@ const LogBuiltInMetadata = {
|
|
|
202
188
|
},
|
|
203
189
|
};
|
|
204
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Loading spinner/indicator
|
|
193
|
+
* @author Gabe Abrams
|
|
194
|
+
*/
|
|
195
|
+
/*------------------------------------------------------------------------*/
|
|
196
|
+
/* -------------------------------- Style ------------------------------- */
|
|
197
|
+
/*------------------------------------------------------------------------*/
|
|
198
|
+
const style$a = `
|
|
199
|
+
/* Container fades in */
|
|
200
|
+
.LoadingSpinner-container {
|
|
201
|
+
animation-name: LoadingSpinner-container-fade-in;
|
|
202
|
+
animation-duration: 0.3s;
|
|
203
|
+
animation-delay: 0.4s;
|
|
204
|
+
animation-fill-mode: both;
|
|
205
|
+
animation-timing-function: ease-out;
|
|
206
|
+
}
|
|
207
|
+
@keyframes LoadingSpinner-container-fade-in {
|
|
208
|
+
0% {
|
|
209
|
+
opacity: 0;
|
|
210
|
+
}
|
|
211
|
+
100% {
|
|
212
|
+
opacity: 1;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Blips */
|
|
217
|
+
.LoadingSpinner-blip-1,
|
|
218
|
+
.LoadingSpinner-blip-2,
|
|
219
|
+
.LoadingSpinner-blip-3,
|
|
220
|
+
.LoadingSpinner-blip-4 {
|
|
221
|
+
font-size: 1.8rem;
|
|
222
|
+
opacity: 0.6;
|
|
223
|
+
margin-top: 1rem;
|
|
224
|
+
margin-bottom: 1rem;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* First Blip */
|
|
228
|
+
.LoadingSpinner-blip-1 {
|
|
229
|
+
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Second Blip */
|
|
233
|
+
.LoadingSpinner-blip-2 {
|
|
234
|
+
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
235
|
+
-webkit-animation-delay: 0.1s;
|
|
236
|
+
animation-delay: 0.1s;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* Third Blip */
|
|
240
|
+
.LoadingSpinner-blip-3 {
|
|
241
|
+
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
242
|
+
animation-delay: 0.2s;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* Fourth Blip */
|
|
246
|
+
.LoadingSpinner-blip-4 {
|
|
247
|
+
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
248
|
+
animation-delay: 0.3s;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* Pop Animation for Each Blip */
|
|
252
|
+
@keyframes LoadingSpinner-pop-animation {
|
|
253
|
+
0% {
|
|
254
|
+
transform: scale(1.0);
|
|
255
|
+
}
|
|
256
|
+
10% {
|
|
257
|
+
transform: scale(1.5);
|
|
258
|
+
}
|
|
259
|
+
30% {
|
|
260
|
+
transform: scale(1.0);
|
|
261
|
+
}
|
|
262
|
+
100% {
|
|
263
|
+
transform: scale(1.0);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
`;
|
|
267
|
+
/*------------------------------------------------------------------------*/
|
|
268
|
+
/* ------------------------------ Component ----------------------------- */
|
|
269
|
+
/*------------------------------------------------------------------------*/
|
|
270
|
+
const LoadingSpinner = () => {
|
|
271
|
+
/*------------------------------------------------------------------------*/
|
|
272
|
+
/* ------------------------------- Render ------------------------------- */
|
|
273
|
+
/*------------------------------------------------------------------------*/
|
|
274
|
+
// Add all four blips to a container
|
|
275
|
+
return (React__default.createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
|
|
276
|
+
React__default.createElement("style", null, style$a),
|
|
277
|
+
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-1 me-1" }),
|
|
278
|
+
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-2 me-1" }),
|
|
279
|
+
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-3 me-1" }),
|
|
280
|
+
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-4" })));
|
|
281
|
+
};
|
|
282
|
+
|
|
205
283
|
/**
|
|
206
284
|
* Wait for a certain number of ms
|
|
207
285
|
* @author Gabe Abrams
|
|
@@ -334,6 +412,7 @@ const BASE_Z_INDEX = 1000000000;
|
|
|
334
412
|
const BASE_Z_INDEX_ON_TOP = 2000000000;
|
|
335
413
|
// Constants
|
|
336
414
|
const MS_TO_ANIMATE = 200; // Animation duration
|
|
415
|
+
const MS_TO_WAIT_BEFORE_SHOWING_LOADING_INDICATOR = 1000;
|
|
337
416
|
// Modal type to list of buttons
|
|
338
417
|
const modalTypeToModalButtonTypes = {
|
|
339
418
|
[ModalType$1.Okay]: [
|
|
@@ -447,7 +526,7 @@ const getNextUniqueId = () => {
|
|
|
447
526
|
/*------------------------------------------------------------------------*/
|
|
448
527
|
/* -------------------------------- Style ------------------------------- */
|
|
449
528
|
/*------------------------------------------------------------------------*/
|
|
450
|
-
const style$
|
|
529
|
+
const style$9 = `
|
|
451
530
|
.Modal-backdrop {
|
|
452
531
|
position: fixed;
|
|
453
532
|
top: 0;
|
|
@@ -519,13 +598,14 @@ const Modal = (props) => {
|
|
|
519
598
|
/*------------------------------------------------------------------------*/
|
|
520
599
|
var _a;
|
|
521
600
|
/* -------------- Props ------------- */
|
|
522
|
-
const { type = ModalType$1.NoButtons, size = ModalSize$1.Large, title, largeTitle, children, onClose, dontAllowBackdropExit, dontShowXButton, onTopOfOtherModals, } = props;
|
|
601
|
+
const { type = ModalType$1.NoButtons, size = ModalSize$1.Large, title, largeTitle, children, onClose, dontAllowBackdropExit, dontShowXButton, onTopOfOtherModals, isLoading, isLoadingCancelable, } = props;
|
|
523
602
|
// Determine if no header either
|
|
524
603
|
const noHeader = (!title && type === ModalType$1.NoButtons);
|
|
525
604
|
/* -------------- State ------------- */
|
|
526
605
|
// True if animation is in use
|
|
527
606
|
const [animatingIn, setAnimatingIn] = useState(true);
|
|
528
607
|
const [animatingPop, setAnimatingPop] = useState(false);
|
|
608
|
+
const [showModal, setShowModal] = useState(false);
|
|
529
609
|
/* -------------- Refs -------------- */
|
|
530
610
|
// Keep track of whether modal is still mounted
|
|
531
611
|
const mounted = useRef(false);
|
|
@@ -552,6 +632,16 @@ const Modal = (props) => {
|
|
|
552
632
|
if (mounted.current) {
|
|
553
633
|
setAnimatingIn(false);
|
|
554
634
|
}
|
|
635
|
+
if (isLoading) {
|
|
636
|
+
// wait before showing modal
|
|
637
|
+
yield waitMs(MS_TO_WAIT_BEFORE_SHOWING_LOADING_INDICATOR);
|
|
638
|
+
if (mounted.current) {
|
|
639
|
+
setShowModal(true);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
setShowModal(true);
|
|
644
|
+
}
|
|
555
645
|
}))();
|
|
556
646
|
return () => {
|
|
557
647
|
mounted.current = false;
|
|
@@ -618,6 +708,15 @@ const Modal = (props) => {
|
|
|
618
708
|
else if (animatingPop) {
|
|
619
709
|
animationClass = 'Modal-animating-pop';
|
|
620
710
|
}
|
|
711
|
+
// default to show close button when not loading and not show close button when loading
|
|
712
|
+
// unless downShowXButton or isLoadingCancelable
|
|
713
|
+
const showCloseButton = (
|
|
714
|
+
// The modal must have an onClose function
|
|
715
|
+
onClose
|
|
716
|
+
// ...and the close button is allowed to be visible
|
|
717
|
+
&& !dontShowXButton
|
|
718
|
+
// ...and should not be shown if the modal is loading and not cancelable
|
|
719
|
+
&& !(isLoading && !isLoadingCancelable));
|
|
621
720
|
// Render the modal
|
|
622
721
|
const contentToRender = (React__default.createElement("div", { className: "modal show", tabIndex: -1, style: {
|
|
623
722
|
zIndex: baseZIndex,
|
|
@@ -626,7 +725,7 @@ const Modal = (props) => {
|
|
|
626
725
|
left: 0,
|
|
627
726
|
right: 0,
|
|
628
727
|
} },
|
|
629
|
-
React__default.createElement("style", null, style$
|
|
728
|
+
React__default.createElement("style", null, style$9),
|
|
630
729
|
React__default.createElement("div", { className: `Modal-backdrop ${backdropAnimationClass}`, style: {
|
|
631
730
|
zIndex: baseZIndex + 1,
|
|
632
731
|
}, onClick: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -644,7 +743,7 @@ const Modal = (props) => {
|
|
|
644
743
|
// Handle close
|
|
645
744
|
handleClose(ModalButtonType$1.Cancel);
|
|
646
745
|
}) }),
|
|
647
|
-
React__default.createElement("div", { className: `modal-dialog modal-${size} ${animationClass} modal-dialog-scrollable modal-dialog-centered`, style: {
|
|
746
|
+
showModal && (React__default.createElement("div", { className: `modal-dialog modal-${size} ${animationClass} modal-dialog-scrollable modal-dialog-centered`, style: {
|
|
648
747
|
zIndex: baseZIndex + 2,
|
|
649
748
|
// Override sizes for even larger for XL
|
|
650
749
|
width: (size === ModalSize$1.ExtraLarge
|
|
@@ -676,7 +775,7 @@ const Modal = (props) => {
|
|
|
676
775
|
? '1.6rem'
|
|
677
776
|
: undefined),
|
|
678
777
|
} }, title),
|
|
679
|
-
|
|
778
|
+
showCloseButton && (React__default.createElement("button", { type: "button", className: "Modal-x-button btn-close", "aria-label": "Close", style: {
|
|
680
779
|
backgroundColor: (isDarkModeOn()
|
|
681
780
|
? 'white'
|
|
682
781
|
: undefined),
|
|
@@ -684,14 +783,18 @@ const Modal = (props) => {
|
|
|
684
783
|
// Handle close
|
|
685
784
|
handleClose(ModalButtonType$1.Cancel);
|
|
686
785
|
} })))),
|
|
687
|
-
|
|
786
|
+
React__default.createElement("div", { className: "modal-body", style: {
|
|
688
787
|
color: (isDarkModeOn()
|
|
689
788
|
? 'white'
|
|
690
789
|
: undefined),
|
|
691
790
|
backgroundColor: (isDarkModeOn()
|
|
692
791
|
? '#444'
|
|
693
792
|
: undefined),
|
|
694
|
-
} },
|
|
793
|
+
} }, isLoading
|
|
794
|
+
? (React__default.createElement(React__default.Fragment, null,
|
|
795
|
+
React__default.createElement(LoadingSpinner, null),
|
|
796
|
+
React__default.createElement("span", { className: "sr-only" }, "Content loading")))
|
|
797
|
+
: children),
|
|
695
798
|
footer && (React__default.createElement("div", { className: "modal-footer pt-1 pb-1", style: {
|
|
696
799
|
color: (isDarkModeOn()
|
|
697
800
|
? 'white'
|
|
@@ -702,7 +805,7 @@ const Modal = (props) => {
|
|
|
702
805
|
borderTop: (isDarkModeOn()
|
|
703
806
|
? '0.1rem solid gray'
|
|
704
807
|
: undefined),
|
|
705
|
-
} }, footer))))));
|
|
808
|
+
} }, footer)))))));
|
|
706
809
|
// Determine which portal to use
|
|
707
810
|
const portalNumber = id.current % NUM_MODAL_PORTALS;
|
|
708
811
|
// Render in a portal
|
|
@@ -1269,7 +1372,7 @@ const showSessionExpiredMessage = () => __awaiter(void 0, void 0, void 0, functi
|
|
|
1269
1372
|
/*------------------------------------------------------------------------*/
|
|
1270
1373
|
/* -------------------------------- Style ------------------------------- */
|
|
1271
1374
|
/*------------------------------------------------------------------------*/
|
|
1272
|
-
const style$
|
|
1375
|
+
const style$8 = `
|
|
1273
1376
|
.AppWrapper-leave-to-url-notice {
|
|
1274
1377
|
opacity: 0;
|
|
1275
1378
|
|
|
@@ -1483,105 +1586,13 @@ const AppWrapper = (props) => {
|
|
|
1483
1586
|
/* --------------- Main UI -------------- */
|
|
1484
1587
|
/*----------------------------------------*/
|
|
1485
1588
|
return (React__default.createElement(React__default.Fragment, null,
|
|
1486
|
-
React__default.createElement("style", null, style$
|
|
1589
|
+
React__default.createElement("style", null, style$8),
|
|
1487
1590
|
React__default.createElement("style", null, tooltipStyle),
|
|
1488
1591
|
modal,
|
|
1489
1592
|
customModalPortals,
|
|
1490
1593
|
body));
|
|
1491
1594
|
};
|
|
1492
1595
|
|
|
1493
|
-
/**
|
|
1494
|
-
* Loading spinner/indicator
|
|
1495
|
-
* @author Gabe Abrams
|
|
1496
|
-
*/
|
|
1497
|
-
/*------------------------------------------------------------------------*/
|
|
1498
|
-
/* -------------------------------- Style ------------------------------- */
|
|
1499
|
-
/*------------------------------------------------------------------------*/
|
|
1500
|
-
const style$8 = `
|
|
1501
|
-
/* Container fades in */
|
|
1502
|
-
.LoadingSpinner-container {
|
|
1503
|
-
animation-name: LoadingSpinner-container-fade-in;
|
|
1504
|
-
animation-duration: 0.3s;
|
|
1505
|
-
animation-delay: 0.4s;
|
|
1506
|
-
animation-fill-mode: both;
|
|
1507
|
-
animation-timing-function: ease-out;
|
|
1508
|
-
}
|
|
1509
|
-
@keyframes LoadingSpinner-container-fade-in {
|
|
1510
|
-
0% {
|
|
1511
|
-
opacity: 0;
|
|
1512
|
-
}
|
|
1513
|
-
100% {
|
|
1514
|
-
opacity: 1;
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
/* Blips */
|
|
1519
|
-
.LoadingSpinner-blip-1,
|
|
1520
|
-
.LoadingSpinner-blip-2,
|
|
1521
|
-
.LoadingSpinner-blip-3,
|
|
1522
|
-
.LoadingSpinner-blip-4 {
|
|
1523
|
-
font-size: 1.8rem;
|
|
1524
|
-
opacity: 0.6;
|
|
1525
|
-
margin-top: 1rem;
|
|
1526
|
-
margin-bottom: 1rem;
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
/* First Blip */
|
|
1530
|
-
.LoadingSpinner-blip-1 {
|
|
1531
|
-
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
/* Second Blip */
|
|
1535
|
-
.LoadingSpinner-blip-2 {
|
|
1536
|
-
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
1537
|
-
-webkit-animation-delay: 0.1s;
|
|
1538
|
-
animation-delay: 0.1s;
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
/* Third Blip */
|
|
1542
|
-
.LoadingSpinner-blip-3 {
|
|
1543
|
-
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
1544
|
-
animation-delay: 0.2s;
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
/* Fourth Blip */
|
|
1548
|
-
.LoadingSpinner-blip-4 {
|
|
1549
|
-
animation: LoadingSpinner-pop-animation 2s infinite;
|
|
1550
|
-
animation-delay: 0.3s;
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
/* Pop Animation for Each Blip */
|
|
1554
|
-
@keyframes LoadingSpinner-pop-animation {
|
|
1555
|
-
0% {
|
|
1556
|
-
transform: scale(1.0);
|
|
1557
|
-
}
|
|
1558
|
-
10% {
|
|
1559
|
-
transform: scale(1.5);
|
|
1560
|
-
}
|
|
1561
|
-
30% {
|
|
1562
|
-
transform: scale(1.0);
|
|
1563
|
-
}
|
|
1564
|
-
100% {
|
|
1565
|
-
transform: scale(1.0);
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
`;
|
|
1569
|
-
/*------------------------------------------------------------------------*/
|
|
1570
|
-
/* ------------------------------ Component ----------------------------- */
|
|
1571
|
-
/*------------------------------------------------------------------------*/
|
|
1572
|
-
const LoadingSpinner = () => {
|
|
1573
|
-
/*------------------------------------------------------------------------*/
|
|
1574
|
-
/* ------------------------------- Render ------------------------------- */
|
|
1575
|
-
/*------------------------------------------------------------------------*/
|
|
1576
|
-
// Add all four blips to a container
|
|
1577
|
-
return (React__default.createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
|
|
1578
|
-
React__default.createElement("style", null, style$8),
|
|
1579
|
-
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-1 me-1" }),
|
|
1580
|
-
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-2 me-1" }),
|
|
1581
|
-
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-3 me-1" }),
|
|
1582
|
-
React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-4" })));
|
|
1583
|
-
};
|
|
1584
|
-
|
|
1585
1596
|
/**
|
|
1586
1597
|
* A box with a tab on the top that holds buttons and other content
|
|
1587
1598
|
* @author Gabe Abrams
|
|
@@ -1613,7 +1624,9 @@ const style$7 = `
|
|
|
1613
1624
|
|
|
1614
1625
|
/* Container for Title */
|
|
1615
1626
|
.TabBox-title-container {
|
|
1616
|
-
|
|
1627
|
+
display: flex;
|
|
1628
|
+
justify-content: space-between;
|
|
1629
|
+
align-items: center;
|
|
1617
1630
|
position: relative;
|
|
1618
1631
|
left: 0;
|
|
1619
1632
|
text-align: left;
|
|
@@ -1646,6 +1659,19 @@ const style$7 = `
|
|
|
1646
1659
|
background: #fdfdfd;
|
|
1647
1660
|
}
|
|
1648
1661
|
|
|
1662
|
+
.TabBox-title-right-container {
|
|
1663
|
+
display: flex;
|
|
1664
|
+
flex-direction: row;
|
|
1665
|
+
align-items: bottom;
|
|
1666
|
+
height: 2.4rem;
|
|
1667
|
+
overflow: visible;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
.TabBox-title-right-contents {
|
|
1671
|
+
margin-right: 0.5rem;
|
|
1672
|
+
margin-bottom: 0.2rem;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1649
1675
|
/* Make the TabBox's Children Appear Above Title if Overlap Occurs */
|
|
1650
1676
|
.TabBox-children {
|
|
1651
1677
|
position: relative;
|
|
@@ -1659,19 +1685,16 @@ const TabBox = (props) => {
|
|
|
1659
1685
|
/*------------------------------------------------------------------------*/
|
|
1660
1686
|
/* -------------------------------- Setup ------------------------------- */
|
|
1661
1687
|
/*------------------------------------------------------------------------*/
|
|
1662
|
-
|
|
1663
|
-
const { title, children, noBottomPadding, noBottomMargin, } = props;
|
|
1688
|
+
const { title, children, topRightChildren, noBottomPadding, noBottomMargin, } = props;
|
|
1664
1689
|
/*------------------------------------------------------------------------*/
|
|
1665
1690
|
/* ------------------------------- Render ------------------------------- */
|
|
1666
1691
|
/*------------------------------------------------------------------------*/
|
|
1667
|
-
/*----------------------------------------*/
|
|
1668
|
-
/* --------------- Main UI -------------- */
|
|
1669
|
-
/*----------------------------------------*/
|
|
1670
|
-
// Full UI
|
|
1671
1692
|
return (React__default.createElement("div", { className: `TabBox-container ${noBottomMargin ? '' : 'mb-2'}` },
|
|
1672
1693
|
React__default.createElement("style", null, style$7),
|
|
1673
1694
|
React__default.createElement("div", { className: "TabBox-title-container" },
|
|
1674
|
-
React__default.createElement("div", { className: "TabBox-title" }, title)
|
|
1695
|
+
React__default.createElement("div", { className: "TabBox-title" }, title),
|
|
1696
|
+
topRightChildren && (React__default.createElement("div", { className: "TabBox-title-right-container" },
|
|
1697
|
+
React__default.createElement("div", { className: "TabBox-title-right-contents" }, topRightChildren)))),
|
|
1675
1698
|
React__default.createElement("div", { className: `TabBox-box ps-2 pt-2 pe-2 ${noBottomPadding ? '' : 'pb-2'}` },
|
|
1676
1699
|
React__default.createElement("div", { className: "TabBox-children" }, children))));
|
|
1677
1700
|
};
|
|
@@ -2658,7 +2681,7 @@ const NestableItemList = (props) => {
|
|
|
2658
2681
|
React__default.createElement(FontAwesomeIcon, { icon: childExpanded[item.id] ? faChevronDown : faChevronRight })))),
|
|
2659
2682
|
React__default.createElement(CheckboxButton, { className: `NestableItemList-CheckboxButton-${item.id}`, text: item.name, checked: item.isGroup ? allChecked(item.children) : item.checked, dashed: item.isGroup ? !noneChecked(item.children) : false, onChanged: (checked) => {
|
|
2660
2683
|
onChanged(changeChecked(item.id, checked, items));
|
|
2661
|
-
}, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$1.Light }),
|
|
2684
|
+
}, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$1.Light, uncheckedVariant: Variant$1.Light }),
|
|
2662
2685
|
(item.isGroup && childExpanded[item.id]) && (React__default.createElement("div", { className: "NestableItemList-children-container", style: {
|
|
2663
2686
|
paddingLeft: '2.2rem',
|
|
2664
2687
|
} },
|
|
@@ -2681,17 +2704,62 @@ const ItemPicker = (props) => {
|
|
|
2681
2704
|
/*------------------------------------------------------------------------*/
|
|
2682
2705
|
/* -------------- Props ------------- */
|
|
2683
2706
|
// Destructure all props
|
|
2684
|
-
const { title, items, onChanged, noBottomMargin, } = props;
|
|
2707
|
+
const { title, items, onChanged, noBottomMargin, hideSelectAllOrNoneButtons, } = props;
|
|
2685
2708
|
/*------------------------------------------------------------------------*/
|
|
2686
2709
|
/* ------------------------- Component Functions ------------------------ */
|
|
2687
2710
|
/*------------------------------------------------------------------------*/
|
|
2711
|
+
/**
|
|
2712
|
+
* Updates the checked state of an item (including all children)
|
|
2713
|
+
* @author Yuen Ler Chow
|
|
2714
|
+
* @param item the item to update
|
|
2715
|
+
* @param checked the new checked state
|
|
2716
|
+
* @returns the updated item
|
|
2717
|
+
*/
|
|
2718
|
+
const updateItemChecked = (item, checked) => {
|
|
2719
|
+
if (item.isGroup) {
|
|
2720
|
+
return Object.assign(Object.assign({}, item), { children: item.children.map((child) => {
|
|
2721
|
+
return updateItemChecked(child, checked);
|
|
2722
|
+
}) });
|
|
2723
|
+
}
|
|
2724
|
+
return Object.assign(Object.assign({}, item), { checked });
|
|
2725
|
+
};
|
|
2726
|
+
/**
|
|
2727
|
+
* Selects all items in the list
|
|
2728
|
+
* @author Yuen Ler Chow
|
|
2729
|
+
*/
|
|
2730
|
+
const handleSelectAll = () => {
|
|
2731
|
+
const updatedItems = items.map((item) => {
|
|
2732
|
+
return updateItemChecked(item, true);
|
|
2733
|
+
});
|
|
2734
|
+
onChanged(updatedItems);
|
|
2735
|
+
};
|
|
2736
|
+
/**
|
|
2737
|
+
* Deselects all items in the list
|
|
2738
|
+
* @author Yuen Ler Chow
|
|
2739
|
+
*/
|
|
2740
|
+
const handleDeselectAll = () => {
|
|
2741
|
+
const updatedItems = items.map((item) => {
|
|
2742
|
+
return updateItemChecked(item, false);
|
|
2743
|
+
});
|
|
2744
|
+
onChanged(updatedItems);
|
|
2745
|
+
};
|
|
2688
2746
|
/*------------------------------------------------------------------------*/
|
|
2689
2747
|
/* ------------------------------- Render ------------------------------- */
|
|
2690
2748
|
/*------------------------------------------------------------------------*/
|
|
2691
2749
|
/*----------------------------------------*/
|
|
2692
2750
|
/* --------------- Main UI -------------- */
|
|
2693
2751
|
/*----------------------------------------*/
|
|
2694
|
-
|
|
2752
|
+
// Select all/none
|
|
2753
|
+
const selectAllOrNone = (!hideSelectAllOrNoneButtons
|
|
2754
|
+
? (React__default.createElement("div", { className: "d-flex h-100 align-items-end flex-row" },
|
|
2755
|
+
React__default.createElement("div", { className: "d-flex justify-content-end" },
|
|
2756
|
+
React__default.createElement("div", { className: "me-2", style: { fontSize: '1.2rem' } }, "Select"),
|
|
2757
|
+
React__default.createElement("div", { className: "btn-group", role: "group" },
|
|
2758
|
+
React__default.createElement("button", { type: "button", style: { borderRight: '0.1rem solid white' }, "aria-label": "Select all contexts", className: "btn btn-secondary py-0", onClick: handleSelectAll }, "All"),
|
|
2759
|
+
React__default.createElement("button", { type: "button", "aria-label": "Deselect all contexts", className: "btn btn-secondary py-0", onClick: handleDeselectAll }, "None")))))
|
|
2760
|
+
: undefined);
|
|
2761
|
+
// Main UI
|
|
2762
|
+
return (React__default.createElement(TabBox, { title: title, noBottomMargin: noBottomMargin, topRightChildren: selectAllOrNone },
|
|
2695
2763
|
React__default.createElement("div", { style: { overflowX: 'auto' } },
|
|
2696
2764
|
React__default.createElement(NestableItemList, { items: items, onChanged: onChanged }))));
|
|
2697
2765
|
};
|
|
@@ -3063,7 +3131,7 @@ const IntelliTable = (props) => {
|
|
|
3063
3131
|
param: column.param,
|
|
3064
3132
|
visible: checked,
|
|
3065
3133
|
});
|
|
3066
|
-
}, checked: columnVisibilityMap[column.param], ariaLabel: `show "${column.title}" column in the ${title} table`, checkedVariant: Variant$1.Light, uncheckedVariant: Variant$1.
|
|
3134
|
+
}, checked: columnVisibilityMap[column.param], ariaLabel: `show "${column.title}" column in the ${title} table`, checkedVariant: Variant$1.Light, uncheckedVariant: Variant$1.Light }));
|
|
3067
3135
|
}),
|
|
3068
3136
|
React__default.createElement("div", { className: "mt-3" }, "Or you can:"),
|
|
3069
3137
|
React__default.createElement("button", { type: "button", id: `IntelliTable-${id}-select-all-columns`, className: "btn btn-secondary me-2", "aria-label": `show all columns in the ${title} table`, onClick: () => {
|
|
@@ -14035,8 +14103,6 @@ const LOG_REVIEW_STATUS_ROUTE = `${ROUTE_PATH_PREFIX}/logs/access_allowed`;
|
|
|
14035
14103
|
let _cacclGetLaunchInfo;
|
|
14036
14104
|
// Stored copy of dce-mango log collection
|
|
14037
14105
|
let _logCollection;
|
|
14038
|
-
// Stored copy of dce-mango cross-server credential collection
|
|
14039
|
-
let _crossServerCredentialCollection;
|
|
14040
14106
|
/*------------------------------------------------------------------------*/
|
|
14041
14107
|
/* Helpers */
|
|
14042
14108
|
/*------------------------------------------------------------------------*/
|
|
@@ -14061,15 +14127,6 @@ const cacclGetLaunchInfo = (req) => {
|
|
|
14061
14127
|
const internalGetLogCollection = () => {
|
|
14062
14128
|
return _logCollection !== null && _logCollection !== void 0 ? _logCollection : null;
|
|
14063
14129
|
};
|
|
14064
|
-
/**
|
|
14065
|
-
* Get cross-server credential collection
|
|
14066
|
-
* @author Gabe Abrams
|
|
14067
|
-
* @return cross-server credential collection if one was included during launch or null
|
|
14068
|
-
* if we don't have a cross-server credential collection (yet)
|
|
14069
|
-
*/
|
|
14070
|
-
const internalGetCrossServerCredentialCollection = () => {
|
|
14071
|
-
return _crossServerCredentialCollection !== null && _crossServerCredentialCollection !== void 0 ? _crossServerCredentialCollection : null;
|
|
14072
|
-
};
|
|
14073
14130
|
/*------------------------------------------------------------------------*/
|
|
14074
14131
|
/* Main */
|
|
14075
14132
|
/*------------------------------------------------------------------------*/
|
|
@@ -14089,14 +14146,10 @@ const internalGetCrossServerCredentialCollection = () => {
|
|
|
14089
14146
|
* userIds are allowed to review logs. If a dce-mango collection, only
|
|
14090
14147
|
* Canvas admins with entries in that collection ({ userId, ...}) are allowed
|
|
14091
14148
|
* to review logs
|
|
14092
|
-
* @param [opts.crossServerCredentialCollection] mongo collection from dce-mango to use for
|
|
14093
|
-
* storing cross-server credentials. If none is included, cross-server credentials
|
|
14094
|
-
* are not supported
|
|
14095
14149
|
*/
|
|
14096
14150
|
const initServer = (opts) => {
|
|
14097
14151
|
_cacclGetLaunchInfo = opts.getLaunchInfo;
|
|
14098
14152
|
_logCollection = opts.logCollection;
|
|
14099
|
-
_crossServerCredentialCollection = opts.crossServerCredentialCollection;
|
|
14100
14153
|
/*----------------------------------------*/
|
|
14101
14154
|
/* Logging */
|
|
14102
14155
|
/*----------------------------------------*/
|
|
@@ -14639,154 +14692,6 @@ const parseUserAgent = (userAgent) => {
|
|
|
14639
14692
|
};
|
|
14640
14693
|
};
|
|
14641
14694
|
|
|
14642
|
-
/*------------------------------------------------------------------------*/
|
|
14643
|
-
/* ------------------------------ Encoding ------------------------------ */
|
|
14644
|
-
/*------------------------------------------------------------------------*/
|
|
14645
|
-
/**
|
|
14646
|
-
* Validate a JWT token
|
|
14647
|
-
* @author Gabe Abrams
|
|
14648
|
-
* @param encodedSecret the encoded secret
|
|
14649
|
-
* @return the secret
|
|
14650
|
-
*/
|
|
14651
|
-
const decodeCredentialSecret = (encodedSecret) => {
|
|
14652
|
-
// Get the credential encoding salt
|
|
14653
|
-
const credentialEncodingSalt = process.env.REACTKIT_CRED_ENCODING_SALT;
|
|
14654
|
-
if (!credentialEncodingSalt) {
|
|
14655
|
-
throw new ErrorWithCode('Cannot decode a cross-server credential secret because the credential encoding salt was not found in env.', ReactKitErrorCode$1.CrossServerNoCredentialEncodingSalt);
|
|
14656
|
-
}
|
|
14657
|
-
// Decode the secret
|
|
14658
|
-
return jwt.decode(encodedSecret, credentialEncodingSalt);
|
|
14659
|
-
};
|
|
14660
|
-
/*------------------------------------------------------------------------*/
|
|
14661
|
-
/* ------------------------------- Signing ------------------------------ */
|
|
14662
|
-
/*------------------------------------------------------------------------*/
|
|
14663
|
-
/**
|
|
14664
|
-
* Sign using sha 256
|
|
14665
|
-
* @author Gabe Abrams
|
|
14666
|
-
* @param opts object containing all arguments
|
|
14667
|
-
* @param opts.pack the pack to sign
|
|
14668
|
-
* @param opts.secret the reactkit secret to sign with
|
|
14669
|
-
* @return the signed hash
|
|
14670
|
-
*/
|
|
14671
|
-
const genSignature = (opts) => {
|
|
14672
|
-
// Generate signature
|
|
14673
|
-
return (createHash('sha256')
|
|
14674
|
-
.update(JSON.stringify({ pack: opts.pack, secret: opts.secret }))
|
|
14675
|
-
.digest('base64'));
|
|
14676
|
-
};
|
|
14677
|
-
/**
|
|
14678
|
-
* Sign data with a private reactkit key, package it into a signed data pack
|
|
14679
|
-
* @author Gabe Abrams
|
|
14680
|
-
* @param opts object containing all arguments
|
|
14681
|
-
* @param opts.method the method to sign
|
|
14682
|
-
* @param opts.path the http request path
|
|
14683
|
-
* @param opts.params the data in the body to sign
|
|
14684
|
-
* @param opts.key the reactkit key to sign with
|
|
14685
|
-
* @param opts.secret the reactkit secret to sign with
|
|
14686
|
-
* @return the signed data
|
|
14687
|
-
*/
|
|
14688
|
-
const createSignedPack = (opts) => {
|
|
14689
|
-
// Create a timestamp
|
|
14690
|
-
const timestamp = Date.now();
|
|
14691
|
-
// Create the pack
|
|
14692
|
-
const pack = JSON.stringify({
|
|
14693
|
-
method: opts.method,
|
|
14694
|
-
path: opts.path,
|
|
14695
|
-
params: opts.params,
|
|
14696
|
-
key: opts.key,
|
|
14697
|
-
timestamp,
|
|
14698
|
-
});
|
|
14699
|
-
// Generate signature
|
|
14700
|
-
const signature = genSignature({
|
|
14701
|
-
pack,
|
|
14702
|
-
secret: opts.secret,
|
|
14703
|
-
});
|
|
14704
|
-
// Create a signed pack
|
|
14705
|
-
const signedPack = encodeURIComponent(JSON.stringify({
|
|
14706
|
-
pack,
|
|
14707
|
-
signature,
|
|
14708
|
-
}));
|
|
14709
|
-
// Return the signed pack
|
|
14710
|
-
return signedPack;
|
|
14711
|
-
};
|
|
14712
|
-
/**
|
|
14713
|
-
* Parse signed pack. Throws an error if invalid
|
|
14714
|
-
* @author Gabe Abrams
|
|
14715
|
-
* @param opts object containing all arguments
|
|
14716
|
-
* @param opts.method the method of the data validate
|
|
14717
|
-
* @param opts.path the http request path to validate
|
|
14718
|
-
* @param opts.scope the name of the scope to validate
|
|
14719
|
-
* @param opts.signedPack the signed data pack to validate
|
|
14720
|
-
* @returns parsed and validated params
|
|
14721
|
-
*/
|
|
14722
|
-
const parseSignedPack = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14723
|
-
// Extract signature
|
|
14724
|
-
let pack;
|
|
14725
|
-
let signature;
|
|
14726
|
-
let method;
|
|
14727
|
-
let path;
|
|
14728
|
-
let key;
|
|
14729
|
-
let timestamp;
|
|
14730
|
-
let params;
|
|
14731
|
-
try {
|
|
14732
|
-
({
|
|
14733
|
-
pack,
|
|
14734
|
-
signature,
|
|
14735
|
-
} = JSON.parse(decodeURIComponent(opts.signedPack)));
|
|
14736
|
-
// Unpack
|
|
14737
|
-
({
|
|
14738
|
-
method,
|
|
14739
|
-
path,
|
|
14740
|
-
params,
|
|
14741
|
-
key,
|
|
14742
|
-
timestamp,
|
|
14743
|
-
} = JSON.parse(pack));
|
|
14744
|
-
}
|
|
14745
|
-
catch (err) {
|
|
14746
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the request could not be parsed.', ReactKitErrorCode$1.PackUnparseable);
|
|
14747
|
-
}
|
|
14748
|
-
// Make sure the method and path match
|
|
14749
|
-
if (method !== opts.method) {
|
|
14750
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the method did not match.', ReactKitErrorCode$1.PackInvalidMethod);
|
|
14751
|
-
}
|
|
14752
|
-
if (path !== opts.path) {
|
|
14753
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the path did not match.', ReactKitErrorCode$1.PackInvalidPath);
|
|
14754
|
-
}
|
|
14755
|
-
// Make sure the timestamp was recent enough
|
|
14756
|
-
const elapsedMs = Math.abs(Date.now() - timestamp);
|
|
14757
|
-
if (elapsedMs < MINUTE_IN_MS) {
|
|
14758
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the request was too old.', ReactKitErrorCode$1.PackInvalidTimestamp);
|
|
14759
|
-
}
|
|
14760
|
-
// Get the cross-server credential collection
|
|
14761
|
-
const crossServerCredentialCollection = internalGetCrossServerCredentialCollection();
|
|
14762
|
-
if (!crossServerCredentialCollection) {
|
|
14763
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the cross-server credential collection was not ready in time.', ReactKitErrorCode$1.PackInvalidCollection);
|
|
14764
|
-
}
|
|
14765
|
-
// Get the cross-server credential
|
|
14766
|
-
const crossServerCredential = yield crossServerCredentialCollection.find({ key });
|
|
14767
|
-
if (!crossServerCredential) {
|
|
14768
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the credential was not found.', ReactKitErrorCode$1.PackInvalidCredential);
|
|
14769
|
-
}
|
|
14770
|
-
// Make sure the scope is included
|
|
14771
|
-
const allowedScopes = crossServerCredential.scopes;
|
|
14772
|
-
if (!allowedScopes.includes(opts.scope)) {
|
|
14773
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the scope was not included.', ReactKitErrorCode$1.PackInvalidScope);
|
|
14774
|
-
}
|
|
14775
|
-
// Decode the secret
|
|
14776
|
-
const secret = decodeCredentialSecret(crossServerCredential.encodedeSecret);
|
|
14777
|
-
// Generate signature
|
|
14778
|
-
const expectedSignature = genSignature({
|
|
14779
|
-
pack,
|
|
14780
|
-
secret,
|
|
14781
|
-
});
|
|
14782
|
-
// Make sure the signature matches
|
|
14783
|
-
if (signature !== expectedSignature) {
|
|
14784
|
-
throw new ErrorWithCode('Could not validate a cross-server request because the signature did not match.', ReactKitErrorCode$1.PackInvalidSignature);
|
|
14785
|
-
}
|
|
14786
|
-
// Return body
|
|
14787
|
-
return params !== null && params !== void 0 ? params : {};
|
|
14788
|
-
});
|
|
14789
|
-
|
|
14790
14695
|
/**
|
|
14791
14696
|
* Generate an express API route handler
|
|
14792
14697
|
* @author Gabe Abrams
|
|
@@ -14794,15 +14699,14 @@ const parseSignedPack = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
14794
14699
|
* @param opts.paramTypes map containing the types for each parameter that is
|
|
14795
14700
|
* included in the request (map: param name => type)
|
|
14796
14701
|
* @param opts.handler function that processes the request
|
|
14797
|
-
* @param [opts.
|
|
14798
|
-
*
|
|
14799
|
-
*
|
|
14800
|
-
*
|
|
14801
|
-
*
|
|
14802
|
-
*
|
|
14803
|
-
*
|
|
14804
|
-
*
|
|
14805
|
-
* If crossServerScope is defined, this is always true
|
|
14702
|
+
* @param [opts.skipSessionCheck] if true, skip the session check (allow users
|
|
14703
|
+
* to not be logged in and launched via LTI)
|
|
14704
|
+
* @param [opts.allowedHosts] if included, only allow requests from these hosts
|
|
14705
|
+
* (start a hostname with a "*" to only check the end of the hostname)
|
|
14706
|
+
* you can include just one string instead of an array
|
|
14707
|
+
* @param [opts.bannedHosts] if included, do not allow requests from these hosts
|
|
14708
|
+
* (start a hostname with a "*" to only check the end of the hostname)
|
|
14709
|
+
* you can include just one string instead of an array
|
|
14806
14710
|
* @param [opts.unhandledErrorMessagePrefix] if included, when an error that
|
|
14807
14711
|
* is not of type ErrorWithCode is thrown, the client will receive an error
|
|
14808
14712
|
* where the error message is prefixed with this string. For example,
|
|
@@ -14830,51 +14734,86 @@ const parseSignedPack = (opts) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
14830
14734
|
const genRouteHandler = (opts) => {
|
|
14831
14735
|
// Return a route handler
|
|
14832
14736
|
return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14833
|
-
|
|
14834
|
-
/* ------------- Preparation ------------ */
|
|
14835
|
-
/*----------------------------------------*/
|
|
14836
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
14737
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
14837
14738
|
// Output params
|
|
14838
14739
|
const output = {};
|
|
14839
|
-
// Determine cross server scopes
|
|
14840
|
-
let crossServerScope = null;
|
|
14841
|
-
if (opts.crossServerScope) {
|
|
14842
|
-
crossServerScope = (_a = opts.crossServerScope) !== null && _a !== void 0 ? _a : null;
|
|
14843
|
-
}
|
|
14844
|
-
// Determine whether we're skipping the session check
|
|
14845
|
-
const skipSessionCheck = !!(opts.skipSessionCheck
|
|
14846
|
-
|| crossServerScope);
|
|
14847
|
-
// Get body from everywhere it can come from
|
|
14848
|
-
let requestBody = Object.assign(Object.assign(Object.assign({}, req.body), req.query), req.params);
|
|
14849
14740
|
/*----------------------------------------*/
|
|
14850
|
-
/*
|
|
14741
|
+
/* ----------- Hostname Check ----------- */
|
|
14851
14742
|
/*----------------------------------------*/
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14743
|
+
// Get hostnames
|
|
14744
|
+
const originURL = String(req.get('origin')
|
|
14745
|
+
|| req.headers.origin
|
|
14746
|
+
|| req.headers.referer);
|
|
14747
|
+
const originHostname = (originURL
|
|
14748
|
+
// Remove protocol
|
|
14749
|
+
.replace(/(^\w+:|^)\/\//, '')
|
|
14750
|
+
// Remove port
|
|
14751
|
+
.replace(/:\d+$/, ''));
|
|
14752
|
+
const serverHostname = String(req.hostname);
|
|
14753
|
+
// Check allowed
|
|
14754
|
+
if (opts.allowedHosts) {
|
|
14755
|
+
// Only accept requests from allowed hosts
|
|
14756
|
+
const allowedArray = (Array.isArray(opts.allowedHosts)
|
|
14757
|
+
? opts.allowedHosts
|
|
14758
|
+
: [opts.allowedHosts]);
|
|
14759
|
+
// Check if server is localhost
|
|
14760
|
+
if (serverHostname === 'localhost') {
|
|
14761
|
+
// Allow localhost
|
|
14762
|
+
allowedArray.push('localhost');
|
|
14763
|
+
}
|
|
14764
|
+
// Check if current host is allowed
|
|
14765
|
+
const allowed = allowedArray.some((allowedHost) => {
|
|
14766
|
+
if (allowedHost.startsWith('*')) {
|
|
14767
|
+
// Check end of hostname
|
|
14768
|
+
return originHostname.endsWith(allowedHost.substring(1));
|
|
14769
|
+
}
|
|
14770
|
+
// Check full hostname
|
|
14771
|
+
return originHostname.toLowerCase() === allowedHost.toLowerCase();
|
|
14772
|
+
});
|
|
14773
|
+
// If not allowed, return error
|
|
14774
|
+
if (!allowed) {
|
|
14775
|
+
return handleError(res, {
|
|
14776
|
+
message: 'You are not allowed to access this endpoint.',
|
|
14777
|
+
code: ReactKitErrorCode$1.HostNotAllowed,
|
|
14778
|
+
status: 403,
|
|
14779
|
+
});
|
|
14858
14780
|
}
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14781
|
+
}
|
|
14782
|
+
// Check banned
|
|
14783
|
+
if (opts.bannedHosts) {
|
|
14784
|
+
// Do not allow requests from banned hosts
|
|
14785
|
+
const bannedArray = (Array.isArray(opts.bannedHosts)
|
|
14786
|
+
? opts.bannedHosts
|
|
14787
|
+
: [opts.bannedHosts]);
|
|
14788
|
+
// Check if current host is banned
|
|
14789
|
+
const banned = bannedArray.some((bannedHost) => {
|
|
14790
|
+
if (bannedHost.startsWith('*')) {
|
|
14791
|
+
// Check end of hostname
|
|
14792
|
+
return originHostname.endsWith(bannedHost.substring(1));
|
|
14793
|
+
}
|
|
14794
|
+
// Check full hostname
|
|
14795
|
+
return originHostname.toLowerCase() === bannedHost.toLowerCase();
|
|
14865
14796
|
});
|
|
14866
|
-
//
|
|
14867
|
-
|
|
14797
|
+
// If banned, return error
|
|
14798
|
+
if (banned) {
|
|
14799
|
+
return handleError(res, {
|
|
14800
|
+
message: 'You are not allowed to access this endpoint.',
|
|
14801
|
+
code: ReactKitErrorCode$1.HostBanned,
|
|
14802
|
+
status: 403,
|
|
14803
|
+
});
|
|
14804
|
+
}
|
|
14868
14805
|
}
|
|
14869
14806
|
/*----------------------------------------*/
|
|
14870
14807
|
/* ------------ Parse Params ------------ */
|
|
14871
14808
|
/*----------------------------------------*/
|
|
14872
14809
|
// Process items one by one
|
|
14873
|
-
const paramList = Object.entries((
|
|
14810
|
+
const paramList = Object.entries((_a = opts.paramTypes) !== null && _a !== void 0 ? _a : {});
|
|
14874
14811
|
for (let i = 0; i < paramList.length; i++) {
|
|
14875
14812
|
const [name, type] = paramList[i];
|
|
14876
14813
|
// Find the value as a string
|
|
14877
|
-
const value =
|
|
14814
|
+
const value = (req.params[name]
|
|
14815
|
+
|| req.query[name]
|
|
14816
|
+
|| req.body[name]);
|
|
14878
14817
|
// Parse
|
|
14879
14818
|
if (type === ParamType$1.Boolean || type === ParamType$1.BooleanOptional) {
|
|
14880
14819
|
// Boolean
|
|
@@ -15032,7 +14971,7 @@ const genRouteHandler = (opts) => {
|
|
|
15032
14971
|
// Not launched
|
|
15033
14972
|
(!launched || !launchInfo)
|
|
15034
14973
|
// Not skipping the session check
|
|
15035
|
-
&& !skipSessionCheck) {
|
|
14974
|
+
&& !opts.skipSessionCheck) {
|
|
15036
14975
|
return handleError(res, {
|
|
15037
14976
|
message: 'Your session has expired. Please refresh the page and try again.',
|
|
15038
14977
|
code: ReactKitErrorCode$1.SessionExpired,
|
|
@@ -15052,7 +14991,7 @@ const genRouteHandler = (opts) => {
|
|
|
15052
14991
|
&& !launchInfo.isLearner
|
|
15053
14992
|
&& !launchInfo.isAdmin))
|
|
15054
14993
|
// Not skipping the session check
|
|
15055
|
-
&& !skipSessionCheck) {
|
|
14994
|
+
&& !opts.skipSessionCheck) {
|
|
15056
14995
|
return handleError(res, {
|
|
15057
14996
|
message: 'Your session was invalid. Please refresh the page and try again.',
|
|
15058
14997
|
code: ReactKitErrorCode$1.SessionExpired,
|
|
@@ -15062,34 +15001,34 @@ const genRouteHandler = (opts) => {
|
|
|
15062
15001
|
// Add launch info to output
|
|
15063
15002
|
output.userId = (launchInfo
|
|
15064
15003
|
? launchInfo.userId
|
|
15065
|
-
: ((
|
|
15004
|
+
: ((_b = output.userId) !== null && _b !== void 0 ? _b : undefined));
|
|
15066
15005
|
output.userFirstName = (launchInfo
|
|
15067
15006
|
? launchInfo.userFirstName
|
|
15068
|
-
: ((
|
|
15007
|
+
: ((_c = output.userFirstName) !== null && _c !== void 0 ? _c : undefined));
|
|
15069
15008
|
output.userLastName = (launchInfo
|
|
15070
15009
|
? launchInfo.userLastName
|
|
15071
|
-
: ((
|
|
15010
|
+
: ((_d = output.userLastName) !== null && _d !== void 0 ? _d : undefined));
|
|
15072
15011
|
output.userEmail = (launchInfo
|
|
15073
15012
|
? launchInfo.userEmail
|
|
15074
|
-
: ((
|
|
15013
|
+
: ((_e = output.userEmail) !== null && _e !== void 0 ? _e : undefined));
|
|
15075
15014
|
output.userAvatarURL = (launchInfo
|
|
15076
|
-
? ((
|
|
15077
|
-
: ((
|
|
15015
|
+
? ((_f = launchInfo.userImage) !== null && _f !== void 0 ? _f : 'http://www.gravatar.com/avatar/?d=identicon')
|
|
15016
|
+
: ((_g = output.userAvatarURL) !== null && _g !== void 0 ? _g : undefined));
|
|
15078
15017
|
output.isLearner = (launchInfo
|
|
15079
15018
|
? !!launchInfo.isLearner
|
|
15080
|
-
: ((
|
|
15019
|
+
: ((_h = output.isLearner) !== null && _h !== void 0 ? _h : undefined));
|
|
15081
15020
|
output.isTTM = (launchInfo
|
|
15082
15021
|
? !!launchInfo.isTTM
|
|
15083
|
-
: ((
|
|
15022
|
+
: ((_j = output.isTTM) !== null && _j !== void 0 ? _j : undefined));
|
|
15084
15023
|
output.isAdmin = (launchInfo
|
|
15085
15024
|
? !!launchInfo.isAdmin
|
|
15086
|
-
: ((
|
|
15025
|
+
: ((_k = output.isAdmin) !== null && _k !== void 0 ? _k : undefined));
|
|
15087
15026
|
output.courseId = (launchInfo
|
|
15088
|
-
? ((
|
|
15089
|
-
: ((
|
|
15027
|
+
? ((_l = output.courseId) !== null && _l !== void 0 ? _l : launchInfo.courseId)
|
|
15028
|
+
: ((_m = output.courseId) !== null && _m !== void 0 ? _m : undefined));
|
|
15090
15029
|
output.courseName = (launchInfo
|
|
15091
15030
|
? launchInfo.contextLabel
|
|
15092
|
-
: ((
|
|
15031
|
+
: ((_o = output.courseName) !== null && _o !== void 0 ? _o : undefined));
|
|
15093
15032
|
// Add other session variables
|
|
15094
15033
|
Object.keys(req.session).forEach((propName) => {
|
|
15095
15034
|
// Skip if prop already in output
|
|
@@ -15163,7 +15102,7 @@ const genRouteHandler = (opts) => {
|
|
|
15163
15102
|
* @author Gabe Abrams
|
|
15164
15103
|
*/
|
|
15165
15104
|
const logServerEvent = (logOpts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15166
|
-
var _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1
|
|
15105
|
+
var _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
|
|
15167
15106
|
// NOTE: internally, we slip through an opts.overrideAsClientEvent boolean
|
|
15168
15107
|
// that indicates that this is actually a client event, but we don't
|
|
15169
15108
|
// include that in the LogFunction type because this is internal and
|
|
@@ -15195,24 +15134,24 @@ const genRouteHandler = (opts) => {
|
|
|
15195
15134
|
timestamp,
|
|
15196
15135
|
context: (typeof logOpts.context === 'string'
|
|
15197
15136
|
? logOpts.context
|
|
15198
|
-
: ((
|
|
15199
|
-
subcontext: ((
|
|
15200
|
-
tags: ((
|
|
15201
|
-
level: ((
|
|
15202
|
-
metadata: ((
|
|
15137
|
+
: ((_q = ((_p = logOpts.context) !== null && _p !== void 0 ? _p : {})._) !== null && _q !== void 0 ? _q : LogBuiltInMetadata.Context.Uncategorized)),
|
|
15138
|
+
subcontext: ((_r = logOpts.subcontext) !== null && _r !== void 0 ? _r : LogBuiltInMetadata.Context.Uncategorized),
|
|
15139
|
+
tags: ((_s = logOpts.tags) !== null && _s !== void 0 ? _s : []),
|
|
15140
|
+
level: ((_t = logOpts.level) !== null && _t !== void 0 ? _t : LogLevel$1.Info),
|
|
15141
|
+
metadata: ((_u = logOpts.metadata) !== null && _u !== void 0 ? _u : {}),
|
|
15203
15142
|
};
|
|
15204
15143
|
// Type-specific info
|
|
15205
15144
|
const typeSpecificInfo = (('error' in opts && opts.error)
|
|
15206
15145
|
? {
|
|
15207
15146
|
type: LogType$1.Error,
|
|
15208
|
-
errorMessage: (
|
|
15209
|
-
errorCode: (
|
|
15210
|
-
errorStack: (
|
|
15147
|
+
errorMessage: (_v = logOpts.error.message) !== null && _v !== void 0 ? _v : 'Unknown message',
|
|
15148
|
+
errorCode: (_w = logOpts.error.code) !== null && _w !== void 0 ? _w : ReactKitErrorCode$1.NoCode,
|
|
15149
|
+
errorStack: (_x = logOpts.error.stack) !== null && _x !== void 0 ? _x : 'No stack',
|
|
15211
15150
|
}
|
|
15212
15151
|
: {
|
|
15213
15152
|
type: LogType$1.Action,
|
|
15214
|
-
target: ((
|
|
15215
|
-
action: ((
|
|
15153
|
+
target: ((_y = logOpts.target) !== null && _y !== void 0 ? _y : LogBuiltInMetadata.Target.NoTarget),
|
|
15154
|
+
action: ((_z = logOpts.action) !== null && _z !== void 0 ? _z : LogAction$1.Unknown),
|
|
15216
15155
|
});
|
|
15217
15156
|
// Source-specific info
|
|
15218
15157
|
const sourceSpecificInfo = (logOpts.overrideAsClientEvent
|
|
@@ -15247,7 +15186,7 @@ const genRouteHandler = (opts) => {
|
|
|
15247
15186
|
catch (err) {
|
|
15248
15187
|
// Print because we cannot store the error
|
|
15249
15188
|
// eslint-disable-next-line no-console
|
|
15250
|
-
console.error('Could not log the following:', logOpts, 'due to this error:', ((
|
|
15189
|
+
console.error('Could not log the following:', logOpts, 'due to this error:', ((_0 = err) !== null && _0 !== void 0 ? _0 : {}).message, ((_1 = err) !== null && _1 !== void 0 ? _1 : {}).stack);
|
|
15251
15190
|
// Create a dummy log to return
|
|
15252
15191
|
const dummyMainInfo = {
|
|
15253
15192
|
id: '-1',
|
|
@@ -15600,18 +15539,6 @@ const initLogCollection = (Collection) => {
|
|
|
15600
15539
|
});
|
|
15601
15540
|
};
|
|
15602
15541
|
|
|
15603
|
-
/**
|
|
15604
|
-
* Initialize a cross-server credential collection given the dce-mango Collection class
|
|
15605
|
-
* @author Gabe Abrams
|
|
15606
|
-
* @param Collection the Collection class from dce-mango
|
|
15607
|
-
* @returns initialized logCollection
|
|
15608
|
-
*/
|
|
15609
|
-
const initCrossServerCredentialCollection = (Collection) => {
|
|
15610
|
-
return new Collection('CrossServerCredential', {
|
|
15611
|
-
uniqueIndexKey: 'key',
|
|
15612
|
-
});
|
|
15613
|
-
};
|
|
15614
|
-
|
|
15615
15542
|
/*------------------------------------------------------------------------*/
|
|
15616
15543
|
/* -------------------------------- Cache ------------------------------- */
|
|
15617
15544
|
/*------------------------------------------------------------------------*/
|
|
@@ -16361,6 +16288,9 @@ const shuffleArray = (arr) => {
|
|
|
16361
16288
|
* @param [opts.host] host to send request to
|
|
16362
16289
|
* @param [opts.method=GET] http method to use
|
|
16363
16290
|
* @param [opts.params] body/data to include in the request
|
|
16291
|
+
* @param [opts.headers] headers to include in the request
|
|
16292
|
+
* @param [opts.sendCrossDomainCredentials=true if in development mode] if true,
|
|
16293
|
+
* send cross-domain credentials even if not in dev mode
|
|
16364
16294
|
* @param [opts.responseType=JSON] expected response type
|
|
16365
16295
|
* @returns { body, status, headers } on success
|
|
16366
16296
|
*/
|
|
@@ -16397,7 +16327,7 @@ const sendServerToServerRequest = (opts) => __awaiter(void 0, void 0, void 0, fu
|
|
|
16397
16327
|
url = `https://${opts.host}${opts.path}${query}`;
|
|
16398
16328
|
}
|
|
16399
16329
|
// Update headers
|
|
16400
|
-
const headers = {};
|
|
16330
|
+
const headers = opts.headers || {};
|
|
16401
16331
|
let data = null;
|
|
16402
16332
|
if (!headers['Content-Type']) {
|
|
16403
16333
|
// Form encoded
|
|
@@ -16470,49 +16400,49 @@ const sendServerToServerRequest = (opts) => __awaiter(void 0, void 0, void 0, fu
|
|
|
16470
16400
|
});
|
|
16471
16401
|
|
|
16472
16402
|
/**
|
|
16473
|
-
*
|
|
16403
|
+
* Send a server-to-server request from this sever to another server that uses
|
|
16404
|
+
* dce-reactkit [for server only]
|
|
16474
16405
|
* @author Gabe Abrams
|
|
16475
16406
|
* @param opts object containing all arguments
|
|
16476
|
-
* @param opts.
|
|
16477
|
-
* @param opts.path the path of the other server's endpoint
|
|
16478
|
-
* @param opts.
|
|
16479
|
-
* @param [opts.
|
|
16480
|
-
*
|
|
16481
|
-
* @
|
|
16482
|
-
* credential secret
|
|
16483
|
-
* @param [opts.params={}] query/body parameters to include
|
|
16484
|
-
* @param [opts.responseType=JSON] the response type from the other server
|
|
16407
|
+
* @param opts.host - the host of the other server
|
|
16408
|
+
* @param opts.path - the path of the other server's endpoint
|
|
16409
|
+
* @param [opts.method=GET] - the method of the endpoint
|
|
16410
|
+
* @param [opts.params] - query/body parameters to include
|
|
16411
|
+
* @param [opts.headers] - headers to include
|
|
16412
|
+
* @returns response from server
|
|
16485
16413
|
*/
|
|
16486
16414
|
const visitEndpointOnAnotherServer = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16487
|
-
var _a
|
|
16488
|
-
//
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16492
|
-
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
params
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16415
|
+
var _a;
|
|
16416
|
+
// Remove properties with undefined values
|
|
16417
|
+
let params;
|
|
16418
|
+
if (opts.params) {
|
|
16419
|
+
params = Object.fromEntries(Object
|
|
16420
|
+
.entries(opts.params)
|
|
16421
|
+
.filter(([, value]) => {
|
|
16422
|
+
return value !== undefined;
|
|
16423
|
+
}));
|
|
16424
|
+
}
|
|
16425
|
+
// Automatically JSONify arrays and objects
|
|
16426
|
+
if (params) {
|
|
16427
|
+
params = Object.fromEntries(Object
|
|
16428
|
+
.entries(params)
|
|
16429
|
+
.map(([key, value]) => {
|
|
16430
|
+
if (Array.isArray(value) || typeof value === 'object') {
|
|
16431
|
+
return [key, JSON.stringify(value)];
|
|
16432
|
+
}
|
|
16433
|
+
return [key, value];
|
|
16434
|
+
}));
|
|
16435
|
+
}
|
|
16503
16436
|
// Send the request
|
|
16504
16437
|
const response = yield sendServerToServerRequest({
|
|
16505
|
-
path: opts.path,
|
|
16506
16438
|
host: opts.host,
|
|
16507
|
-
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
},
|
|
16511
|
-
responseType: opts.responseType,
|
|
16439
|
+
path: opts.path,
|
|
16440
|
+
method: (_a = opts.method) !== null && _a !== void 0 ? _a : 'GET',
|
|
16441
|
+
params,
|
|
16512
16442
|
});
|
|
16513
16443
|
// Check for failure
|
|
16514
16444
|
if (!response || !response.body) {
|
|
16515
|
-
throw new ErrorWithCode('We didn\'t get a response from the
|
|
16445
|
+
throw new ErrorWithCode('We didn\'t get a response from the server. Please check your internet connection.', ReactKitErrorCode$1.NoResponse);
|
|
16516
16446
|
}
|
|
16517
16447
|
if (!response.body.success) {
|
|
16518
16448
|
// Other errors
|
|
@@ -16526,6 +16456,27 @@ const visitEndpointOnAnotherServer = (opts) => __awaiter(void 0, void 0, void 0,
|
|
|
16526
16456
|
return body;
|
|
16527
16457
|
});
|
|
16528
16458
|
|
|
16459
|
+
const punctuationRegex = /[!@#$%^&*(),.?\/;:'"\-\[\]]/g;
|
|
16460
|
+
/**
|
|
16461
|
+
* Get number of words in string
|
|
16462
|
+
* @author Gardenia Liu
|
|
16463
|
+
* @author Allison Zhang
|
|
16464
|
+
* @author Gabe Abrams
|
|
16465
|
+
* @param text the string to check
|
|
16466
|
+
* @returns number of words in the string
|
|
16467
|
+
*/
|
|
16468
|
+
const getWordCount = (text) => {
|
|
16469
|
+
const trimmedTextWithoutPunctuation = (text
|
|
16470
|
+
// Remove leading and trailing whitespace
|
|
16471
|
+
.trim()
|
|
16472
|
+
// Remove punctuation
|
|
16473
|
+
.replace(punctuationRegex, ''));
|
|
16474
|
+
if (trimmedTextWithoutPunctuation.length === 0) {
|
|
16475
|
+
return 0;
|
|
16476
|
+
}
|
|
16477
|
+
return trimmedTextWithoutPunctuation.split(/\s+/g).length;
|
|
16478
|
+
};
|
|
16479
|
+
|
|
16529
16480
|
/**
|
|
16530
16481
|
* Days of the week
|
|
16531
16482
|
* @author Gabe Abrams
|
|
@@ -16542,5 +16493,5 @@ var DayOfWeek;
|
|
|
16542
16493
|
})(DayOfWeek || (DayOfWeek = {}));
|
|
16543
16494
|
var DayOfWeek$1 = DayOfWeek;
|
|
16544
16495
|
|
|
16545
|
-
export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, DayOfWeek$1 as DayOfWeek, Drawer, Dropdown, DropdownItemType$1 as DropdownItemType, DynamicWord, ErrorBox, ErrorWithCode, HOUR_IN_MS, IntelliTable, ItemPicker, LoadingSpinner, LogAction$1 as LogAction, LogBuiltInMetadata, LogReviewer, LogSource$1 as LogSource, LogType$1 as LogType, MINUTE_IN_MS, Modal, ModalButtonType$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, MultiSwitch, ParamType$1 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$1 as ReactKitErrorCode, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant$1 as Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert, avg, canReviewLogs, capitalize, ceilToNumDecimals, combineClassNames, compareArraysByProp, confirm, everyAsync, extractProp, filterAsync, floorToNumDecimals, forEachAsync, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, idify, initClient,
|
|
16496
|
+
export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, DayOfWeek$1 as DayOfWeek, Drawer, Dropdown, DropdownItemType$1 as DropdownItemType, DynamicWord, ErrorBox, ErrorWithCode, HOUR_IN_MS, IntelliTable, ItemPicker, LoadingSpinner, LogAction$1 as LogAction, LogBuiltInMetadata, LogReviewer, LogSource$1 as LogSource, LogType$1 as LogType, MINUTE_IN_MS, Modal, ModalButtonType$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, MultiSwitch, ParamType$1 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$1 as ReactKitErrorCode, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant$1 as Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert, avg, canReviewLogs, capitalize, ceilToNumDecimals, combineClassNames, compareArraysByProp, confirm, everyAsync, extractProp, filterAsync, floorToNumDecimals, forEachAsync, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, getWordCount, handleError, handleSuccess, idify, initClient, initLogCollection, initServer, isMobileOrTablet, leaveToURL, logClientEvent, makeLinksClickable, mapAsync, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, prefixWithAOrAn, prompt, roundToNumDecimals, setClientEventMetadataPopulator, showFatalError, shuffleArray, someAsync, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, useForceRender, validateEmail, validatePhoneNumber, validateString, visitEndpointOnAnotherServer, visitServerEndpoint, waitMs };
|
|
16546
16497
|
//# sourceMappingURL=index.js.map
|