orc-shared 5.9.0-dev.8 → 5.10.0-dev.1

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.
@@ -0,0 +1,106 @@
1
+ import React from "react";
2
+ import { makeStyles } from "@material-ui/core/styles";
3
+ import Menu from "@material-ui/core/Menu";
4
+ import MenuItem from "@material-ui/core/MenuItem";
5
+ import Divider from "./DataDisplay/Divider";
6
+ import DividerProps from "./DataDisplay/dividerProps";
7
+ import Icon from "./DataDisplay/Icon";
8
+ import Button from "@material-ui/core/Button";
9
+
10
+ const useMenuStyles = makeStyles(theme => ({
11
+ menuItem: {
12
+ fontFamily: theme.typography.fontFamily,
13
+ textTransform: "none",
14
+ color: theme.palette.text.primary,
15
+ borderRadius: 0,
16
+ "&:hover": {
17
+ borderRadius: 0,
18
+ boxShadow: "none",
19
+ backgroundColor: theme.palette.primary.light,
20
+ },
21
+ "&:focus, &:active, &.Mui-focusVisible": {
22
+ borderRadius: 0,
23
+ boxShadow: "none",
24
+ outline: "none",
25
+ },
26
+ },
27
+ menu: {
28
+ border: `${theme.spacing(0.1)} solid ${theme.palette.primary.main}`,
29
+ },
30
+ arrowIcon: {
31
+ width: theme.spacing(1),
32
+ height: theme.spacing(1),
33
+ },
34
+ }));
35
+
36
+ const StyledMenu = props => {
37
+ const classes = useMenuStyles();
38
+
39
+ return (
40
+ <Menu
41
+ elevation={0}
42
+ getContentAnchorEl={null}
43
+ anchorOrigin={{
44
+ vertical: "bottom",
45
+ horizontal: "left",
46
+ }}
47
+ transformOrigin={{
48
+ vertical: "top",
49
+ horizontal: "left",
50
+ }}
51
+ classes={{ paper: classes.menu }}
52
+ {...props}
53
+ />
54
+ );
55
+ };
56
+
57
+ const MenuButton = ({ options, label }) => {
58
+ const [anchorEl, setAnchorEl] = React.useState(null);
59
+ const classes = useMenuStyles();
60
+
61
+ const handleClick = event => {
62
+ setAnchorEl(event.currentTarget);
63
+ };
64
+
65
+ const handleClose = () => {
66
+ setAnchorEl(null);
67
+ };
68
+
69
+ const dividerProps = new DividerProps();
70
+ dividerProps.set(DividerProps.propNames.light, true);
71
+ dividerProps.set(DividerProps.propNames.variant, "middle");
72
+ const allDisabled = options?.every(o => o.disabled) ?? true;
73
+ return (
74
+ <>
75
+ <Button
76
+ aria-haspopup="true"
77
+ variant="outlined"
78
+ color="primary"
79
+ disabled={allDisabled}
80
+ onClick={handleClick}
81
+ endIcon={<Icon id="chevron-down" className={classes.arrowIcon} />}
82
+ >
83
+ {label}
84
+ </Button>
85
+ <StyledMenu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose}>
86
+ {options?.map(({ key, component, disabled, action }, index) => (
87
+ <div key={key}>
88
+ <MenuItem
89
+ onClick={() => {
90
+ handleClose();
91
+ action?.();
92
+ }}
93
+ disabled={disabled}
94
+ classes={{ root: classes.menuItem }}
95
+ >
96
+ {component}
97
+ </MenuItem>
98
+ {index < options.length - 1 && <Divider dividerProps={dividerProps} />}
99
+ </div>
100
+ ))}
101
+ </StyledMenu>
102
+ </>
103
+ );
104
+ };
105
+
106
+ export default MenuButton;
@@ -0,0 +1,74 @@
1
+ import React from "react";
2
+ import MenuButton from "./MenuButtons";
3
+ import Button from "@material-ui/core/Button";
4
+ import Menu from "@material-ui/core/Menu";
5
+ import Icon from "./DataDisplay/Icon";
6
+ import sinon from "sinon";
7
+ import ReactDOM from "react-dom";
8
+
9
+ describe("MenuButton", () => {
10
+ it("Renders MenuButton with no options", () => {
11
+ const menuItems = [
12
+ {
13
+ disabled: true,
14
+ },
15
+ {
16
+ disabled: true,
17
+ },
18
+ ];
19
+
20
+ const component = <MenuButton label={<p>Label</p>} options={menuItems} />;
21
+
22
+ const expected = (
23
+ <>
24
+ <Button disabled={true} variant="outlined" color="primary" endIcon={<Icon id="chevron-down" />}>
25
+ <p>Label</p>
26
+ </Button>
27
+ <Menu open={false}></Menu>
28
+ </>
29
+ );
30
+
31
+ expect(component, "when mounted", "to satisfy", expected);
32
+ });
33
+
34
+ it("Renders MenuButton with all options disabled", () => {
35
+ const component = <MenuButton label={<p>Label</p>} />;
36
+
37
+ const expected = (
38
+ <>
39
+ <Button disabled={true} variant="outlined" color="primary" endIcon={<Icon id="chevron-down" />}>
40
+ <p>Label</p>
41
+ </Button>
42
+ <Menu open={false}></Menu>
43
+ </>
44
+ );
45
+
46
+ expect(component, "when mounted", "to satisfy", expected);
47
+ });
48
+
49
+ it("Call option set in menu item", () => {
50
+ const menuItems = [
51
+ {
52
+ action: sinon.spy().named("action"),
53
+ },
54
+ ];
55
+
56
+ const container = document.createElement("div");
57
+ document.body.appendChild(container);
58
+ ReactDOM.render(<MenuButton options={menuItems} />, container);
59
+
60
+ const clickEvent = new MouseEvent("click", {
61
+ bubbles: true,
62
+ cancelable: false,
63
+ });
64
+
65
+ const button = container.querySelector("button");
66
+ button.dispatchEvent(clickEvent);
67
+
68
+ const items = document.querySelectorAll(".MuiListItem-root");
69
+ expect(items, "to have length", 1);
70
+
71
+ items[0].dispatchEvent(clickEvent);
72
+ expect(menuItems[0].action, "was called");
73
+ });
74
+ });
@@ -47,6 +47,13 @@ const DropDownMenu = ({ payload, menuItems, children, dropDownMenuProps = new Dr
47
47
  setAnchorEl(null);
48
48
  };
49
49
 
50
+ // Even though we do nothing, we need to avoid mouse event propagation when the mouse
51
+ // button is released after hovering out the menu
52
+ const onMainMenuClick = event => {
53
+ event.preventDefault();
54
+ event.stopPropagation();
55
+ };
56
+
50
57
  const onMenuItemClick = (action, itemContext) => event => {
51
58
  onClose(event);
52
59
  action(payload, itemContext);
@@ -76,6 +83,7 @@ const DropDownMenu = ({ payload, menuItems, children, dropDownMenuProps = new Dr
76
83
  classes={{ paper: classes.menu }}
77
84
  id="scope-menu"
78
85
  open={isOpened}
86
+ onClick={onMainMenuClick}
79
87
  onClose={onClose}
80
88
  autoFocus={autoFocus}
81
89
  anchorEl={anchorEl}
@@ -8,6 +8,7 @@ import Icon from "../DataDisplay/Icon";
8
8
  import DropDownMenu from "./DropDownMenu";
9
9
  import { ignoreConsoleError } from "../../../utils/testUtils";
10
10
  import { TestWrapper, createMuiTheme } from "./../../../utils/testUtils";
11
+ import Menu from "@material-ui/core/Menu";
11
12
 
12
13
  describe("DropDownMenu", () => {
13
14
  let store, menuItems, container;
@@ -92,4 +93,27 @@ describe("DropDownMenu", () => {
92
93
  expect(menuItems[0].action, "to have calls satisfying", [{ args: [payload, "aContext"] }]);
93
94
  expect(menuItems[1].action, "to have calls satisfying", [{ args: [payload, "myContext"] }]);
94
95
  });
96
+
97
+ it("should handle onClick event on the menu", () => {
98
+ const payload = "payload";
99
+
100
+ const component = (
101
+ <Provider store={store}>
102
+ <DropDownMenu payload={payload} menuItems={menuItems} />
103
+ </Provider>
104
+ );
105
+
106
+ const mountedComponent = mount(component);
107
+
108
+ const event = {
109
+ preventDefault: sinon.spy().named("preventDefault"),
110
+ stopPropagation: sinon.spy().named("stopPropagation"),
111
+ };
112
+
113
+ const dropDownMenu = mountedComponent.find(Menu).at(0);
114
+ dropDownMenu.invoke("onClick")(event);
115
+
116
+ expect(event.preventDefault, "was called");
117
+ expect(event.stopPropagation, "was called");
118
+ });
95
119
  });
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import InformationItem from "./MaterialUI/DataDisplay/PredefinedElements/InformationItem";
3
+ import sharedMessages from "../sharedMessages";
4
+ import { useIntl } from "react-intl";
5
+ import Box from "@material-ui/core/Box";
6
+ import { makeStyles } from "@material-ui/core/styles";
7
+
8
+ const useStyles = makeStyles(theme => ({
9
+ registry: {
10
+ "& > div + div": {
11
+ marginTop: theme.spacing(2),
12
+ },
13
+ },
14
+ }));
15
+
16
+ const Registry = ({ dateCreated, createdBy, lastModifiedDate, lastModifiedBy, additionalContent = [] }) => {
17
+ const { formatDate } = useIntl();
18
+ const classes = useStyles();
19
+
20
+ const created = formatDate(dateCreated);
21
+ const lastModified = formatDate(lastModifiedDate);
22
+ 0;
23
+ const registry = (
24
+ <Box className={classes.registry} display="flex" flexDirection="column">
25
+ {dateCreated !== undefined && <InformationItem label={sharedMessages.created} children={created} />}
26
+ {createdBy !== undefined && <InformationItem label={sharedMessages.createdBy} children={createdBy} />}
27
+ {lastModifiedDate !== undefined && (
28
+ <InformationItem label={sharedMessages.lastModified} children={lastModified} />
29
+ )}
30
+ {lastModifiedBy !== undefined && (
31
+ <InformationItem label={sharedMessages.lastModifiedBy} children={lastModifiedBy} />
32
+ )}
33
+ {additionalContent.map((c, index) => (
34
+ <InformationItem key={"additional" + index} label={c.label} children={c.content} />
35
+ ))}
36
+ </Box>
37
+ );
38
+
39
+ return registry;
40
+ };
41
+
42
+ export default Registry;
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+ import InformationItem from "./MaterialUI/DataDisplay/PredefinedElements/InformationItem";
3
+ import sharedMessages from "~/sharedMessages";
4
+ import Box from "@material-ui/core/Box";
5
+ import Registry from "./Registry";
6
+ import { TestWrapper, createMuiTheme, extractMessages } from "../utils/testUtils";
7
+
8
+ const messages = extractMessages(sharedMessages);
9
+ const theme = createMuiTheme();
10
+
11
+ describe("Registry", () => {
12
+ it("Renders Registry correctly", () => {
13
+ const created = "2020-10-06T16:21:55.5700000Z";
14
+ const createdBy = "Somebody";
15
+ const lastModified = "2020-10-06T16:21:55.5700000Z";
16
+ const lastModifiedBy = "OOE@oco";
17
+
18
+ const component = (
19
+ <TestWrapper intlProvider={{ messages }} stylesProvider muiThemeProvider={{ theme }}>
20
+ <Registry
21
+ dateCreated={created}
22
+ createdBy={createdBy}
23
+ lastModifiedDate={lastModified}
24
+ lastModifiedBy={lastModifiedBy}
25
+ />
26
+ </TestWrapper>
27
+ );
28
+
29
+ const expected = (
30
+ <TestWrapper intlProvider={{ messages }} stylesProvider muiThemeProvider={{ theme }}>
31
+ <Box display="flex" flexDirection="column">
32
+ <InformationItem label={sharedMessages.created} children="10/6/2020" />
33
+ <InformationItem label={sharedMessages.createdBy} children={createdBy} />
34
+ <InformationItem label={sharedMessages.lastModified} children="10/6/2020" />
35
+ <InformationItem label={sharedMessages.lastModifiedBy} children={lastModifiedBy} />
36
+ </Box>
37
+ </TestWrapper>
38
+ );
39
+
40
+ expect(component, "when mounted", "to satisfy", expected);
41
+ });
42
+
43
+ it("Renders Registry correctly with additional content", () => {
44
+ const created = "2020-10-06T16:21:55.5700000Z";
45
+ const createdBy = "Somebody";
46
+ const lastModified = "2020-10-06T16:21:55.5700000Z";
47
+ const lastModifiedBy = "OOE@oco";
48
+
49
+ const component = (
50
+ <TestWrapper intlProvider={{ messages }} stylesProvider muiThemeProvider={{ theme }}>
51
+ <Registry
52
+ dateCreated={created}
53
+ createdBy={createdBy}
54
+ lastModifiedDate={lastModified}
55
+ lastModifiedBy={lastModifiedBy}
56
+ additionalContent={[
57
+ {
58
+ label: sharedMessages.about,
59
+ content: "some date",
60
+ },
61
+ {
62
+ label: sharedMessages.help,
63
+ content: "Hugh Mann",
64
+ },
65
+ ]}
66
+ />
67
+ </TestWrapper>
68
+ );
69
+
70
+ const expected = (
71
+ <TestWrapper intlProvider={{ messages }} stylesProvider muiThemeProvider={{ theme }}>
72
+ <Box display="flex" flexDirection="column">
73
+ <InformationItem label={sharedMessages.created} children="10/6/2020" />
74
+ <InformationItem label={sharedMessages.createdBy} children={createdBy} />
75
+ <InformationItem label={sharedMessages.lastModified} children="10/6/2020" />
76
+ <InformationItem label={sharedMessages.lastModifiedBy} children={lastModifiedBy} />
77
+ <InformationItem label={sharedMessages.about} children={"some date"} />
78
+ <InformationItem label={sharedMessages.help} children={"Hugh Mann"} />
79
+ </Box>
80
+ </TestWrapper>
81
+ );
82
+
83
+ expect(component, "when mounted", "to satisfy", expected);
84
+ });
85
+ });
package/src/requests ADDED
@@ -0,0 +1,34 @@
1
+ createCustomerLookupTypeDefinitionRequest
2
+ createEntityTypeRequest
3
+ createOrderLookupTypeDefinitionRequest
4
+ deleteTaskInfoRequest
5
+ getApplicationModules
6
+ getAuthorizedApplicationsRequest
7
+ getCountriesRequest
8
+ getCustomerDefinitionsRequest
9
+ getCustomerLookupRequest
10
+ getCustomerLookupsRequest
11
+ getOrderDefinitionRequest
12
+ getOrderLookupRequest
13
+ getOrderLookupsRequest
14
+ getProductDefinitionsRequest
15
+ getProductLookupsRequest
16
+ getProfileAttributeGroupsRequest
17
+ getRequesterTasksInfoRequest
18
+ getScopeExtendedConfigurationRequest
19
+ getSupportedCulturesRequest
20
+ getTaskExecutionLogsRequest
21
+ getTaskInfoRequest
22
+ getTimeZonesRequest
23
+ getUserApplicationRequest
24
+ getUserCultureRequest
25
+ getUserPermissionsRequest
26
+ getUserScopeRequest
27
+ getUserScopeTreeRequest
28
+ getVersionInfoRequest
29
+ saveUserApplicationRequest
30
+ saveUserCultureRequest
31
+ signOutRequest
32
+ updateCustomerLookupTypeDefinitionRequest
33
+ updateEntityTypeRequest
34
+ updateOrderLookupTypeDefinitionRequest
@@ -279,6 +279,26 @@ const sharedMessages = defineMessages({
279
279
  id: "orc-shared.valueTypeWrapperFalse",
280
280
  defaultMessage: "False",
281
281
  },
282
+ registry: {
283
+ id: "orc-shared.registry",
284
+ defaultMessage: "Registry",
285
+ },
286
+ created: {
287
+ id: "orc-shared.created",
288
+ defaultMessage: "Date Created",
289
+ },
290
+ createdBy: {
291
+ id: "orc-shared.createdBy",
292
+ defaultMessage: "Created By",
293
+ },
294
+ lastModified: {
295
+ id: "orc-shared.lastModified",
296
+ defaultMessage: "Last Modified",
297
+ },
298
+ lastModifiedBy: {
299
+ id: "orc-shared.lastModifiedBy",
300
+ defaultMessage: "Last Modified By",
301
+ },
282
302
  });
283
303
 
284
304
  export default sharedMessages;
@@ -14,6 +14,8 @@
14
14
  "orc-shared.confirmation": "Confirmation",
15
15
  "orc-shared.copyright": "© {year} Orckestra Technologies Inc.",
16
16
  "orc-shared.copyrightTermsNotice": "This computer program is protected by copyright laws and international treaties. Unauthorized reproduction or redistribution of this program, or any portion of it, may result in severe civil and criminal penalties, and will be prosecuted to the maximum extent possible under the law. Orckestra is a trademark of Orckestra Technologies Inc. All other trademarks are property of the respective owners.",
17
+ "orc-shared.created": "Date Created",
18
+ "orc-shared.createdBy": "Created By",
17
19
  "orc-shared.dataTypeBoolean": "Yes/No Choice",
18
20
  "orc-shared.dataTypeDate": "Date/Calendar",
19
21
  "orc-shared.dataTypeDecimal": "Decimal Number",
@@ -37,6 +39,8 @@
37
39
  "orc-shared.inactive": "Inactive",
38
40
  "orc-shared.internetExplorerWarningContent": "You are using a browser that we no longer support. For a better experience with our HTML web applications, we recommend you to use the latest version of one of the following browsers:",
39
41
  "orc-shared.internetExplorerWarningTitle": "Improve your experience",
42
+ "orc-shared.lastModified": "Last Modified",
43
+ "orc-shared.lastModifiedBy": "Last Modified By",
40
44
  "orc-shared.needToRefresh": "You are not authorized to execute a request. Click refresh to reload the application.",
41
45
  "orc-shared.next": "Next",
42
46
  "orc-shared.no": "No",
@@ -46,6 +50,7 @@
46
50
  "orc-shared.orcSharedVersion": "Orc-Shared Framework {version}",
47
51
  "orc-shared.preferences": "Preferences",
48
52
  "orc-shared.refresh": "Refresh",
53
+ "orc-shared.registry": "Registry",
49
54
  "orc-shared.remove": "Remove",
50
55
  "orc-shared.save": "Save",
51
56
  "orc-shared.scopeChangeWithOpenedTabsConfirmation": "One or more entities opened will be closed. Would you like to change scope now?",
@@ -14,6 +14,8 @@
14
14
  "orc-shared.confirmation": "Confirmation",
15
15
  "orc-shared.copyright": "© {year} Technologies Orckestra Inc.",
16
16
  "orc-shared.copyrightTermsNotice": "Avertissement: Ce programme est protégé par la loi relative au droit d'auteur et par les conventions internationales. Toute reproduction ou distribution partielle ou totale du logiciel, par quelque moyen que ce soit, est strictement interdite. Toute personne ne respectant pas ces dispositions se rendra coupable du délit de contrefaçon et sera passible des sanctions pénales prévues par la loi. Orckestra est une marque de commerce déposée et détenue par Technologies Orckestra Inc. Toutes les autres marques de commerce sont la propriété de leurs détenteurs respectifs.",
17
+ "orc-shared.created": "Date de création",
18
+ "orc-shared.createdBy": "Créé par",
17
19
  "orc-shared.dataTypeBoolean": "Choix Oui/Non",
18
20
  "orc-shared.dataTypeDate": "Date/Calendrier",
19
21
  "orc-shared.dataTypeDecimal": "Nombre décimal",
@@ -37,6 +39,8 @@
37
39
  "orc-shared.inactive": "Inactif",
38
40
  "orc-shared.internetExplorerWarningContent": "Vous utilisez un navigateur qui n'est plus supporté. Pour assurer une expérience optimale de nos applications web HTML, nous vous recommendons d'utiliser la dernière version des navigateurs suivants:",
39
41
  "orc-shared.internetExplorerWarningTitle": "Améliorez votre expérience",
42
+ "orc-shared.lastModified": "Dernière date de modification",
43
+ "orc-shared.lastModifiedBy": "Modifié par",
40
44
  "orc-shared.needToRefresh": "Vous n'êtes pas autorisé à effectuer une requête. Veuillez cliquer sur Rafraîchir pour rafraîchir l’application.",
41
45
  "orc-shared.next": "Suivant",
42
46
  "orc-shared.no": "Non",
@@ -46,6 +50,7 @@
46
50
  "orc-shared.orcSharedVersion": "Infrastructure Orc-Shared {version}",
47
51
  "orc-shared.preferences": "Préférences",
48
52
  "orc-shared.refresh": "Rafraîchir",
53
+ "orc-shared.registry": "Régistre",
49
54
  "orc-shared.remove": "Retirer",
50
55
  "orc-shared.save": "Sauvegarder",
51
56
  "orc-shared.scopeChangeWithOpenedTabsConfirmation": "Une ou plusieurs entités ouvertes seront fermées. Voulez-vous vraiment changer de Scope?",
@@ -18,6 +18,8 @@ export const customDataType = {
18
18
  carrierProviderSelector: "CarrierProviderSelector",
19
19
  routingProviderSelector: "RoutingProviderSelector",
20
20
  multipleCarrierProvidersSelector: "MultipleCarrierProvidersSelector",
21
+ serviceLevelSelector: "ServiceLevelSelector",
22
+ percentageDecimal: "PercentageDecimal",
21
23
  };
22
24
 
23
25
  const tieredAttributeTypes = [customDataType.priceTieredRateTable, customDataType.quantityTieredRateTable];
@@ -72,14 +74,16 @@ export const toJsonCargo = (attribute, value) => {
72
74
  case customDataType.money:
73
75
  return createJsonCargo(jsonCargoType.double, Number(formatNumber(value, 2)));
74
76
  case customDataType.moneyDecimal:
77
+ case customDataType.percentageDecimal:
75
78
  return createJsonCargo(jsonCargoType.decimal, Number(formatNumber(value, 2)));
76
79
  case customDataType.priceTieredRateTable:
77
80
  case customDataType.quantityTieredRateTable:
78
81
  return createTieredTableJsonCargo(value);
79
82
  case customDataType.password:
80
- case customDataType.carrierProviderSelector: // To be properly handled when user story 61801 will be addressed
81
- case customDataType.routingProviderSelector: // To be properly handled when user story 61801 will be addressed
82
- case customDataType.multipleCarrierProvidersSelector: // To be properly handled when user story 61801 will be addressed
83
+ case customDataType.carrierProviderSelector:
84
+ case customDataType.routingProviderSelector:
85
+ case customDataType.multipleCarrierProvidersSelector:
86
+ case customDataType.serviceLevelSelector:
83
87
  return value;
84
88
  default:
85
89
  throw new Error(`toJsonCargo: attribute.customDataType ${attribute.customDataType} is not implemented`);