diff --git a/fbcnms-packages/fbcnms-ui/components/Colors.js b/fbcnms-packages/fbcnms-ui/components/Colors.js
new file mode 100644
index 0000000..0c51491
--- /dev/null
+++ b/fbcnms-packages/fbcnms-ui/components/Colors.js
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ * @format
+ */
+
+export const colors = {
+ primary: {
+ white: '#FFFFFF',
+ selago: '#F4F7FD',
+ concrete: '#F2F2F2',
+ mercury: '#E5E5E5',
+ nobel: '#B3B3B3',
+ gullGray: '#9DA7BB',
+ comet: '#545F77',
+ brightGray: '#323845',
+ mirage: '#171B25',
+ },
+ secondary: {
+ malibu: '#88B3F9',
+ dodgerBlue: '#3984FF',
+ mariner: '#1F5BC4',
+ },
+ button: {
+ lightOutline: '#CCD0DB',
+ fill: '#FAFAFB',
+ },
+ state: {
+ positive: '#31BF56',
+ positiveAlt: '#229A41',
+ error: '#E52240',
+ errorAlt: '#B21029',
+ errorFill: '#FFF8F9',
+ warning: '#F5DD5A',
+ warningAlt: '#B69900',
+ warningFill: '#FFFCED',
+ },
+ alerts: {
+ severe: 'E52240',
+ major: '#E36730',
+ minor: '#F5DD5A',
+ other: '#88B3F9',
+ },
+ data: {
+ coral: '#FF824B',
+ flamePea: '#E36730',
+ portage: '#A07EEA',
+ studio: '#6649A6',
+ },
+ code: {
+ crusta: '#F76D47',
+ pelorous: '#39B6C8',
+ electricViolet: '#7D4DFF',
+ orchid: '#DA70D6',
+ chelseaCucumber: '#91B859',
+ candlelight: '#FFD715',
+ mischka: '#D4D8DE',
+ },
+};
diff --git a/fbcnms-packages/fbcnms-ui/components/DataGrid.js b/fbcnms-packages/fbcnms-ui/components/DataGrid.js
new file mode 100644
index 0000000..f11d1f2
--- /dev/null
+++ b/fbcnms-packages/fbcnms-ui/components/DataGrid.js
@@ -0,0 +1,266 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ * @format
+ */
+import typeof SvgIcon from '@material-ui/core/@@SvgIcon';
+
+import Card from '@material-ui/core/Card';
+import CardHeader from '@material-ui/core/CardHeader';
+import Collapse from '@material-ui/core/Collapse';
+import Divider from '@material-ui/core/Divider';
+import ExpandLess from '@material-ui/icons/ExpandLess';
+import ExpandMore from '@material-ui/icons/ExpandMore';
+import Grid from '@material-ui/core/Grid';
+import IconButton from '@material-ui/core/IconButton';
+import Input from '@material-ui/core/Input';
+import InputAdornment from '@material-ui/core/InputAdornment';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import React from 'react';
+import Visibility from '@material-ui/icons/Visibility';
+import VisibilityOff from '@material-ui/icons/VisibilityOff';
+
+import {colors} from './Colors';
+import {makeStyles} from '@material-ui/styles';
+
+const useStyles = makeStyles(theme => ({
+ dataHeaderBlock: {
+ display: 'flex',
+ alignItems: 'center',
+ padding: 0,
+ },
+ dataHeaderContent: {
+ display: 'flex',
+ alignItems: 'center',
+ },
+ dataHeaderIcon: {
+ fill: colors.primary.comet,
+ marginRight: theme.spacing(1),
+ },
+ dataBlock: {
+ boxShadow: `0 0 0 1px ${colors.primary.concrete}`,
+ },
+ dataLabel: {
+ color: colors.primary.comet,
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ dataValue: {
+ color: colors.primary.brightGray,
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ width: props =>
+ props.hasStatus
+ ? 'calc(100% - 16px)'
+ : props.hasIcon
+ ? 'calc(100% - 32px)'
+ : '100%',
+ },
+ dataObscuredValue: {
+ color: colors.primary.brightGray,
+ width: '100%',
+
+ '& input': {
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ },
+ dataBox: {
+ width: '100%',
+ padding: props => (props.collapsed ? '0' : null),
+
+ '& > div': {
+ width: '100%',
+ },
+ },
+ dataIcon: {
+ display: 'flex',
+ alignItems: 'center',
+
+ '& svg': {
+ fill: colors.primary.comet,
+ marginRight: theme.spacing(1),
+ },
+ },
+ list: {
+ padding: 0,
+ },
+}));
+
+// Data Icon adds an icon to the left of the value
+function DataIcon(icon: SvgIcon, val: string) {
+ const props = {hasIcon: true};
+ const classes = useStyles(props);
+ const Icon = icon;
+ return (
+
+
+
+
+
+ {val}
+
+
+ );
+}
+
+// Data Obscure makes the field into a password type filed with a visibility toggle for more sensitive fields.
+function DataObscure(value: number | string, category: ?string) {
+ const [showPassword, setShowPassword] = React.useState(false);
+ return (
+
+ setShowPassword(!showPassword)}
+ onMouseDown={event => event.preventDefault()}>
+ {showPassword ? : }
+
+
+ }
+ />
+ );
+}
+
+function DataCollapse(data: Data) {
+ const props = {collapsed: true};
+ const classes = useStyles(props);
+ const [open, setOpen] = React.useState(true);
+ const dataEntryValue = data.value + (data.unit ?? '');
+ return (
+
+ setOpen(!open)}>
+
+ {open ? : }
+
+
+
+ {data.collapse ?? <>>}
+
+
+ );
+}
+
+type Data = {
+ icon?: SvgIcon,
+ category?: string,
+ value: number | string,
+ obscure?: boolean,
+ //$FlowFixMe TODO: Needs a ComponentType argument
+ collapse?: ComponentType | boolean,
+ unit?: string,
+ statusCircle?: boolean,
+ statusInactive?: boolean,
+ status?: boolean,
+ tooltip?: string,
+};
+
+export type DataRows = Data[];
+
+type Props = {data: DataRows[], testID?: string};
+
+export default function DataGrid(props: Props) {
+ const classes = useStyles();
+ const dataGrid = props.data.map((row, i) => (
+
+ {row.map((data, j) => {
+ const dataEntryValue = data.value + (data.unit ?? '');
+
+ return (
+
+
+
+ {data.collapse !== undefined && data.collapse !== false ? (
+ DataCollapse(data)
+ ) : (
+
+ )}
+
+
+
+ );
+ })}
+
+ ));
+ return (
+
+
+ {dataGrid}
+
+
+ );
+}
diff --git a/fbcnms-packages/fbcnms-ui/master/OrganizationDialog.js b/fbcnms-packages/fbcnms-ui/master/OrganizationDialog.js
index a1fbd26..d72a586 100644
--- a/fbcnms-packages/fbcnms-ui/master/OrganizationDialog.js
+++ b/fbcnms-packages/fbcnms-ui/master/OrganizationDialog.js
@@ -21,6 +21,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormLabel from '@material-ui/core/FormLabel';
+import Input from '@material-ui/core/Input';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
@@ -31,12 +32,15 @@ import React from 'react';
import Select from '@material-ui/core/Select';
import Tab from '@material-ui/core/Tab';
import Tabs from '@material-ui/core/Tabs';
+import TypedSelect from '@fbcnms/ui/components/TypedSelect';
+import renderList from '@fbcnms/util/renderList';
import {AltFormField} from '../components/FormField';
import {UserRoles} from '@fbcnms/auth/types';
+import {getProjectTabs as getAllProjectTabs} from '@fbcnms/projects/projects';
import {makeStyles} from '@material-ui/styles';
import {useAxios} from '@fbcnms/ui/hooks';
-import {useState} from 'react';
+import {useEffect, useState} from 'react';
const useStyles = makeStyles(_ => ({
input: {
@@ -58,6 +62,9 @@ type Props = {
onCreateUser: (user: CreateUserType) => void,
addUser: boolean,
setAddUser: () => void,
+ createError: string,
+ open: boolean,
+ organization: any,
};
type CreateUserType = {
@@ -85,13 +92,16 @@ export default function (props: Props) {
});
const [organization, setOrganization] = useState(
- {},
+ props.organization || {},
);
- const [currentTab, setCurrentTab] = useState(props.addUser ? 1 : 0);
+ const [currentTab, setCurrentTab] = useState(0);
const [shouldEnableAllNetworks, setShouldEnableAllNetworks] = useState(false);
const [user, setUser] = useState({});
const [createError, setCreateError] = useState('');
const allNetworks = error || !response ? [] : response.data.sort();
+ useEffect(() => {
+ setCurrentTab(props.addUser ? 1 : 0);
+ }, [props.addUser]);
if (isLoading) {
return ;
@@ -155,12 +165,16 @@ export default function (props: Props) {
: Array.from(user.networkIDs || []),
};
props.onCreateUser(payload);
+ // console.log(createError, 'error');
+ // if(createError) {}
+ // props.onClose();
+ // setUser({});
}
};
return (