@material-ui/lab#AlertTitle JavaScript Examples
The following examples show how to use
@material-ui/lab#AlertTitle.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ImageErrorAlert.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 6 votes |
function ImageErrorAlert({
alertHeight,
alertWidth,
alertPadding,
alertPosition,
alertTextSize,
alertTitleSize,
}) {
return (
<Alert
severity="error"
style={{
flexDirection: 'column',
position: alertPosition,
width: alertWidth,
height: alertHeight,
padding: alertPadding,
}}
>
<AlertTitle style={{ fontSize: alertTitleSize, whiteSpace: 'nowrap' }}>
Failed to load image
</AlertTitle>
<div>
<p style={{ fontSize: alertTextSize }}>
please try — <strong>reloading the page</strong>
</p>
<p style={{ fontSize: alertTextSize }}>
or — <strong>report the issue to an admin</strong>
</p>
</div>
</Alert>
);
}
Example #2
Source File: AlertMessage.js From reddish with MIT License | 6 votes |
AlertMessage = ({ severity, error, clearError }) => {
const classes = useAlertStyles();
if (!error) {
return null;
}
return (
<div className={classes.root}>
<Alert severity={severity} onClose={clearError}>
<AlertTitle>Error</AlertTitle>
{error}
</Alert>
</div>
);
}
Example #3
Source File: ErrorMessage.js From stack-underflow with MIT License | 6 votes |
AlertMessage = ({ errorMsg, clearErrorMsg }) => {
const classes = useAlertStyles();
if (!errorMsg) {
return null;
}
return (
<div className={classes.root}>
<Alert severity="error" onClose={clearErrorMsg}>
<AlertTitle>Error</AlertTitle>
{errorMsg}
</Alert>
</div>
);
}
Example #4
Source File: AlertBox.js From to-view-list with MIT License | 6 votes |
AlertBox = ({ severity, message, clearError, title }) => {
const classes = useAlertStyles();
return (
<div className={classes.root}>
<Alert severity={severity} onClose={clearError}>
<AlertTitle>{title || 'Error'}</AlertTitle>
{message}
</Alert>
</div>
);
}
Example #5
Source File: DemoCredsBox.js From to-view-list with MIT License | 6 votes |
DemoCredsBox = () => {
const classes = useAlertStyles();
return (
<div className={classes.root}>
<Alert severity="info">
<AlertTitle>Demo Account Credentials</AlertTitle>
{demoCreds}
</Alert>
</div>
);
}
Example #6
Source File: ErrorFallback.js From akashlytics-deploy with GNU General Public License v3.0 | 6 votes |
export function ErrorFallback({ error, resetErrorBoundary }) {
const classes = useStyles();
return (
<div className={classes.root} role="alert">
<Typography variant="h4" className={classes.heading}>
Something went wrong:
</Typography>
<Alert severity="error" className={classes.alert}>
<AlertTitle>Error</AlertTitle>
{error.message}
</Alert>
<Button variant="contained" color="primary" onClick={resetErrorBoundary}>
Try again
</Button>
</div>
);
}
Example #7
Source File: Announcement.jsx From redive_linebot with MIT License | 6 votes |
TopNews = props => {
const { breakingNews } = props;
const levels = ["success", "info", "warning", "error"];
if (Object.keys(breakingNews).length === 0) {
breakingNews.level = "success";
breakingNews.title = "乾淨無比";
breakingNews.content = "這個作者很懶,什麼話都沒說~";
breakingNews.create_time = new Date().toString();
}
return (
<Alert severity={levels.indexOf(breakingNews.level) === -1 ? "warning" : breakingNews.level}>
<AlertTitle>{breakingNews.title}</AlertTitle>
{breakingNews.content} <br />
<Typography variant="caption" color="textSecondary">
{new Date(breakingNews.create_time).toLocaleString()}
</Typography>
</Alert>
);
}
Example #8
Source File: Notification.js From scholar-front-end with MIT License | 6 votes |
function Notification() {
const [open, setOpen] = React.useState(true);
const classes = useStyles();
return (
<div className={classes.root}>
<Collapse in={open}>
<Alert severity="info" action={
<IconButton aria-label="close" size="small" onClick={()=>{
setOpen(false);
}}>
<CloseIcon fontSize="inherit"/>
</IconButton>
}>
<AlertTitle>Price Drop</AlertTitle>
<p className={classes.inform}>All Courses At <strong> 399 </strong>/-</p>
</Alert>
</Collapse>
</div>
)
}
Example #9
Source File: InspectClients.js From management-center with Apache License 2.0 | 5 votes |
Clients = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client: brokerClient } = context;
const { inspectFeature, userProfile, roles = [], clients = [], onSort, sortBy, sortDirection } = props;
const onUpdateUserRoles = async (user, roles = []) => {
if (!roles) {
roles = [];
}
const rolenames = roles.map((role) => role.value);
await brokerClient.updateUserRoles(user, rolenames);
const clients = await brokerClient.inspectListClients();
dispatch(updateInspectClients(clients));
};
const onSelectClient = async (username) => {
const client = await brokerClient.inspectGetClient(username);
dispatch(updateInspectClient(client));
history.push(`/admin/inspect/clients/detail/${username}`);
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/admin">
Admin
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Inspect
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{inspectFeature?.error ? <><br/><Alert severity="warning">
<AlertTitle>{inspectFeature.error.title}</AlertTitle>
{inspectFeature.error.message}
</Alert></> : null}
{!inspectFeature?.error && inspectFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that this feature is included in your MMC license.
</Alert></> : null}
<br />
<br />
{ createClientsTable(clients, classes, props, onUpdateUserRoles, onSelectClient) }
</div>
);
}
Example #10
Source File: Notify.jsx From redive_linebot with MIT License | 5 votes |
Notify = () => {
const classes = useStyles();
const option = useOption();
const { loading, isBinding, option: optionData, isLoggedIn } = option;
useEffect(() => {
window.document.title = "訂閱通知設定頁面";
}, []);
return (
<React.Fragment>
<Grid container direction="column" className={classes.root}>
<Grid container item>
<Grid item>
<Description />
</Grid>
<Grid item>
<IconButton color="secondary" onClick={option.handleOpen}>
<SettingsIcon />
</IconButton>
</Grid>
</Grid>
<Grid item>
{isBinding ? (
<Alert severity="success">綁定中!需更改設定請點擊標題右邊齒輪!</Alert>
) : (
<Alert severity="warning">
<AlertTitle>注意!</AlertTitle>
{isLoggedIn
? "尚未綁定LINE Notify!點擊標題右邊齒輪進行設定吧!"
: "尚未登入!請先點擊右上角的登入鈕"}
</Alert>
)}
</Grid>
{isBinding
? optionData.subData.map((data, index) => (
<Grid item key={index}>
<CardOption
handleChange={event =>
option.handleSwitch(data.key, event.target.checked ? 1 : 0)
}
{...data}
/>
</Grid>
))
: null}
<Grid item>
<ActionDialog {...option} />
</Grid>
</Grid>
{
<Backdrop className={classes.backdrop} open={loading}>
<CircularProgress color="inherit" />
</Backdrop>
}
</React.Fragment>
);
}
Example #11
Source File: withAuthWrapper.js From nextjs-todo-list with MIT License | 4 votes |
withAuthWrapper = (Component) => (props) => {
const [loading, setLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const { activateAuth } = useContext(AuthContext);
const firebase = useContext(FirebaseContext);
useEffect(() => {
redirectIfAuthenticated();
}, []);
if (errorMessage) {
setTimeout(() => {
setErrorMessage('');
}, 5000);
}
const saveAuthAndRedirect = (data) => {
try {
const { user } = data;
let { idToken = null } = data;
if (!idToken) idToken = user.uid;
activateAuth(user, idToken);
setLoading(false);
Router.push('/');
} catch (error) {
console.log({ error });
}
};
const onGoogleSignIn = async () => {
setLoading(true);
firebase
.doAuthWithGoogle()
.then((resp) => {
saveAuthAndRedirect(resp);
})
.catch((error) => {
const { message } = error;
setLoading(false);
setErrorMessage(message);
});
};
const onGithubSignIn = async () => {
setLoading(true);
await firebase
.doAuthWithGithub()
.then((resp) => saveAuthAndRedirect(resp))
.catch((error) => {
setLoading(false);
const { message } = error;
setErrorMessage(message);
});
};
return (
<MainLayout>
<div className="container">
<div className="main">
{errorMessage && (
<Alert severity="error">
<AlertTitle>Error</AlertTitle>
{errorMessage}
</Alert>
)}
<Component
{...props}
loading={loading}
onGoogleSignIn={onGoogleSignIn}
onGithubSignIn={onGithubSignIn}
/>
</div>
</div>
<style jsx>
{`
.container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
`}
</style>
</MainLayout>
);
}
Example #12
Source File: index.jsx From redive_linebot with MIT License | 4 votes |
TradeOrder = () => {
const isLoggedIn = liff.isLoggedIn();
const seletEl = useRef(null);
const chargeEl = useRef(null);
const [{ data = [], loading }, fetchItems] = useAxios("/api/Inventory", { manual: true });
const [{ data: createResponse, loading: createLoading, error }, createOrder] = useAxios(
{
url: "/api/Trade",
method: "POST",
},
{ manual: true }
);
const [{ open, message, severity }, { handleOpen, handleClose }] = useHintBar();
const query = useQuery();
const targetId = query.get("target_id");
const { userId } = liff.getContext();
useEffect(() => {
if (!isLoggedIn) return;
fetchItems();
return () => {};
}, [isLoggedIn, fetchItems]);
useEffect(() => {
if (!targetId) {
handleOpen("未指定交易對象", "error");
}
return () => {};
}, [targetId, handleOpen]);
useEffect(() => {
(() => {
if (!error) return;
handleOpen(get(error, "response.data.message"), "error");
})();
return () => {};
}, [error]);
const pageLoading = loading || createLoading;
if (!isLoggedIn) {
return <AlertLogin />;
}
const handleCancel = () => {
if (liff.isInClient()) {
liff.closeWindow();
} else {
window.location.href = "/";
}
};
const handleSubmit = () => {
let payload = {
targetId,
itemId: parseInt(seletEl.current.value),
charge: parseInt(chargeEl.current.value),
};
if (get(payload, "charge", 0) <= 0) {
handleOpen("請輸入收費金額", "error");
} else {
createOrder({
data: payload,
});
}
};
if (createResponse) {
return <TradeCreateResult marketId={get(createResponse, "marketId")} />;
}
const isSelf = userId === targetId;
const selfAlert = (
<Grid item>
<Alert severity="error">
<AlertTitle>錯誤</AlertTitle>
您不能與自己進行交易
</Alert>
</Grid>
);
return (
<Grid container direction="column" spacing={2}>
{pageLoading && <DotsLoading />}
{isSelf && selfAlert}
<Grid item>
<Alert severity="warning">
<AlertTitle>注意</AlertTitle>
<Typography variant="inherit" component="p">
1. 請確認您的交易對象是否已經在您的好友列表中,如果沒有,請先加入好友
</Typography>
<Typography variant="inherit">
2. 交易對象為指令自動帶出,如果您不是要跟對方交易,請直接關閉視窗
</Typography>
</Alert>
</Grid>
<Grid item container spacing={2}>
<Grid item xs={12}>
<TextField label="交易對象" value={targetId} disabled variant="outlined" fullWidth />
</Grid>
<Grid item xs={12}>
<TextField
select
label="選擇商品"
SelectProps={{
native: true,
}}
inputRef={seletEl}
fullWidth
variant="outlined"
helperText="只會列出您擁有的商品"
autoFocus
disabled={isSelf}
>
{data.map(item => (
<option key={item.itemId} value={item.itemId}>
{item.name}
</option>
))}
</TextField>
</Grid>
<Grid item xs={12}>
<TextField
label="要求女神石"
type="number"
variant="outlined"
defaultValue={0}
fullWidth
inputRef={chargeEl}
helperText="請輸入要求的女神石數量,對方將會支付相應的女神石"
disabled={isSelf}
/>
</Grid>
<Grid item xs={6}>
<Button
variant="contained"
color="secondary"
fullWidth
onClick={handleCancel}
disabled={isSelf}
>
取消交易
</Button>
</Grid>
<Grid item xs={6}>
<Button
variant="contained"
color="primary"
fullWidth
onClick={handleSubmit}
disabled={isSelf}
>
送出交易
</Button>
</Grid>
</Grid>
<HintSnackBar {...{ open, message, severity, handleClose }} />
</Grid>
);
}
Example #13
Source File: BattleSign.jsx From redive_linebot with MIT License | 4 votes |
BattleSign = () => {
const [{ isError, isSuccess }, send] = useSendMessage();
let { week, boss } = useParams();
const location = useLocation();
const classes = useStyles();
const [state, setState] = useState({
week: week || 1,
boss: boss || 1,
type: "1",
damage: "",
comment: "",
maxDamage: 0,
});
const [alert, setAlert] = useState({ open: false, message: "" });
const [Hotkeys, setHotKeys] = useState([]);
useEffect(() => {
window.document.title = "自訂報名內容";
}, []);
useEffect(() => {
if (!isError) return;
setAlert({ open: true, message: "發送失敗,不過幫你複製起來了!可直接到LINE貼上!" });
}, [isError]);
useEffect(() => {
if (!isSuccess) return;
window.liff.closeWindow();
}, [isSuccess]);
useEffect(() => {
const querys = new window.URLSearchParams(location.search);
let damage = querys.get("damage") || 0;
setHotKeys([
{ title: "物理一刀", damage, comment: "物理一刀殺", type: "1" },
{ title: "法刀一刀", damage, comment: "法隊一刀殺", type: "1" },
]);
setState({ ...state, maxDamage: parseInt(damage) });
}, [location.search]);
const alertClose = () => {
setAlert({ ...alert, open: false, message: "" });
};
const handleDamage = event => {
let damage = event.target.value;
damage = /^\d+$/.test(damage) ? parseInt(damage) : "";
setState({ ...state, damage });
};
const handleComment = event => {
setState({ ...state, comment: event.target.value });
};
const handleType = event => {
setState({ ...state, type: event.target.value });
};
return (
<React.Fragment>
<Grid container className={classes.gridBox}>
<Grid item xs={12}>
<Typography variant="h4" component="p">
報名面版
</Typography>
</Grid>
<Grid item xs={12}>
<Alert severity="info">
<AlertTitle>
{state.week} 周 {state.boss} 王
</AlertTitle>
請注意是否為要 <strong>報名的王</strong> 以及 <strong>周次</strong>
</Alert>
</Grid>
</Grid>
<Grid container className={classes.gridBox} direction="column">
<Grid item>
<Typography variant="body1">快速鍵</Typography>
</Grid>
<Grid item>
<ButtonGroup variant="text" color="primary" aria-label="text primary button group">
{Hotkeys.map((hotkey, index) => (
<Button
key={index}
onClick={() =>
setState({
...state,
damage: hotkey.damage,
comment: hotkey.comment,
type: hotkey.type,
})
}
>
{hotkey.title}
</Button>
))}
</ButtonGroup>
</Grid>
</Grid>
<Grid container className={classes.gridBox} justify="space-around">
<Grid item xs={12} sm={3}>
<TextField
select
fullWidth
label="刀種"
value={state.type}
onChange={handleType}
SelectProps={{
native: true,
}}
variant="outlined"
>
{SaberTypes.map(data => (
<option key={data.value} value={data.value}>
{data.title}
</option>
))}
</TextField>
</Grid>
<Grid container item xs={12} sm={3} direction="column">
<Grid item>
<TextField
label="預計傷害"
fullWidth
type="number"
variant="outlined"
value={state.damage}
onChange={handleDamage}
/>
</Grid>
<Grid item>
<PrettoSlider
min={0}
max={state.maxDamage}
step={window.Math.floor(state.maxDamage / 100)}
value={parseInt(state.damage)}
onChange={(event, value) => setState({ ...state, damage: value.toString() })}
/>
</Grid>
</Grid>
<Grid item xs={12} sm={3}>
<TextField
label="備註留言"
fullWidth
variant="outlined"
value={state.comment}
onChange={handleComment}
/>
</Grid>
<Grid item xs={12}>
<CopyToClipboard text={genMessage(state)}>
<Button
fullWidth
variant="contained"
color="primary"
onClick={() => send(genMessage(state))}
>
送出
</Button>
</CopyToClipboard>
</Grid>
</Grid>
<Snackbar open={alert.open} autoHideDuration={6000} onClose={alertClose}>
<Alert elevation={6} variant="filled" onClose={alertClose} severity="warning">
{alert.message}
</Alert>
</Snackbar>
</React.Fragment>
);
}
Example #14
Source File: EditProfile.js From lifebank with MIT License | 4 votes |
EditProfilePage = () => {
const { t } = useTranslation('translations')
const classes = useStyles()
const history = useHistory()
const [, { logout }] = useUser()
const [currentUser] = useUser()
const [openSnackbar, setOpenSnackbar] = useState(false)
const theme = useTheme()
const isDesktop = useMediaQuery(theme.breakpoints.up('md'), {
defaultMatches: false
})
const [
loadProfile,
{ error: errorProfile, loading, data: { profile: { profile } = {} } = {} }
] = useLazyQuery(PROFILE_QUERY, { fetchPolicy: 'network-only' })
const [
revokeConsent,
{
error: errorRevokeConsent,
loading: revokeConsentLoading,
data: { revoke_consent: revokeConsentResult } = {}
}
] = useMutation(REVOKE_CONSENT_MUTATION)
const [
grantConsent,
{
error: errorGrantConsent,
loading: grantConsentLoading,
data: { grant_consent: grantConsentResult } = {}
}
] = useMutation(GRANT_CONSENT_MUTATION)
const [
editProfile,
{ error: errorEditResults, loading: editLoading, data: { edit_profile: editProfileResult } = {} }
] = useMutation(EDIT_PROFILE_MUTATION)
const [setUsername] = useMutation(SET_USERNAME)
const handleConsentChange = () => {
profile?.consent ? revokeConsent() : grantConsent()
}
const handleUpdateUser = (userEdited, userNameEdited, account) => {
editProfile({
variables: {
profile: userEdited
}
})
if (account && userNameEdited) {
setUsername({
variables: {
account: account,
username: userNameEdited
}
})
}
}
const handleCloseSnackBar = () => {
setOpenSnackbar({ ...openSnackbar, show: false })
}
useEffect(() => {
if (!currentUser) {
return
}
loadProfile()
}, [currentUser, loadProfile])
useEffect(() => {
if (grantConsentResult || revokeConsentResult) {
loadProfile()
}
}, [grantConsentResult, revokeConsentResult, loadProfile])
useEffect(() => {
if (!editProfileResult) return
const { success } = editProfileResult
if (success) {
history.push({
pathname: '/profile',
state: true
})
} else if (!success) {
setOpenSnackbar({
show: true,
message: t('editProfile.duringSaveProfileData'),
severity: 'error'
})
}
}, [t, history, editProfileResult])
useEffect(() => {
if (errorProfile) {
if (errorProfile.message === 'GraphQL error: Could not verify JWT: JWTExpired') {
logout()
history.push('/')
} else history.push('/internal-error')
}
}, [logout, history, errorProfile])
useEffect(() => {
if (errorRevokeConsent || errorGrantConsent || errorEditResults) {
setOpenSnackbar({
show: true,
message: t('editProfile.duringSaveProfileData'),
severity: 'error'
})
}
}, [t, errorRevokeConsent, errorGrantConsent, errorEditResults])
return (
<>
{isDesktop && (
<Box className={classes.wrapper}>
{loading && <CircularProgress />}
{!loading && currentUser && profile?.role === 'donor' && (
<Suspense fallback={<CircularProgress />}>
<EditProfileDonor
profile={profile}
onConsentChange={handleConsentChange}
loading={grantConsentLoading || revokeConsentLoading || editLoading}
onSubmit={handleUpdateUser}
/>
</Suspense>
)}
{!loading && currentUser && profile?.role === 'sponsor' && (
<Suspense fallback={<CircularProgress />}>
<EditProfileSponsor
profile={profile}
onSubmit={handleUpdateUser}
loading={editLoading}
/>
</Suspense>
)}
{!loading && currentUser && profile?.role === 'lifebank' && (
<Suspense fallback={<CircularProgress />}>
<EditProfileBank
profile={profile}
userName={profile.username}
onSubmit={handleUpdateUser}
loading={editLoading}
/>
</Suspense>
)}
</Box >
)}
{!isDesktop && (
<Box className={classes.wrapperMobile}>
{loading && <CircularProgress />}
{!loading && currentUser && profile?.role === 'lifebank' && (
<Suspense fallback={<CircularProgress />}>
<EditProfileBankMobile
profile={profile}
userName={profile.username}
onSubmit={handleUpdateUser}
loading={editLoading}
/>
</Suspense>
)}
{!loading && currentUser && profile?.role === 'sponsor' && (
<Suspense fallback={<CircularProgress />}>
<EditProfileSponsorMobile
profile={profile}
onSubmit={handleUpdateUser}
loading={editLoading}
/>
</Suspense>
)}
{!loading && currentUser && profile?.role === 'donor' && (
<Suspense fallback={<CircularProgress />}>
<EditProfileDonor
profile={profile}
onConsentChange={handleConsentChange}
loading={grantConsentLoading || revokeConsentLoading || editLoading}
onSubmit={handleUpdateUser}
/>
</Suspense>
)}
</Box>
)}
<Snackbar open={openSnackbar.show} autoHideDuration={4000} onClose={handleCloseSnackBar}>
<Alert
severity={openSnackbar.severity}
action={
<IconButton
aria-label="close"
color="inherit"
size="small"
onClick={handleCloseSnackBar}
>
<CloseIcon fontSize="inherit" />
</IconButton>
}
>
<AlertTitle>{t('editProfile.error')}</AlertTitle>
{openSnackbar.message}
</Alert>
</Snackbar>
</>
)
}
Example #15
Source File: TopicTree.js From management-center with Apache License 2.0 | 4 votes |
TopicTree = ({ topicTree, lastUpdated, currentConnectionName, settings }) => {
const classes = useStyles();
const [messageHistory, setMessageHistory] = React.useState([]);
const [selectedNode, setSelectedNode] = React.useState({});
const [selectedNodeId, setSelectedNodeId] = React.useState('');
useEffect(() => {
const parts = selectedNodeId.split('/');
parts.shift();
let current = topicTree.topicTree;
parts.forEach((part, index) => {
if (current[part]) {
current = current[part];
}
});
current = Object.assign({}, current);
current._received = Date.now();
if (current._message !== selectedNode?._message // if new message
&& current._messagesCounter > selectedNode?._messagesCounter) // quick fix
{
setSelectedNode(current);
messageHistory.unshift(current);
setMessageHistory(messageHistory.slice(0, 51));
}
})
const onLabelClick = (node) => {
setSelectedNode(node);
setSelectedNodeId(node.id);
setMessageHistory([]);
};
const data = generateTreeData('topic-tree-root', 'Topic Tree', topicTree);
useEffect(() => {
setSelectedNode(null);
setSelectedNodeId('');
setMessageHistory([]);
}, [currentConnectionName]);
const renderTree = (node) => (
<StyledTreeItem
nodeId={node.id}
labelText={node.name}
onLabelClick={() => {
onLabelClick(node);
}}
// labelIcon={InfoIcon}
message={isJSON(node._message) ? null : node._message}
topicsCounter={node._topicsCounter}
labelInfo={node._messagesCounter}
// color="#e3742f"
// bgColor="#fcefe3"
>
{/* <TreeItem key={node.id} nodeId={node.id} label={node.name}> */}
{Array.isArray(node.children) ? node.children.map((childNode) => renderTree(childNode)) : null}
{/* </TreeItem> */}
</StyledTreeItem>
);
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/system">
System
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Topic Tree
</Typography>
</Breadcrumbs>
{(settings?.topicTreeEnabled === false) ? <><br/><Alert severity="warning">
<AlertTitle>Topic tree not enabled</AlertTitle>
The MMC is currently not collecting topic tree data. If you want to collect data, please enable the topic tree feature in the settings page.
Note that if you enable this setting and the MMC is collecting topic tree data, the performance of the MMC backend might decrease.
</Alert></> : null}
<br />
<Grid container spacing={3}>
<Grid item xs={6}>
<Paper className={classes.paper}>
<TreeView
className={classes.root}
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
// defaultExpanded={["topic-tree-root"]}
>
{renderTree(data)}
</TreeView>
</Paper>
</Grid>
<Grid item xs={6}>
<Paper className={classes.paper}>
<TableContainer component={Paper} className={classes.table}>
<Table size="medium">
<TableBody>
{selectedNode?._name && (
<TableRow>
<TableCell>
<strong>Name</strong>
</TableCell>
<TableCell>{selectedNode?._name}</TableCell>
</TableRow>
)}
{selectedNode?._topic && (
<TableRow>
<TableCell>
<strong>Topic</strong>
</TableCell>
<TableCell>{selectedNode?._topic}</TableCell>
</TableRow>
)}
{selectedNode?._created && (
<TableRow>
<TableCell>
<strong>Created</strong>
</TableCell>
<TableCell>{moment(selectedNode?._created).format('LLLL')}</TableCell>
</TableRow>
)}
{selectedNode?._lastModified && (
<TableRow>
<TableCell>
<strong>Last modified</strong>
</TableCell>
<TableCell>{moment(selectedNode?._lastModified).format('LLLL')}</TableCell>
</TableRow>
)}
{typeof selectedNode?._qos === 'number' && (
<TableRow>
<TableCell>
<strong>QoS</strong>
</TableCell>
<TableCell>{selectedNode?._qos}</TableCell>
</TableRow>
)}
{(selectedNode?._retain === false || selectedNode?._retain === true) && (
<TableRow>
<TableCell>
<strong>Retain</strong>
</TableCell>
<TableCell>{selectedNode?._retain ? 'yes' : 'no'}</TableCell>
</TableRow>
)}
{selectedNode?._topicsCounter >= 0 && (
<TableRow>
<TableCell>
<strong>Sub topics</strong>
</TableCell>
<TableCell>{selectedNode?._topicsCounter}</TableCell>
</TableRow>
)}
{selectedNode?._messagesCounter && (
<TableRow>
<TableCell>
<strong>Total messages</strong>
</TableCell>
<TableCell>{selectedNode?._messagesCounter}</TableCell>
</TableRow>
)}
{/* {selectedNode?._message && selectedNode?._message.startsWith('{') && ( */}
{selectedNode?._message && (
<TableRow>
<TableCell
className={classes.payloadHistory}
>
<strong>Payload</strong>
</TableCell>
<TableCell>
<TextareaAutosize
className={classes.payloadDetail}
rows={5}
value={
isJSON(selectedNode?._message)
? prettifyJSON(selectedNode?._message)
: selectedNode?._message
}
/>
</TableCell>
</TableRow>
)}
{/* {selectedNode?._message && !selectedNode?._message.startsWith('{') && (
<TableRow>
<TableCell>
<strong>Payload</strong>
</TableCell>
<TableCell>{selectedNode?._message}</TableCell>
</TableRow>
)} */}
</TableBody>
</Table>
</TableContainer>
<TableContainer component={Paper} className={classes.table}>
<Table size="medium">
<TableBody>
{/* TODO: extract as component */}
{messageHistory ? messageHistory.map((entry, index) => {
if (index > 0) {
// if (entry?._message && entry?._message.startsWith('{')) {
if (entry?._message) {
return <TableRow>
<TableCell
className={classes.payloadHistory}
>
<strong>{moment(entry._received).format('HH:mm:ss:SSS')}</strong>
</TableCell>
<TableCell>
<TextareaAutosize
className={classes.payloadDetail}
rows={5}
value={
isJSON(entry?._message)
? prettifyJSON(entry?._message)
: entry?._message
}
/>
</TableCell>
</TableRow>
// } else if(entry?._message && !entry?._message.startsWith('{')) {
// return <TableRow>
// <TableCell>
// <strong>{moment(entry._received).format('HH:mm:ss:SSS')}</strong>
// </TableCell>
// <TableCell>{entry?._message}</TableCell>
// </TableRow>
}
}
}) : null }
</TableBody>
</Table>
</TableContainer>
</Paper>
</Grid>
</Grid>
{topicTree && <div style={{
fontSize: '0.9em',
position: 'absolute',
right: '15px',
top: '70px'
}}>
Topic tree last updated at: {moment(lastUpdated).format('hh:mm:ss a')}
</div>}
</div>
);
}
Example #16
Source File: Streams.js From management-center with Apache License 2.0 | 4 votes |
Streams = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client: brokerClient } = context;
const { streamprocessingFeature, connectionID, streams = [], onSort, sortBy, sortDirection } = props;
const [replayStreamEditorOpen, setReplayStreamEditorOpen] = React.useState(false);
const [replayStream, setReplayStream] = React.useState({});
const handleClickReplayStreamEditorOpen = () => {
setReplayStreamEditorOpen(true);
};
const handleReplayStreamEditorClose = () => {
setReplayStreamEditorOpen(false);
};
const handleReplay = async (stream, { replayTopic, gte, lte, reverse, limit, speed }) => {
try {
await brokerClient.replayStream({
streamname: stream.streamname,
replayTopic,
gte,
lte,
reverse,
limit,
speed
});
const streams = await brokerClient.listStreams();
dispatch(updateStreams(streams));
enqueueSnackbar(`Successfully started replay of stream "${stream.streamname}"`, {
variant: 'success'
});
setReplayStreamEditorOpen(false);
} catch (error) {
enqueueSnackbar(`Error starting replay of stream "${stream.streamname}". Reason: ${error}`, {
variant: 'error'
});
setReplayStreamEditorOpen(false);
}
}
const onNewStream = () => {
history.push('/streams/new');
};
const onReload = async () => {
const streams = await brokerClient.listStreams();
dispatch(updateStreams(streams));
}
const onDisableStream = async (streamname) => {
await confirm({
title: 'Confirm stream disable',
description: `Do you really want to disable stream "${streamname}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
await brokerClient.disableStream(streamname);
const streams = await brokerClient.listStreams();
enqueueSnackbar('Stream successfully disabled', {
variant: 'success'
});
dispatch(updateStreams(streams));
};
const onEnableStream = async (streamname) => {
await brokerClient.enableStream(streamname);
const streams = await brokerClient.listStreams();
enqueueSnackbar('Stream successfully enabled', {
variant: 'success'
});
dispatch(updateStreams(streams));
};
const onEnableProcessStream = async (streamname) => {
await brokerClient.processStream(streamname, true);
const streams = await brokerClient.listStreams();
enqueueSnackbar('Stream processing successfully enabled', {
variant: 'success'
});
dispatch(updateStreams(streams));
};
const onDisableProcessStream = async (streamname) => {
await brokerClient.processStream(streamname, false);
const streams = await brokerClient.listStreams();
enqueueSnackbar('Stream processing successfully disabled', {
variant: 'success'
});
dispatch(updateStreams(streams));
};
const onEnablePersistStream = async (streamname) => {
await brokerClient.persistStream(streamname, true);
const streams = await brokerClient.listStreams();
enqueueSnackbar('Stream persistence successfully enabled', {
variant: 'success'
});
dispatch(updateStreams(streams));
};
const onDisablePersistStream = async (streamname) => {
await brokerClient.persistStream(streamname, false);
const streams = await brokerClient.listStreams();
enqueueSnackbar('Stream persistence successfully disabled', {
variant: 'success'
});
dispatch(updateStreams(streams));
};
const onSelectStream = async (streamname) => {
const stream = await brokerClient.getStream(streamname);
dispatch(updateStream(stream));
history.push(`/streams/detail/${streamname}`);
};
const onClearStreamMessages = async (streamname) => {
await confirm({
title: 'Confirm clear all stream messages',
description: `Do you really want to clear all messages in the stream "${streamname}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
try {
await brokerClient.clearStreamMessages(streamname);
enqueueSnackbar(`Messages from stream "${streamname}" successfully cleared.`, {
variant: 'success'
});
} catch(error) {
enqueueSnackbar(`Error clearing messages from "${streamname}". Reason: ${error}`, {
variant: 'error'
});
}
};
const onReplayStream = async (stream) => {
setReplayStream(stream);
setReplayStreamEditorOpen(true);
};
const onDeleteStream = async (streamname) => {
await confirm({
title: 'Confirm stream deletion',
description: `Do you really want to delete stream "${streamname}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
await brokerClient.deleteStream(streamname);
enqueueSnackbar(`Stream "${streamname}" successfully deleted`, {
variant: 'success'
});
const streams = await brokerClient.listStreams();
dispatch(updateStreams(streams));
};
return (
<div>
<ReplayStreamDialog
stream={replayStream}
open={replayStreamEditorOpen}
handleReplay={handleReplay}
handleClose={handleReplayStreamEditorClose}
/>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Streams
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{streamprocessingFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Enterprise Solution feature</AlertTitle>
Streams are a premium feature. For more information visit <a className={classes.link} href="https://www.cedalo.com">cedalo.com</a> or contact us at <a className={classes.link} href="mailto:[email protected]">[email protected]</a>.
</Alert></> : null}
{streamprocessingFeature?.supported !== false && <Grid container spacing={1} alignItems="flex-end">
<Grid item xs={6}>
<Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewStream();
}}
>
New Stream
</Button>
</Grid>
<Grid item xs={6}>
<Box display="flex" flexDirection="row-reverse">
<Tooltip title="Reload streams">
<IconButton
color="secondary"
aria-label="Reload streams"
component="span"
onClick={(event) => {
event.stopPropagation();
onReload();
}}
>
<ReloadIcon />
</IconButton>
</Tooltip>
</Box>
</Grid>
</Grid>}
<br />
{streamprocessingFeature?.supported !== false && streams && streams.length > 0 ? (
<div>
<Hidden xsDown implementation="css">
<TableContainer component={Paper} className={classes.tableContainer}>
<Table size="medium">
<TableHead>
<TableRow>
{STREAM_TABLE_COLUMNS.map((column) => (
<TableCell
key={column.id}
sortDirection={sortBy === column.id ? sortDirection : false}
>
{/* <TableSortLabel
active={sortBy === column.id}
direction={sortDirection}
onClick={() => onSort(column.id)}
> */}
{column.key}
{/* </TableSortLabel> */}
</TableCell>
))}
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{streams &&
streams.map((stream) => (
<StyledTableRow
hover
key={stream.streamname}
onClick={(event) => {
if (
event.target.nodeName?.toLowerCase() === 'td'
) {
onSelectStream(stream.streamname);
}
}}
>
<TableCell>{stream.streamname}</TableCell>
<TableCell>{stream.textdescription}</TableCell>
<TableCell>{stream.sourcetopic}</TableCell>
<TableCell>{stream.targettopic}</TableCell>
<TableCell>{stream.targetqos}</TableCell>
<TableCell>{stream.ttl}</TableCell>
{/* <TableCell>{stream.replaying ? "replaying" : "stopped"}</TableCell> */}
<TableCell>
<Tooltip title="Process stream">
<Switch
checked={
typeof stream.process === 'undefined' ||
stream.process === true
}
onClick={(event) => {
event.stopPropagation();
if (event.target.checked) {
onEnableProcessStream(stream.streamname);
} else {
onDisableProcessStream(stream.streamname);
}
}}
/>
</Tooltip>
</TableCell>
<TableCell>
<Tooltip title="Persist stream">
<Switch
checked={
typeof stream.persist === 'undefined' ||
stream.persist === true
}
onClick={(event) => {
event.stopPropagation();
if (event.target.checked) {
onEnablePersistStream(stream.streamname);
} else {
onDisablePersistStream(stream.streamname);
}
}}
/>
</Tooltip>
</TableCell>
<TableCell>
<Tooltip title="Activate / Deactivate stream">
<Switch
checked={
typeof stream.active === 'undefined' ||
stream.active === true
}
onClick={(event) => {
event.stopPropagation();
if (event.target.checked) {
onEnableStream(stream.streamname);
} else {
onDisableStream(stream.streamname);
}
}}
/>
</Tooltip>
</TableCell>
<TableCell align="right">
<Tooltip title="Clear stream messages">
<IconButton
disabled={!stream.persist}
size="small"
onClick={(event) => {
event.stopPropagation();
onClearStreamMessages(stream.streamname);
}}
>
<ClearStreamIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Replay stream">
<IconButton
disabled={!stream.persist}
size="small"
onClick={(event) => {
event.stopPropagation();
onReplayStream(stream);
}}
>
<ReplayIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Delete stream">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteStream(stream.streamname);
}}
>
<DeleteIcon fontSize="small" />
</IconButton>
</Tooltip>
</TableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Hidden>
<Hidden smUp implementation="css">
<Paper>
<List className={classes.root}>
{streams.map((stream) => (
<React.Fragment>
<ListItem
alignItems="flex-start"
onClick={(event) => onSelectStream(stream.streamname)}
>
<ListItemText
primary={<span>{stream.streamname}</span>}
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
className={classes.inline}
color="textPrimary"
>
{stream.streamname}
</Typography>
</React.Fragment>
}
/>
<ListItemSecondaryAction>
<IconButton
edge="end"
size="small"
onClick={(event) => {
event.stopPropagation();
onSelectStream(stream.streamname);
}}
aria-label="edit"
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
edge="end"
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteStream(stream.streamname);
}}
aria-label="delete"
>
<DeleteIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Paper>
</Hidden>
</div>
) : (
<div>No streams found</div>
)}
</div>
);
}
Example #17
Source File: Status.js From management-center with Apache License 2.0 | 4 votes |
Status = ({ brokerLicense, brokerLicenseLoading, lastUpdated, systemStatus, defaultClient, currentConnection, currentConnectionName }) => {
const classes = useStyles();
const totalMessages = parseInt(systemStatus?.$SYS?.broker?.messages?.sent);
const publishMessages = (parseInt(systemStatus?.$SYS?.broker?.publish?.messages?.sent) / totalMessages) * 100;
const otherMessages =
((totalMessages - parseInt(systemStatus?.$SYS?.broker?.publish?.messages?.sent)) / totalMessages) * 100;
const data = {
datasets: [
{
data: [publishMessages, otherMessages],
backgroundColor: [colors.indigo[500], colors.red[600], colors.orange[600]],
borderWidth: 8,
borderColor: colors.common.white,
hoverBorderColor: colors.common.white
}
],
labels: ['PUBLISH', 'Other']
};
const dataDescriptions = [
{
title: 'PUBLISH',
value: Math.round(publishMessages),
icon: MessageIcon,
color: colors.indigo[500]
},
{
title: 'Other',
value: Math.round(otherMessages),
icon: MessageIcon,
color: colors.red[600]
}
];
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/system">
System
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Status
</Typography>
</Breadcrumbs>
<br />
{systemStatus?.$SYS ? <Container maxWidth={false}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="h5" component="div" gutterBottom>
{currentConnectionName}
</Typography>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="Clients total"
value={systemStatus?.$SYS?.broker?.clients?.total}
icon={<ClientIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="Subscriptions"
value={systemStatus?.$SYS?.broker?.subscriptions?.count}
icon={<SubscriptionIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="PUBLISH received"
value={systemStatus?.$SYS?.broker?.publish?.messages?.received}
icon={<MessageIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="PUBLISH sent"
value={systemStatus?.$SYS?.broker?.publish?.messages?.sent}
icon={<MessageIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="Bytes received"
value={systemStatus?.$SYS?.broker?.bytes?.received}
icon={<DataReceivedIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="Bytes sent"
value={systemStatus?.$SYS?.broker?.bytes?.sent}
icon={<DataSentIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="Total received"
value={systemStatus?.$SYS?.broker?.messages?.received}
icon={<MessageIcon />}
/>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<Info
label="Total messages sent"
value={systemStatus?.$SYS?.broker?.messages?.sent}
icon={<MessageIcon />}
/>
</Grid>
<Grid item lg={4} sm={4} xl={4} xs={12}>
<TableContainer component={Paper}>
<Table className={classes.table}>
<TableHead>
<TableCell colSpan={2}>Broker</TableCell>
</TableHead>
<TableBody>
<TableRow key="version">
<TableCell component="th" scope="row">
Broker version
</TableCell>
<TableCell align="right">{systemStatus?.$SYS?.broker?.version}</TableCell>
</TableRow>
<TableRow key="uptime">
<TableCell component="th" scope="row">
Uptime
</TableCell>
<TableCell align="right">{systemStatus?.$SYS?.broker?.uptime}</TableCell>
</TableRow>
<TableRow key="url">
<TableCell component="th" scope="row">
URL
</TableCell>
<TableCell align="right">{currentConnection?.url}</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Grid>
<Grid item lg={4} sm={4} xl={4} xs={12}>
<TableContainer component={Paper}>
<Table className={classes.table}>
<TableHead>
<TableCell colSpan={2}>Clients</TableCell>
</TableHead>
<TableBody>
<TableRow key="clients-total">
<TableCell component="th" scope="row">
Total clients
</TableCell>
<TableCell align="right">
{systemStatus?.$SYS?.broker?.clients?.total}
</TableCell>
</TableRow>
<TableRow key="clients-active">
<TableCell component="th" scope="row">
Active clients
</TableCell>
<TableCell align="right">
{systemStatus?.$SYS?.broker?.clients?.active}
</TableCell>
</TableRow>
<TableRow key="clients-connected">
<TableCell component="th" scope="row">
Connected clients
</TableCell>
<TableCell align="right">
{systemStatus?.$SYS?.broker?.clients?.connected}
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Grid>
<Grid item lg={4} sm={4} xl={4} xs={12}>
<TableContainer component={Paper}>
<Table className={classes.table}>
<TableHead>
<TableCell colSpan={2}>Messages</TableCell>
</TableHead>
<TableBody>
<TableRow key="messsages-received">
<TableCell component="th" scope="row">
Received messages
</TableCell>
<TableCell align="right">
{systemStatus?.$SYS?.broker?.messages?.received}
</TableCell>
</TableRow>
<TableRow key="messsages-sent">
<TableCell component="th" scope="row">
Sent messages
</TableCell>
<TableCell align="right">
{systemStatus?.$SYS?.broker?.messages?.sent}
</TableCell>
</TableRow>
<TableRow key="messsages-stored">
<TableCell component="th" scope="row">
Stored messages
</TableCell>
<TableCell align="right">
{systemStatus?.$SYS?.broker?.messages?.stored}
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Grid>
{/* <Grid item lg={3} sm={3} xl={3} xs={12}>
<Chart
title="Sent messages by type"
data={data}
dataDescriptions={dataDescriptions}
/>
</Grid> */}
<Grid item lg={12} sm={12} xl={12} xs={12}>
{brokerLicenseLoading ?
<Alert severity="info">
<AlertTitle>Loading license information</AlertTitle>
<CircularProgress color="secondary" />
</Alert> : null}
{brokerLicense ? <LicenseTable license={brokerLicense} /> : null}
</Grid>
</Grid>
</Container> : <Alert severity="warning">
<AlertTitle>System status information not accessible</AlertTitle>
We couldn't retrieve the system status information.
Please make sure that the user "{defaultClient?.username}" has the rights to read the "$SYS" topic on the selected broker.
</Alert>
}
{systemStatus?.$SYS && <div style={{
fontSize: '0.9em',
position: 'absolute',
right: '15px',
top: '70px'
}}>
Dashboard last updated at: {moment(lastUpdated).format('hh:mm:ss a')}
</div>}
</div>
);
}
Example #18
Source File: Roles.js From management-center with Apache License 2.0 | 4 votes |
Roles = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client } = context;
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);
const handleChangePage = async (event, newPage) => {
setPage(newPage);
const count = rowsPerPage;
const offset = newPage * rowsPerPage;
const roles = await client.listRoles(true, count, offset);
dispatch(updateRoles(roles));
};
const handleChangeRowsPerPage = async (event) => {
const rowsPerPage = parseInt(event.target.value, 10);
setRowsPerPage(rowsPerPage);
setPage(0);
const roles = await client.listRoles(true, rowsPerPage, 0);
dispatch(updateRoles(roles));
};
const onEditDefaultACLAccess = () => {
history.push('/security/acl');
}
const onNewRole = () => {
history.push('/security/roles/new');
};
const onDeleteRole = async (rolename) => {
await confirm({
title: 'Confirm role deletion',
description: `Do you really want to delete the role "${rolename}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
if (rolename === 'admin') {
await confirm({
title: 'Confirm default role deletion',
description: `Are you sure? You are about to delete the default role for the current Mosquitto instance.`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
}
await client.deleteRole(rolename);
enqueueSnackbar('Role successfully deleted', {
variant: 'success'
});
const roles = await client.listRoles(true, rowsPerPage, page * rowsPerPage);
dispatch(updateRoles(roles));
const clients = await client.listClients();
dispatch(updateClients(clients));
const groups = await client.listGroups();
dispatch(updateGroups(groups));
};
const onSelectRole = async (rolename) => {
const role = await client.getRole(rolename);
dispatch(updateRole(role));
history.push(`/security/roles/detail/${rolename}`);
};
const { dynamicsecurityFeature, defaultACLAccess, roles = [], onSort, sortBy, sortDirection } = props;
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/security">
Security
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Roles
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{dynamicsecurityFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that the broker connected has the dynamic security enabled.
</Alert></> : null}
<br />
{dynamicsecurityFeature?.supported !== false && <><Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewRole();
}}
>
New Role
</Button>
<Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<EditIcon />}
onClick={onEditDefaultACLAccess}
>
Edit default ACL access
</Button>
<br />
<br />
</>}
{dynamicsecurityFeature?.supported !== false && roles?.roles?.length > 0 ? (
<div>
<Hidden xsDown implementation="css">
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
{ROLE_TABLE_COLUMNS.map((column) => (
<TableCell
key={column.id}
sortDirection={sortBy === column.id ? sortDirection : false}
>
<TableSortLabel
active={sortBy === column.id}
direction={sortDirection}
onClick={() => onSort(column.id)}
>
{column.key}
</TableSortLabel>
</TableCell>
))}
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{roles.roles.map((role) => (
<TableRow
hover
key={role.rolename}
onClick={() => onSelectRole(role.rolename)}
style={{ cursor: 'pointer' }}
>
<TableCell>{role.rolename}</TableCell>
<TableCell>{role.textname}</TableCell>
<TableCell>{role.textdescription}</TableCell>
<TableCell align="right">
{/* <IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteRole(role.rolename);
}}
>
<EditIcon fontSize="small" />
</IconButton> */}
<Tooltip title="Delete role">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteRole(role.rolename);
}}
>
<DeleteIcon fontSize="small" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={8}
count={roles?.totalCount}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
</Hidden>
<Hidden smUp implementation="css">
<Paper>
<List className={classes.root}>
{roles.roles.map((role) => (
<React.Fragment>
<ListItem alignItems="flex-start">
<ListItemText
primary={<span>{role.rolename}</span>}
// secondary={
// <React.Fragment>
// <Typography
// component="span"
// variant="body2"
// className={classes.inline}
// color="textPrimary"
// >
// Role details
// </Typography>
// </React.Fragment>
// }
/>
<ListItemSecondaryAction>
<IconButton edge="end" size="small" aria-label="edit">
<EditIcon fontSize="small" />
</IconButton>
<IconButton edge="end" size="small" aria-label="delete">
<DeleteIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Paper>
</Hidden>
</div>
) : (
<div>No roles found</div>
)}
{/* <Fab
color="primary"
aria-label="add"
className={classes.fab}
onClick={(event) => {
event.stopPropagation();
onNewRole();
}}
>
<AddIcon />
</Fab> */}
</div>
);
}
Example #19
Source File: LicenseTable.js From management-center with Apache License 2.0 | 4 votes |
LicenseTable = (props) => {
const classes = useStyles();
const { license } = props;
return (
<div>
{
!license &&
<Alert severity="info">
<AlertTitle>No license information available</AlertTitle>
This broker does not provide any license information.
</Alert>
}
{license && license.edition && (
<TableContainer component={Paper} className={classes.tableContainer}>
<Table size="medium">
<TableBody>
<TableRow>
<TableCell>
<b>Edition</b>
</TableCell>
<TableCell>{license.edition === 'pro' ? getPremium() : license.edition}</TableCell>
</TableRow>
<TableRow>
<TableCell>
<b>Issued by</b>
</TableCell>
<TableCell>{license.issuedBy}</TableCell>
</TableRow>
{isPremiumLicense(license) && (
<TableRow>
<TableCell>
<b>Issued to</b>
</TableCell>
<TableCell>{license.issuedTo}</TableCell>
</TableRow>
)}
{isPremiumLicense(license) && (
<TableRow>
<TableCell>
<b>Valid since</b>
</TableCell>
<TableCell>{moment(license.validSince).format('LLLL')}</TableCell>
</TableRow>
)}
{isPremiumLicense(license) && (
<TableRow>
<TableCell>
<b>Valid until</b>
</TableCell>
<TableCell>{moment(license.validUntil).format('LLLL')}</TableCell>
</TableRow>
)}
{/* <TableRow>
<TableCell>
<b>Max. broker connections</b>
</TableCell>
<TableCell>{license.maxBrokerConnections}</TableCell>
</TableRow> */}
{/* <TableRow>
<TableCell>
<b>Advanced REST API</b>
</TableCell>
<TableCell>{createFeatureIcon('rest-api', license)}</TableCell>
</TableRow>
<TableRow>
<TableCell>
<b>Custom Theme</b>
</TableCell>
<TableCell>{createFeatureIcon('white-labeling', license)}</TableCell>
</TableRow> */}
{/* <TableRow>
<TableCell>
<b>? Import / Export</b>
</TableCell>
<TableCell>
{
createFeatureIcon('import-export', license)
}
</TableCell>
</TableRow> */}
{/* <TableRow>
<TableCell>
<b>Multiple Connections</b>
</TableCell>
<TableCell>{createFeatureIcon('multiple-broker-connections', license)}</TableCell>
</TableRow> */}
</TableBody>
</Table>
</TableContainer>
)}
<br />
{license?.features &&
<TableContainer component={Paper} className={classes.tableContainer}>
<Table size="medium">
<TableHead>
<TableRow>
<TableCell>
<b>Feature</b>
</TableCell>
<TableCell>
<b>Version</b>
</TableCell>
{/* <TableCell>
<b>Valid until</b>
</TableCell>
<TableCell>
<b>Valid since</b>
</TableCell> */}
</TableRow>
</TableHead>
<TableBody>
{license?.features.map(feature => (
<TableRow>
<TableCell>
{feature.name}
</TableCell>
<TableCell>
{feature.version}
</TableCell>
{/* <TableCell>
{moment(feature.validSince).format('LLLL')}
</TableCell>
<TableCell>
{moment(feature.validUntil).format('LLLL')}
</TableCell> */}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
}
</div>
);
}
Example #20
Source File: Groups.js From management-center with Apache License 2.0 | 4 votes |
Groups = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client } = context;
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);
const handleChangePage = async (event, newPage) => {
setPage(newPage);
const count = rowsPerPage;
const offset = newPage * rowsPerPage;
const groups = await client.listGroups(true, count, offset);
dispatch(updateGroups(groups));
};
const handleChangeRowsPerPage = async (event) => {
const rowsPerPage = parseInt(event.target.value, 10);
setRowsPerPage(rowsPerPage);
setPage(0);
const groups = await client.listGroups(true, rowsPerPage, 0);
dispatch(updateGroups(groups));
};
const onUpdateGroupClients = async (group, clients = []) => {
if (!clients) {
clients = [];
}
const clientNames = clients.map((client) => client.value);
await client.updateGroupClients(group, clientNames);
const groups = await client.listGroups(true, rowsPerPage, page * rowsPerPage);
dispatch(updateGroups(groups));
const clientsUpdated = await client.listClients();
dispatch(updateClients(clientsUpdated));
};
const onUpdateGroupRoles = async (group, roles = []) => {
if (!roles) {
roles = [];
}
const rolenames = roles.map((role) => role.value);
await client.updateGroupRoles(group, rolenames);
const groups = await client.listGroups(true, rowsPerPage, page * rowsPerPage);
dispatch(updateGroups(groups));
};
const onUpdateAnonymousGroup = async (groupname) => {
await client.setAnonymousGroup(groupname);
const group = await client.getAnonymousGroup();
dispatch(updateAnonymousGroup(group));
enqueueSnackbar('Anonymous group successfully set', {
variant: 'success'
});
}
const onSelectGroup = async (groupname) => {
const group = await client.getGroup(groupname);
dispatch(updateGroup(group));
history.push(`/security/groups/detail/${groupname}`);
};
const onNewGroup = () => {
history.push('/security/groups/new');
};
const onDeleteGroup = async (groupname) => {
await confirm({
title: 'Confirm group deletion',
description: `Do you really want to delete the group "${groupname}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
await client.deleteGroup(groupname);
enqueueSnackbar(`Group "${groupname}" successfully deleted`, {
variant: 'success'
});
const groups = await client.listGroups(true, rowsPerPage, page * rowsPerPage);
dispatch(updateGroups(groups));
const clients = await client.listClients();
dispatch(updateClients(clients));
};
const onRemoveClientFromGroup = async (username, group) => {
await client.removeGroupClient(username, group);
const groups = await client.listGroups(true, rowsPerPage, page * rowsPerPage);
dispatch(updateGroups(groups));
};
const { dynamicsecurityFeature, anonymousGroup, groups = [], rolesAll = [], clientsAll = [], onSort, sortBy, sortDirection } = props;
// TODO: probably extract into reducer
const clientSuggestions = clientsAll
.sort()
.map((username) => ({
label: username,
value: username
}));
const roleSuggestions = rolesAll
.sort()
.map((rolename) => ({
label: rolename,
value: rolename
}));
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/security">
Security
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Groups
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{dynamicsecurityFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that the broker connected has the dynamic security enabled.
</Alert></> : null}
<br />
{dynamicsecurityFeature?.supported !== false && <><Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewGroup();
}}
>
New Group
</Button>
<br />
<br />
</>}
{dynamicsecurityFeature?.supported !== false && groups?.groups?.length > 0 ? (
<div>
<Hidden xsDown implementation="css">
<TableContainer component={Paper} className={classes.tableContainer}>
<Table>
<TableHead>
<TableRow>
{GROUP_TABLE_COLUMNS.map((column) => (
<TableCell
key={column.id}
sortDirection={sortBy === column.id ? sortDirection : false}
>
<TableSortLabel
active={sortBy === column.id}
direction={sortDirection}
onClick={() => onSort(column.id)}
>
{column.key}
</TableSortLabel>
</TableCell>
))}
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{groups &&
groups.groups.map((group) => (
<TableRow
hover
key={group.groupname}
onClick={(event) => {
if (event.target.nodeName?.toLowerCase() === 'td') {
onSelectGroup(group.groupname);
}
}}
style={{ cursor: 'pointer' }}
>
<TableCell>{group.groupname}</TableCell>
<TableCell>{group.textname}</TableCell>
<TableCell>{group.textdescription}</TableCell>
<TableCell className={classes.badges}>
<AutoSuggest
suggestions={clientSuggestions}
values={group.clients.map((client) => ({
label: client.username,
value: client.username
}))}
handleChange={(value) => {
onUpdateGroupClients(group, value);
}}
/>
</TableCell>
<TableCell className={classes.badges}>
<AutoSuggest
suggestions={roleSuggestions}
values={group.roles.map((role) => ({
label: role.rolename,
value: role.rolename
}))}
handleChange={(value) => {
onUpdateGroupRoles(group, value);
}}
/>
</TableCell>
<TableCell align="right">
{/* <IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onSelectGroup(group.groupname);
}}
>
<EditIcon fontSize="small" />
</IconButton> */}
<Tooltip title="Delete group">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteGroup(group.groupname);
}}
>
<DeleteIcon fontSize="small" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={8}
count={groups?.totalCount}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
</Hidden>
<Hidden smUp implementation="css">
<Paper>
<List className={classes.root}>
{groups.groups.map((group) => (
<React.Fragment>
<ListItem
alignItems="flex-start"
onClick={(event) => onSelectGroup(group.groupname)}
>
<ListItemText
primary={<span>{group.groupname}</span>}
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
className={classes.inline}
color="textPrimary"
>
{group.textname}
</Typography>
<span> — {group.textdescription} </span>
</React.Fragment>
}
/>
<ListItemSecondaryAction>
<IconButton
edge="end"
size="small"
onClick={(event) => {
event.stopPropagation();
onSelectGroup(group.groupname);
}}
aria-label="edit"
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
edge="end"
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteGroup(group.groupname);
}}
aria-label="delete"
>
<DeleteIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Paper>
</Hidden>
<AnonymousGroupSelect
onUpdateAnonymousGroup={onUpdateAnonymousGroup}
/>
</div>
) : (
<div>No groups found</div>
)}
{/* <Fab
color="primary"
aria-label="add"
className={classes.fab}
onClick={(event) => {
event.stopPropagation();
onNewGroup();
}}
>
<AddIcon />
</Fab> */}
</div>
);
}
Example #21
Source File: Clients.js From management-center with Apache License 2.0 | 4 votes |
Clients = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client: brokerClient } = context;
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);
const handleChangePage = async (event, newPage) => {
setPage(newPage);
const count = rowsPerPage;
const offset = newPage * count;
const clients = await brokerClient.listClients(true, count, offset);
dispatch(updateClients(clients));
};
const handleChangeRowsPerPage = async (event) => {
const rowsPerPage = parseInt(event.target.value, 10);
setRowsPerPage(rowsPerPage);
setPage(0);
const clients = await brokerClient.listClients(true, rowsPerPage, 0);
dispatch(updateClients(clients));
};
const onUpdateClientGroups = async (client, groups = []) => {
if (!groups) {
groups = [];
}
if (groups.length === 0) {
await confirm({
title: 'Confirm remove client from all groups',
description: `Do you really want to remove client "${client.username}" from all groups?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
}
const groupnames = groups.map((group) => group.value);
await brokerClient.updateClientGroups(client, groupnames);
const clients = await brokerClient.listClients(true, rowsPerPage, page * rowsPerPage);
dispatch(updateClients(clients));
const groupsUpdated = await brokerClient.listGroups();
dispatch(updateGroups(groupsUpdated));
};
const onUpdateClientRoles = async (client, roles = []) => {
if (!roles) {
roles = [];
}
const rolenames = roles.map((role) => role.value);
await brokerClient.updateClientRoles(client, rolenames);
const clients = await brokerClient.listClients(true, rowsPerPage, page * rowsPerPage);
dispatch(updateClients(clients));
};
const onSelectClient = async (username) => {
const client = await brokerClient.getClient(username);
dispatch(updateClient(client));
history.push(`/security/clients/detail/${username}`);
};
const onNewClient = () => {
history.push('/security/clients/new');
};
const onEditClient = async (username) => {
const client = await brokerClient.getClient(username);
dispatch(updateClient(client));
history.push(`/security/clients/detail/${username}/?action=edit`);
};
const onDeleteClient = async (username) => {
await confirm({
title: 'Confirm client deletion',
description: `Do you really want to delete client "${username}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
if (username === 'cedalo') {
await confirm({
title: 'Confirm default client deletion',
description: `Are you sure? You are about to delete the default client for the current Mosquitto instance.`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
}
await brokerClient.deleteClient(username);
enqueueSnackbar(`Client "${username}" successfully deleted`, {
variant: 'success'
});
const clients = await brokerClient.listClients(true, rowsPerPage, page * rowsPerPage);
dispatch(updateClients(clients));
const groups = await brokerClient.listGroups();
dispatch(updateGroups(groups));
};
const onDisableClient = async (username) => {
await confirm({
title: 'Confirm client disable',
description: `Do you really want to disable client "${username}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
await brokerClient.disableClient(username);
const clients = await brokerClient.listClients(true, rowsPerPage, page * rowsPerPage);
enqueueSnackbar('Client successfully disabled', {
variant: 'success'
});
dispatch(updateClients(clients));
};
const onEnableClient = async (username) => {
await brokerClient.enableClient(username);
const clients = await brokerClient.listClients(true, rowsPerPage, page * rowsPerPage);
enqueueSnackbar('Client successfully enabled', {
variant: 'success'
});
dispatch(updateClients(clients));
};
const onRemoveClientFromGroup = async (client, group) => {
await confirm({
title: 'Remove client from group',
description: `Do you really want to remove client "${client.username}" from group "${group}"?`
});
await client.removeGroupClient(client, group);
const clients = await brokerClient.listClients(true, rowsPerPage, page * rowsPerPage);
dispatch(updateClients(clients));
};
const { dynamicsecurityFeature, connectionID, defaultClient, groupsAll = [], rolesAll = [], clients = [], onSort, sortBy, sortDirection } = props;
const groupSuggestions = groupsAll
.sort()
.map((groupname) => ({
label: groupname,
value: groupname
}));
const roleSuggestions = rolesAll
.sort()
.map((rolename) => ({
label: rolename,
value: rolename
}));
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/security">
Security
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Clients
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{dynamicsecurityFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that the broker connected has the dynamic security enabled.
</Alert></> : null}
<br />
{dynamicsecurityFeature?.supported !== false && <><Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewClient();
}}
>
New Client
</Button>
<br />
<br />
</>}
{dynamicsecurityFeature?.supported !== false && clients?.clients?.length > 0 ? (
<div>
<Hidden xsDown implementation="css">
<TableContainer component={Paper} className={classes.tableContainer}>
<Table size="medium">
<TableHead>
<TableRow>
{USER_TABLE_COLUMNS.map((column) => (
<TableCell
key={column.id}
sortDirection={sortBy === column.id ? sortDirection : false}
>
{/* <TableSortLabel
active={sortBy === column.id}
direction={sortDirection}
onClick={() => onSort(column.id)}
> */}
{column.key}
{/* </TableSortLabel> */}
</TableCell>
))}
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{clients &&
clients.clients.map((client) => (
<StyledTableRow
hover
key={client.username}
onClick={(event) => {
if (
event.target.nodeName?.toLowerCase() === 'td' ||
defaultClient?.username === client.username
) {
onSelectClient(client.username);
}
}}
style={{ cursor: 'pointer' }}
>
<TableCell>{client.username}</TableCell>
<TableCell>{client.clientid}</TableCell>
<TableCell>{client.textname}</TableCell>
<TableCell>{client.textdescription}</TableCell>
<TableCell className={classes.badges}>
<AutoSuggest
disabled={defaultClient?.username === client.username}
suggestions={groupSuggestions}
values={client.groups.map((group) => ({
label: group.groupname,
value: group.groupname
}))}
handleChange={(value) => {
onUpdateClientGroups(client, value);
}}
/>
</TableCell>
<TableCell className={classes.badges}>
<AutoSuggest
disabled={defaultClient?.username === client.username}
suggestions={roleSuggestions}
values={client.roles.map((role) => ({
label: role.rolename,
value: role.rolename
}))}
handleChange={(value) => {
onUpdateClientRoles(client, value);
}}
/>
</TableCell>
<TableCell align="right">
{/* <IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onEditClient(client.username);
}}
>
<EditIcon fontSize="small" />
</IconButton> */}
<Tooltip title="Delete client">
<IconButton
disabled={defaultClient?.username === client.username}
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteClient(client.username);
}}
>
<DeleteIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Enable / disable client">
<Switch
disabled={defaultClient?.username === client.username}
checked={
typeof client.disabled === 'undefined' ||
client.disabled === false
}
onClick={(event) => {
event.stopPropagation();
if (event.target.checked) {
onEnableClient(client.username);
} else {
onDisableClient(client.username);
}
}}
/>
</Tooltip>
</TableCell>
</StyledTableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={8}
count={clients?.totalCount}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
</Hidden>
<Hidden smUp implementation="css">
<Paper>
<List className={classes.root}>
{clients.clients.map((client) => (
<React.Fragment>
<ListItem
alignItems="flex-start"
onClick={(event) => onSelectClient(client.username)}
>
<ListItemText
primary={<span>{client.username}</span>}
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
className={classes.inline}
color="textPrimary"
>
{client.textname}
</Typography>
<span> — {client.textdescription} </span>
{/* <div className={classes.badges}>
{client.groups.map((group) => (
<Chip
// icon={<FaceIcon />}
size="small"
label={group}
onDelete={(event) => {
event.stopPropagation();
onRemoveClientFromGroup(client, group);
}}
color="secondary"
/>
))}
</div> */}
</React.Fragment>
}
/>
<ListItemSecondaryAction>
<IconButton
edge="end"
size="small"
onClick={(event) => {
event.stopPropagation();
onSelectClient(client.username);
}}
aria-label="edit"
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
edge="end"
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteClient(client.username);
}}
aria-label="delete"
>
<DeleteIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Paper>
</Hidden>
</div>
) : (
<div>No clients found</div>
)}
{/* <Fab
color="primary"
aria-label="add"
className={classes.fab}
onClick={(event) => {
event.stopPropagation();
onNewClient();
}}
>
<AddIcon />
</Fab> */}
</div>
);
}
Example #22
Source File: Users.js From management-center with Apache License 2.0 | 4 votes |
Users = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client: brokerClient } = context;
const { userManagementFeature, userProfile, roles = [], users = [], onSort, sortBy, sortDirection } = props;
const onUpdateUserRoles = async (user, roles = []) => {
if (!roles) {
roles = [];
}
const rolenames = roles.map((role) => role.value);
await brokerClient.updateUserRoles(user, rolenames);
const users = await brokerClient.listUsers();
dispatch(updateUsers(users));
};
const onSelectUser = async (username) => {
const user = await brokerClient.getUser(username);
dispatch(updateUser(user));
history.push(`/admin/users/detail/${username}`);
};
const onNewUser = () => {
history.push('/admin/users/new');
};
const onDeleteUser = async (username) => {
await confirm({
title: 'Confirm user deletion',
description: `Do you really want to delete user "${username}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
if (username === userProfile.username) {
await confirm({
title: 'Confirm user deletion',
description: `Are you sure? You are about to delete the user that you are currently using. If you proceed you will be logged out and cannot access the system any longer with that user.`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
window.location.href = '/logout';
}
await brokerClient.deleteUser(username);
enqueueSnackbar(`User "${username}" successfully deleted`, {
variant: 'success'
});
const users = await brokerClient.listUsers();
dispatch(updateUsers(users));
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/admin">
Admin
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Users
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{userManagementFeature?.error ? <><br/><Alert severity="warning">
<AlertTitle>{userManagementFeature.error.title}</AlertTitle>
{userManagementFeature.error.message}
</Alert></> : null}
{!userManagementFeature?.error && userManagementFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that this feature is included in your MMC license.
</Alert></> : null}
<br />
{!userManagementFeature?.error && userManagementFeature?.supported !== false && <><Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewUser();
}}
>
New User
</Button>
<br />
<br />
</>}
{ createUserTable(users, classes, props, onDeleteUser, onUpdateUserRoles, onSelectUser) }
</div>
);
}
Example #23
Source File: UserNew.js From management-center with Apache License 2.0 | 4 votes |
UserNew = (props) => {
const { users, userRoles = [], userManagementFeature } = props;
const classes = useStyles();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [passwordConfirm, setPasswordConfirm] = useState('');
const [roles, setRoles] = useState([]);
const roleSuggestions = userRoles
.sort()
.map((rolename) => ({
label: rolename,
value: rolename
}));
const usernameExists = props?.users?.find((searchUser) => {
return searchUser.username === username;
});
const passwordsMatch = password === passwordConfirm;
const validate = () => {
const valid = passwordsMatch
&& !usernameExists
&& username !== ''
&& password !== ''
&& username.match(/^[0-9a-zA-Z]+$/);
return valid;
};
const { enqueueSnackbar } = useSnackbar();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { client } = context;
const onSaveUser = async () => {
try {
await client.createUser(username, password, roles);
const users = await client.listUsers();
dispatch(updateUsers(users));
history.push(`/admin/users`);
enqueueSnackbar(`User "${username}" successfully created.`, {
variant: 'success'
});
} catch (error) {
enqueueSnackbar(`Error creating user "${username}". Reason: ${error.message || error}`, {
variant: 'error'
});
throw error;
}
};
const onCancel = async () => {
await confirm({
title: 'Cancel user creation',
description: `Do you really want to cancel creating this user?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
history.goBack();
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/security">
Admin
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Users
</Typography>
</Breadcrumbs>
<br />
{/* TODO: Quick hack to detect whether feature is supported */}
{userManagementFeature?.error ? <><br /><Alert severity="warning">
<AlertTitle>{userManagementFeature.error.title}</AlertTitle>
{userManagementFeature.error.message}
</Alert></> : null}
{!userManagementFeature?.error && <div className={classes.root}>
<Paper>
<form className={classes.form} noValidate autoComplete="off">
<div className={classes.margin}>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12}>
<TextField
error={usernameExists}
helperText={usernameExists && 'A user with this username already exists.'}
required
id="username"
label="User name"
onChange={(event) => setUsername(event.target.value)}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
id="password"
label="Password"
error={!passwordsMatch}
helperText={!passwordsMatch && 'Passwords must match.'}
onChange={(event) => setPassword(event.target.value)}
defaultValue=""
variant="outlined"
fullWidth
type="password"
className={classes.textField}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PasswordIcon />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
id="password-confirm"
label="Password Confirm"
error={!passwordsMatch}
helperText={!passwordsMatch && 'Passwords must match.'}
onChange={(event) => setPasswordConfirm(event.target.value)}
defaultValue=""
variant="outlined"
fullWidth
type="password"
className={classes.textField}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PasswordIcon />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12}>
<AutoSuggest
placeholder="Select roles..."
suggestions={roleSuggestions}
values={roles?.map((role) => ({
label: role,
value: role
}))}
handleChange={(value) => {
setRoles(value.map((role) => role.value));
}}
/>
</Grid>
<Grid container xs={12} alignItems="flex-start">
<Grid item xs={12} className={classes.buttons}>
<SaveCancelButtons
onSave={onSaveUser}
saveDisabled={!validate()}
onCancel={onCancel}
/>
</Grid>
</Grid>
</Grid>
</div>
</form>
</Paper>
</div>}
</div>
);
}
Example #24
Source File: Clusters.js From management-center with Apache License 2.0 | 4 votes |
Clusters = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client: brokerClient } = context;
const [progressDialogOpen, setProgressDialogOpen] = React.useState(false);
const { clusterManagementFeature, clusters = [], onSort, sortBy, sortDirection } = props;
const onSelectCluster = async (clustername, numberOfNodes) => {
setProgressDialogOpen(true);
try {
const cluster = await brokerClient.getCluster(clustername, numberOfNodes);
dispatch(updateCluster(cluster));
setProgressDialogOpen(false);
history.push(`/admin/clusters/detail/${clustername}`);
} catch(error) {
enqueueSnackbar(`Cluster loading failed. Reason: ${error.message || error}`, {
variant: 'error'
});
}
};
const onNewCluster = () => {
history.push('/admin/clusters/new');
};
const onCheckHealthStatus = async (clustername) => {
try {
const healtStatus = await brokerClient.checkClusterHealthStatus(clustername);
if (healtStatus.error) {
const error = healtStatus.error;
enqueueSnackbar(`Cluster health check failed. Reason: ${error.message || error}`, {
variant: 'error'
});
} else {
enqueueSnackbar(`Cluster "${clustername}" healthy`, {
variant: 'success'
});
}
} catch (error) {
enqueueSnackbar(`Cluster health check failed. Reason: ${error.message || error}`, {
variant: 'error'
});
}
};
const onDeleteCluster = async (clustername) => {
await confirm({
title: 'Confirm cluster deletion',
description: `Do you really want to delete cluster "${clustername}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
await brokerClient.deleteCluster(clustername);
enqueueSnackbar(`Cluster "${clustername}" successfully deleted`, {
variant: 'success'
});
const clusters = await brokerClient.listClusters();
dispatch(updateClusters(clusters));
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/admin">
Admin
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Clusters
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{clusterManagementFeature?.error ? <><br/><Alert severity="warning">
<AlertTitle>{clusterManagementFeature.error.title}</AlertTitle>
{clusterManagementFeature.error.message}
</Alert></> : null}
{!clusterManagementFeature?.error && clusterManagementFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that this feature is included in your MMC license.
</Alert></> : null}
<br />
{!clusterManagementFeature?.error && clusterManagementFeature?.supported !== false && <><Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewCluster();
}}
>
New Cluster
</Button>
<br />
<br />
<WaitDialog
title='Loading cluster details'
message='Note that this can take a while depending on the size and status of your cluster.'
open={progressDialogOpen}
handleClose={() => setProgressDialogOpen(false)}
/>
</>}
{ createClusterTable(clusters, classes, props, onCheckHealthStatus, onDeleteCluster, onSelectCluster) }
</div>
);
}
Example #25
Source File: ClusterNew.js From management-center with Apache License 2.0 | 4 votes |
ClusterNew = (props) => {
const { clusters, clusterManagementFeature } = props;
const classes = useStyles();
const [clustername, setClustername] = useState('Example');
const [clusterDescription, setClusterDescription] = useState('Example cluster');
const [node1, setNode1] = useState({
port: 7000
});
const [node2, setNode2] = useState({
port: 7000
});
const [node3, setNode3] = useState({
port: 7000
});
const clusternameExists = props?.clusters?.find((searchCluster) => {
return searchCluster.clustername === clustername;
});
const nodes = [
node1, node2, node3
];
const validate = () => {
const valid = !clusternameExists && clustername !== '';
return valid;
};
const { enqueueSnackbar } = useSnackbar();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { client } = context;
const onSaveCluster = async () => {
try {
await client.createCluster({
clustername,
description: clusterDescription,
nodes
});
const clusters = await client.listClusters();
dispatch(updateClusters(clusters));
history.push(`/admin/clusters`);
enqueueSnackbar(`Cluster "${clustername}" successfully created.`, {
variant: 'success'
});
} catch (error) {
enqueueSnackbar(`Error creating cluster "${clustername}". Reason: ${error.message || error}`, {
variant: 'error'
});
throw error;
}
};
const onCancel = async () => {
await confirm({
title: 'Cancel cluster creation',
description: `Do you really want to cancel creating this cluster?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
history.goBack();
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/security">
Admin
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Clusters
</Typography>
</Breadcrumbs>
<br />
{/* TODO: Quick hack to detect whether feature is supported */}
{clusterManagementFeature?.error ? <><br /><Alert severity="warning">
<AlertTitle>{clusterManagementFeature.error.title}</AlertTitle>
{clusterManagementFeature.error.message}
</Alert></> : null}
{!clusterManagementFeature?.error && <div className={classes.root}>
<Paper>
<form className={classes.form} noValidate autoComplete="off">
<div className={classes.margin}>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12} sm={4}>
<TextField
error={clusternameExists}
helperText={clusternameExists && 'A cluster with this clustername already exists.'}
required
id="clustername"
label="Cluster name"
onChange={(event) => setClustername(event.target.value)}
defaultValue="Example"
variant="outlined"
fullWidth
className={classes.textField}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<ClusterIcon />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12} sm={8}>
<TextField
required={false}
id="description"
label="Cluster description"
onChange={(event) => setClusterDescription(event.target.value)}
defaultValue="Example cluster"
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid item xs={12}>
<Card variant="outlined">
<CardHeader
subheader="Node 1"
/>
<CardContent>
<SelectNodeComponent
defaultNode={node1}
/>
</CardContent>
</Card>
<br />
<Card variant="outlined">
<CardHeader
subheader="Node 2"
/>
<CardContent>
<SelectNodeComponent
defaultNode={node2}
/>
</CardContent>
</Card>
<br />
<Card variant="outlined">
<CardHeader
subheader="Node 3"
/>
<CardContent>
<SelectNodeComponent
defaultNode={node3}
/>
</CardContent>
</Card>
</Grid>
<Grid container xs={12} alignItems="flex-start">
<Grid item xs={12} className={classes.buttons}>
<SaveCancelButtons
onSave={onSaveCluster}
saveDisabled={!validate()}
onCancel={onCancel}
/>
</Grid>
</Grid>
</Grid>
</div>
</form>
</Paper>
</div>}
</div>
);
}
Example #26
Source File: MarkdownEdit.jsx From markItDown with MIT License | 4 votes |
function MarkdownEdit({ content, changeContent }) {
const [open, setOpen] = useState(false);
const editorRef = useRef(null);
useEffect(() => {
if (content === "") {
localStorage.setItem("markdown", placeholder);
} else {
localStorage.setItem("markdown", content);
}
}, [content]);
const handleEditorChange = (event) => {
event.preventDefault();
changeContent(event.target.value);
};
const handleClearClick = () => {
changeContent("");
editorRef.current.focus();
};
const handleDownloadClick = () => {
let blob = new Blob([content], {
type: "text/plain",
});
let a = document.createElement("a");
a.download = "markdown.md";
a.href = window.URL.createObjectURL(blob);
a.click();
};
const handleCopyClick = () => {
copyToClipBoard("editor");
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div className="markdown-edit scroll">
<div className="section-title">
<h3>Markdown</h3>
<div className="right-section">
<Tooltip title="Download Markdown">
<button onClick={handleDownloadClick} className="btn">
<SaveIcon />
</button>
</Tooltip>
<Tooltip title="Copy to Clipboard">
<button onClick={handleCopyClick} className="btn">
<CopyIcon />
</button>
</Tooltip>
<Tooltip title="Clean">
<button onClick={handleClearClick} className="btn">
<CleanIcon />
</button>
</Tooltip>
</div>
</div>
<textarea
className="editable"
value={content}
onChange={handleEditorChange}
id="editor"
ref={editorRef}></textarea>
<Snackbar open={open} autoHideDuration={2000} onClose={handleClose}>
<Alert
onClose={handleClose}
severity="success"
elevation={6}
variant="filled">
<AlertTitle>Copied</AlertTitle>
The markdown is copied to your clipboard
</Alert>
</Snackbar>
</div>
);
}