{"version":3,"sources":["config.ts","layout/Header.tsx","common/DefaultPage.tsx","common/LoadingSpinner.tsx","inject.tsx","snack/browserNotification.ts","layout/Navigation.tsx","common/ScrollUpButton.tsx","common/SettingsDialog.tsx","snack/SnackBarHandler.tsx","common/ConfirmDialog.tsx","message/extras.ts","common/CopyableSecret.tsx","common/NumberField.tsx","application/AddApplicationDialog.tsx","application/UpdateApplicationDialog.tsx","common/LastUsedCell.tsx","application/Applications.tsx","client/AddClientDialog.tsx","client/UpdateClientDialog.tsx","client/Clients.tsx","plugin/Plugins.tsx","common/Markdown.tsx","common/Container.tsx","plugin/PluginDetailView.tsx","user/Register.tsx","user/Login.tsx","message/Message.tsx","message/Messages.tsx","user/AddEditUserDialog.tsx","user/Users.tsx","common/ConnectionErrorBanner.tsx","layout/Layout.tsx","CurrentUser.ts","common/BaseStore.ts","application/AppStore.ts","message/WebSocketStore.ts","snack/SnackManager.ts","user/UserStore.ts","message/MessagesStore.ts","client/ClientStore.ts","plugin/PluginStore.ts","reactions.ts","index.tsx","apiAuth.ts","registerServiceWorker.ts"],"names":["config","url","register","version","commit","buildDate","window","get","key","Header","observer","this","props","classes","name","loggedIn","admin","toggleTheme","logout","style","setNavOpen","width","position","AppBar","className","appBar","Toolbar","toolbar","title","to","link","Typography","variant","titleName","color","href","renderButtons","IconButton","onClick","target","rel","showSettings","menuButtons","Hidden","smUp","implementation","icon","label","id","Component","ResponsiveButton","rest","Button","startIcon","withWidth","withStyles","theme","createStyles","zIndex","drawer","breakpoints","down","paddingBottom","justifyContent","flexWrap","display","flex","flexBasis","marginTop","order","up","paddingRight","textDecoration","withTheme","DefaultPage","rightControl","maxWidth","children","margin","Grid","container","spacing","item","xs","LoadingSpinner","textAlign","CircularProgress","size","inject","stores","node","mobxInject","InjectProvider","mayAllowPermission","Notify","needsPermission","isSupported","Notification","permission","closeAndFocus","event","parent","focus","location","close","closeAfterTimeout","setTimeout","Navigation","state","showRequestNotification","appStore","navOpen","apps","getItems","userApps","length","map","app","ListItem","button","ListItemAvatar","minWidth","Avatar","height","src","image","ListItemText","primary","placeholderItems","disabled","root","paper","drawerPaper","Divider","align","requestPermission","console","log","setState","ResponsiveDrawer","Drawer","open","xsDown","minHeight","mixins","ScrollUpButton","opacity","scrollHandler","currentScrollPos","pageYOffset","nextState","Math","min","scrollUp","scrollTo","addEventListener","removeEventListener","Fab","bottom","right","SettingsDialog","pass","fClose","currentUser","Dialog","onClose","DialogTitle","DialogContent","TextField","autoFocus","type","value","onChange","e","fullWidth","DialogActions","Tooltip","changePassword","observable","SnackBarHandler","dispose","componentDidMount","reaction","snackManager","counter","onNewSnack","componentWillUnmount","openWhen","snackOpenSince","Date","now","MIN_VISIBLE_SNACK_TIME_IN_MS","closeCurrentSnack","openNextSnack","hasNext","next","current","message","duration","MAX_VISIBLE_SNACK_TIME_IN_MS","Snackbar","anchorOrigin","vertical","horizontal","autoHideDuration","onExited","action","ConfirmDialog","text","fOnSubmit","DialogContentText","RenderMode","CopyableSecret","visible","toggleVisibility","copyToClipboard","a","navigator","clipboard","writeText","snack","error","fontFamily","fontSize","NumberField","React","useState","toString","stringValue","setStringValue","setError","helperText","i","parseInt","Number","isNaN","AddDialog","description","defaultPriority","submitEnabled","handleChange","bind","multiline","propertyName","UpdateDialog","initialName","initialDescription","initialDefaultPriority","LastUsedCell","lastUsed","date","Applications","uploadId","upload","refresh","uploadImage","click","onUploadImage","file","files","indexOf","alert","createDialog","deleteId","updateId","Paper","elevation","overflowX","Table","TableHead","TableRow","TableCell","padding","TableBody","token","fUpload","fDelete","fEdit","noDelete","internal","ref","create","update","getByID","remove","Row","alt","alignItems","placement","Clients","clientStore","showDialog","clients","client","Plugins","pluginStore","plugins","plugin","enabled","fToggleStatus","changeEnabledState","Switch","checked","Markdown","gfm","PluginDetailView","pluginID","match","params","pluginInfo","displayText","currentConfig","refreshFeatures","nextProps","refreshIfMissing","Promise","all","refreshConfigurer","refreshDisplayer","capabilities","requestConfig","response","requestDisplay","getByIDOrUndefined","undefined","Info","Build","initialConfig","save","newConfig","changeConfig","Subject","PanelWrapper","Icon","paddingLeft","float","toLowerCase","trim","replace","ConfigurerPanel","unsavedChanges","options","mode","lineNumbers","_","_1","newConf","then","DisplayerPanel","PluginInfo","author","modulePath","website","license","wordWrap","join","RegistrationDialog","namePresent","passPresent","success","Login","login","preventDefault","username","password","registerButton","registerDialog","onSubmit","autoComplete","connectionErrorMessage","marginBottom","contentType","extras","extract","Object","keys","k","some","Plain","path","priorityColor","priority","Message","getBoundingClientRect","renderContent","content","plainContent","wrapperPadding","borderLeftColor","borderLeftWidth","borderLeftStyle","imageWrapper","messageContentWrapper","header","headerTitle","trash","component","PureComponent","marginRight","whiteSpace","wordBreak","overflow","Messages","appId","isLoadingMore","updateAllWithProps","messagesStore","exists","loadMore","updateAll","deleteMessage","removeSingle","renderMessage","heights","gutterBottom","onscroll","innerHeight","document","body","offsetHeight","checkIfLoadMore","messages","hasMore","canLoadMore","getName","hasMessages","refreshByApp","deleteAll","loaded","useWindowAsScrollContainer","preloadBatchSize","elementHeight","m","removeByApp","AddEditDialog","isEdit","FormControlLabel","control","handleChecked","UserRow","Users","userStore","editId","users","user","wrapper","ConnectionErrorBanner","retry","backgroundColor","lineHeight","localStorageThemeKey","themeMap","light","createMuiTheme","palette","dark","Layout","localStorageTheme","localStorage","getItem","currentTheme","setItem","authenticating","tryReconnect","flexDirection","CssBaseline","top","exact","render","tokenKey","CurrentUser","tokenCache","reconnectTimeoutId","reconnectTime","localStorageToken","setToken","axios","post","catch","data","errorDescription","browser","detect","request","method","headers","Authorization","Base64","encode","resp","tryAuthenticate","reject","passThrough","status","connectionError","statusText","filter","forEach","delete","resolve","removeItem","quiet","clearTimeout","BaseStore","Error","items","find","hasId","requestDelete","requestItems","AppStore","onDelete","formData","FormData","append","put","WebSocketStore","wsActive","ws","listen","callback","wsUrl","WebSocket","onerror","onmessage","JSON","parse","onclose","SnackManager","shift","push","UserStore","AllMessages","MessagesStore","loading","stateOf","emptyState","clear","fetchMessages","since","getUnCached","appToImage","reduce","appid","createTransformer","clearCache","createEmptyStatesForApps","array","nextSince","messageToDelete","index","findIndex","splice","pagedResult","paging","unshift","clearAll","removeFromList","ClientStore","createNoNotifcation","PluginStore","registerReactions","wsStore","loadAll","msg","publishSingleMessage","removeMarkdown","silent","notifyClick","notifyShow","show","Audio","play","port","hostname","protocol","pathname","slashes","concat","endsWith","substring","lastIndexOf","prodUrl","initStores","interceptors","use","onbeforeunload","ReactDOM","getElementById","serviceWorker","ready","registration","unregister"],"mappings":"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","file":"static/js/main.ca03a2c1.chunk.js","sourcesContent":["import {IVersion} from './types';\n\nexport interface IConfig {\n    url: string;\n    register: boolean;\n    version: IVersion;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ndeclare global {\n    interface Window {\n        config?: Partial<IConfig>;\n    }\n}\n\nconst config: IConfig = {\n    url: 'unset',\n    register: false,\n    version: {commit: 'unknown', buildDate: 'unknown', version: 'unknown'},\n    ...window.config,\n};\n\nexport function set<Key extends keyof IConfig>(key: Key, value: IConfig[Key]): void {\n    config[key] = value;\n}\n\nexport function get<K extends keyof IConfig>(key: K): IConfig[K] {\n    return config[key];\n}\n","import AppBar from '@material-ui/core/AppBar';\nimport Button from '@material-ui/core/Button';\nimport IconButton from '@material-ui/core/IconButton';\nimport {createStyles, Theme, WithStyles, withStyles} from '@material-ui/core/styles';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport Typography from '@material-ui/core/Typography';\nimport AccountCircle from '@material-ui/icons/AccountCircle';\nimport Chat from '@material-ui/icons/Chat';\nimport DevicesOther from '@material-ui/icons/DevicesOther';\nimport ExitToApp from '@material-ui/icons/ExitToApp';\nimport Highlight from '@material-ui/icons/Highlight';\nimport GitHubIcon from '@material-ui/icons/GitHub';\nimport MenuIcon from '@material-ui/icons/Menu';\nimport Apps from '@material-ui/icons/Apps';\nimport SupervisorAccount from '@material-ui/icons/SupervisorAccount';\nimport React, {Component, CSSProperties} from 'react';\nimport {Link} from 'react-router-dom';\nimport {observer} from 'mobx-react';\nimport {Hidden, PropTypes, withWidth} from '@material-ui/core';\nimport {Breakpoint} from '@material-ui/core/styles/createBreakpoints';\n\nconst styles = (theme: Theme) =>\n    createStyles({\n        appBar: {\n            zIndex: theme.zIndex.drawer + 1,\n            [theme.breakpoints.down('xs')]: {\n                paddingBottom: 10,\n            },\n        },\n        toolbar: {\n            justifyContent: 'space-between',\n            [theme.breakpoints.down('xs')]: {\n                flexWrap: 'wrap',\n            },\n        },\n        menuButtons: {\n            display: 'flex',\n            [theme.breakpoints.down('sm')]: {\n                flex: 1,\n            },\n            justifyContent: 'center',\n            [theme.breakpoints.down('xs')]: {\n                flexBasis: '100%',\n                marginTop: 5,\n                order: 1,\n                justifyContent: 'space-between',\n            },\n        },\n        title: {\n            [theme.breakpoints.up('md')]: {\n                flex: 1,\n            },\n            display: 'flex',\n            alignItems: 'center',\n        },\n        titleName: {\n            paddingRight: 10,\n        },\n        link: {\n            color: 'inherit',\n            textDecoration: 'none',\n        },\n    });\n\ntype Styles = WithStyles<'link' | 'menuButtons' | 'toolbar' | 'titleName' | 'title' | 'appBar'>;\n\ninterface IProps extends Styles {\n    loggedIn: boolean;\n    name: string;\n    admin: boolean;\n    version: string;\n    toggleTheme: VoidFunction;\n    showSettings: VoidFunction;\n    logout: VoidFunction;\n    style: CSSProperties;\n    width: Breakpoint;\n    setNavOpen: (open: boolean) => void;\n}\n\n@observer\nclass Header extends Component<IProps> {\n    public render() {\n        const {\n            classes,\n            version,\n            name,\n            loggedIn,\n            admin,\n            toggleTheme,\n            logout,\n            style,\n            setNavOpen,\n            width,\n        } = this.props;\n\n        const position = width === 'xs' ? 'sticky' : 'fixed';\n\n        return (\n            <AppBar position={position} style={style} className={classes.appBar}>\n                <Toolbar className={classes.toolbar}>\n                    <div className={classes.title}>\n                        <Link to=\"/\" className={classes.link}>\n                            <Typography variant=\"h5\" className={classes.titleName} color=\"inherit\">\n                                Gotify\n                            </Typography>\n                        </Link>\n                        <a\n                            href={'https://github.com/gotify/server/releases/tag/v' + version}\n                            className={classes.link}>\n                            <Typography variant=\"button\" color=\"inherit\">\n                                @{version}\n                            </Typography>\n                        </a>\n                    </div>\n                    {loggedIn && this.renderButtons(name, admin, logout, width, setNavOpen)}\n                    <div>\n                        <IconButton onClick={toggleTheme} color=\"inherit\">\n                            <Highlight />\n                        </IconButton>\n\n                        <a\n                            href=\"https://github.com/gotify/server\"\n                            className={classes.link}\n                            target=\"_blank\"\n                            rel=\"noopener noreferrer\">\n                            <IconButton color=\"inherit\">\n                                <GitHubIcon />\n                            </IconButton>\n                        </a>\n                    </div>\n                </Toolbar>\n            </AppBar>\n        );\n    }\n\n    private renderButtons(\n        name: string,\n        admin: boolean,\n        logout: VoidFunction,\n        width: Breakpoint,\n        setNavOpen: (open: boolean) => void\n    ) {\n        const {classes, showSettings} = this.props;\n        return (\n            <div className={classes.menuButtons}>\n                <Hidden smUp implementation=\"css\">\n                    <ResponsiveButton\n                        icon={<MenuIcon />}\n                        onClick={() => setNavOpen(true)}\n                        label=\"menu\"\n                        width={width}\n                        color=\"inherit\"\n                    />\n                </Hidden>\n                {admin && (\n                    <Link className={classes.link} to=\"/users\" id=\"navigate-users\">\n                        <ResponsiveButton\n                            icon={<SupervisorAccount />}\n                            label=\"users\"\n                            width={width}\n                            color=\"inherit\"\n                        />\n                    </Link>\n                )}\n                <Link className={classes.link} to=\"/applications\" id=\"navigate-apps\">\n                    <ResponsiveButton icon={<Chat />} label=\"apps\" width={width} color=\"inherit\" />\n                </Link>\n                <Link className={classes.link} to=\"/clients\" id=\"navigate-clients\">\n                    <ResponsiveButton\n                        icon={<DevicesOther />}\n                        label=\"clients\"\n                        width={width}\n                        color=\"inherit\"\n                    />\n                </Link>\n                <Link className={classes.link} to=\"/plugins\" id=\"navigate-plugins\">\n                    <ResponsiveButton\n                        icon={<Apps />}\n                        label=\"plugins\"\n                        width={width}\n                        color=\"inherit\"\n                    />\n                </Link>\n                <ResponsiveButton\n                    icon={<AccountCircle />}\n                    label={name}\n                    onClick={showSettings}\n                    id=\"changepw\"\n                    width={width}\n                    color=\"inherit\"\n                />\n                <ResponsiveButton\n                    icon={<ExitToApp />}\n                    label=\"Logout\"\n                    onClick={logout}\n                    id=\"logout\"\n                    width={width}\n                    color=\"inherit\"\n                />\n            </div>\n        );\n    }\n}\n\nconst ResponsiveButton: React.FC<{\n    width: Breakpoint;\n    color: PropTypes.Color;\n    label: string;\n    id?: string;\n    onClick?: () => void;\n    icon: React.ReactNode;\n}> = ({width, icon, label, ...rest}) => {\n    if (width === 'xs' || width === 'sm') {\n        return <IconButton {...rest}>{icon}</IconButton>;\n    }\n    return (\n        <Button startIcon={icon} {...rest}>\n            {label}\n        </Button>\n    );\n};\n\nexport default withWidth()(withStyles(styles, {withTheme: true})(Header));\n","import Grid from '@material-ui/core/Grid';\nimport Typography from '@material-ui/core/Typography';\nimport React, {FC} from 'react';\n\ninterface IProps {\n    title: string;\n    rightControl?: React.ReactNode;\n    maxWidth?: number;\n}\n\nconst DefaultPage: FC<IProps> = ({title, rightControl, maxWidth = 700, children}) => (\n    <main style={{margin: '0 auto', maxWidth}}>\n        <Grid container spacing={4}>\n            <Grid item xs={12} style={{display: 'flex', flexWrap: 'wrap'}}>\n                <Typography variant=\"h4\" style={{flex: 1}}>\n                    {title}\n                </Typography>\n                {rightControl}\n            </Grid>\n            {children}\n        </Grid>\n    </main>\n);\nexport default DefaultPage;\n","import CircularProgress from '@material-ui/core/CircularProgress';\nimport Grid from '@material-ui/core/Grid';\nimport React from 'react';\nimport DefaultPage from './DefaultPage';\n\nexport default function LoadingSpinner() {\n    return (\n        <DefaultPage title=\"\" maxWidth={250}>\n            <Grid item xs={12} style={{textAlign: 'center'}}>\n                <CircularProgress size={40} />\n            </Grid>\n        </DefaultPage>\n    );\n}\n","import * as React from 'react';\nimport {UserStore} from './user/UserStore';\nimport {SnackManager} from './snack/SnackManager';\nimport {MessagesStore} from './message/MessagesStore';\nimport {CurrentUser} from './CurrentUser';\nimport {ClientStore} from './client/ClientStore';\nimport {AppStore} from './application/AppStore';\nimport {inject as mobxInject, Provider} from 'mobx-react';\nimport {WebSocketStore} from './message/WebSocketStore';\nimport {PluginStore} from './plugin/PluginStore';\n\nexport interface StoreMapping {\n    userStore: UserStore;\n    snackManager: SnackManager;\n    messagesStore: MessagesStore;\n    currentUser: CurrentUser;\n    clientStore: ClientStore;\n    appStore: AppStore;\n    pluginStore: PluginStore;\n    wsStore: WebSocketStore;\n}\n\nexport type AllStores = Extract<keyof StoreMapping, string>;\nexport type Stores<T extends AllStores> = Pick<StoreMapping, T>;\n\nexport const inject =\n    <I extends AllStores>(...stores: I[]) =>\n    // eslint-disable-next-line @typescript-eslint/ban-types\n    <P extends {}>(\n        node: React.ComponentType<P>\n    ): React.ComponentType<Pick<P, Exclude<keyof P, I>>> =>\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        mobxInject(...stores)(node) as any;\n\nexport const InjectProvider: React.FC<{stores: StoreMapping}> = ({children, stores}) => (\n    <Provider {...stores}>{children}</Provider>\n);\n","import Notify from 'notifyjs';\nimport removeMarkdown from 'remove-markdown';\nimport {IMessage} from '../types';\n\nexport function mayAllowPermission(): boolean {\n    return Notify.needsPermission && Notify.isSupported() && Notification.permission !== 'denied';\n}\n\nexport function requestPermission() {\n    if (Notify.needsPermission && Notify.isSupported()) {\n        Notify.requestPermission(\n            () => console.log('granted notification permissions'),\n            () => console.log('notification permission denied')\n        );\n    }\n}\n\nexport function notifyNewMessage(msg: IMessage) {\n    const notify = new Notify(msg.title, {\n        body: removeMarkdown(msg.message),\n        icon: msg.image,\n        silent: true,\n        notifyClick: closeAndFocus,\n        notifyShow: closeAfterTimeout,\n    });\n    notify.show();\n}\n\nfunction closeAndFocus(event: Event) {\n    if (window.parent) {\n        window.parent.focus();\n    }\n    window.focus();\n    window.location.href = '/';\n    const target = event.target as Notification;\n    target.close();\n}\n\nfunction closeAfterTimeout(event: Event) {\n    setTimeout(() => {\n        const target = event.target as Notification;\n        target.close();\n    }, 5000);\n}\n","import Divider from '@material-ui/core/Divider';\nimport Drawer from '@material-ui/core/Drawer';\nimport {StyleRules, Theme, WithStyles, withStyles} from '@material-ui/core/styles';\nimport React, {Component} from 'react';\nimport {Link} from 'react-router-dom';\nimport {observer} from 'mobx-react';\nimport {inject, Stores} from '../inject';\nimport {mayAllowPermission, requestPermission} from '../snack/browserNotification';\nimport {\n    Button,\n    Hidden,\n    IconButton,\n    Typography,\n    ListItem,\n    ListItemText,\n    ListItemAvatar,\n    Avatar,\n} from '@material-ui/core';\nimport {DrawerProps} from '@material-ui/core/Drawer/Drawer';\nimport CloseIcon from '@material-ui/icons/Close';\n\nconst styles = (theme: Theme): StyleRules<'root' | 'drawerPaper' | 'toolbar' | 'link'> => ({\n    root: {\n        height: '100%',\n    },\n    drawerPaper: {\n        position: 'relative',\n        width: 250,\n        minHeight: '100%',\n        height: '100vh',\n    },\n    toolbar: theme.mixins.toolbar,\n    link: {\n        color: 'inherit',\n        textDecoration: 'none',\n    },\n});\n\ntype Styles = WithStyles<'root' | 'drawerPaper' | 'toolbar' | 'link'>;\n\ninterface IProps {\n    loggedIn: boolean;\n    navOpen: boolean;\n    setNavOpen: (open: boolean) => void;\n}\n\n@observer\nclass Navigation extends Component<\n    IProps & Styles & Stores<'appStore'>,\n    {showRequestNotification: boolean}\n> {\n    public state = {showRequestNotification: mayAllowPermission()};\n\n    public render() {\n        const {classes, loggedIn, appStore, navOpen, setNavOpen} = this.props;\n        const {showRequestNotification} = this.state;\n        const apps = appStore.getItems();\n\n        const userApps =\n            apps.length === 0\n                ? null\n                : apps.map((app) => (\n                      <Link\n                          onClick={() => setNavOpen(false)}\n                          className={`${classes.link} item`}\n                          to={'/messages/' + app.id}\n                          key={app.id}>\n                          <ListItem button>\n                              <ListItemAvatar style={{minWidth: 42}}>\n                                  <Avatar\n                                      style={{width: 32, height: 32}}\n                                      src={app.image}\n                                      variant=\"square\"\n                                  />\n                              </ListItemAvatar>\n                              <ListItemText primary={app.name} />\n                          </ListItem>\n                      </Link>\n                  ));\n\n        const placeholderItems = [\n            <ListItem button disabled key={-1}>\n                <ListItemText primary=\"Some Server\" />\n            </ListItem>,\n            <ListItem button disabled key={-2}>\n                <ListItemText primary=\"A Raspberry PI\" />\n            </ListItem>,\n        ];\n\n        return (\n            <ResponsiveDrawer\n                classes={{root: classes.root, paper: classes.drawerPaper}}\n                navOpen={navOpen}\n                setNavOpen={setNavOpen}\n                id=\"message-navigation\">\n                <div className={classes.toolbar} />\n                <Link className={classes.link} to=\"/\" onClick={() => setNavOpen(false)}>\n                    <ListItem button disabled={!loggedIn} className=\"all\">\n                        <ListItemText primary=\"All Messages\" />\n                    </ListItem>\n                </Link>\n                <Divider />\n                <div>{loggedIn ? userApps : placeholderItems}</div>\n                <Divider />\n                <Typography align=\"center\" style={{marginTop: 10}}>\n                    {showRequestNotification ? (\n                        <Button\n                            onClick={() => {\n                                requestPermission();\n                                this.setState({showRequestNotification: false});\n                            }}>\n                            Enable Notifications\n                        </Button>\n                    ) : null}\n                </Typography>\n            </ResponsiveDrawer>\n        );\n    }\n}\n\nconst ResponsiveDrawer: React.FC<\n    DrawerProps & {navOpen: boolean; setNavOpen: (open: boolean) => void}\n> = ({navOpen, setNavOpen, children, ...rest}) => (\n    <>\n        <Hidden smUp implementation=\"css\">\n            <Drawer variant=\"temporary\" open={navOpen} {...rest}>\n                <IconButton onClick={() => setNavOpen(false)}>\n                    <CloseIcon />\n                </IconButton>\n                {children}\n            </Drawer>\n        </Hidden>\n        <Hidden xsDown implementation=\"css\">\n            <Drawer variant=\"permanent\" {...rest}>\n                {children}\n            </Drawer>\n        </Hidden>\n    </>\n);\n\nexport default withStyles(styles, {withTheme: true})(inject('appStore')(Navigation));\n","import Fab from '@material-ui/core/Fab';\nimport KeyboardArrowUp from '@material-ui/icons/KeyboardArrowUp';\nimport React, {Component} from 'react';\n\nclass ScrollUpButton extends Component {\n    state = {\n        display: 'none',\n        opacity: 0,\n    };\n    componentDidMount() {\n        window.addEventListener('scroll', this.scrollHandler);\n    }\n\n    componentWillUnmount() {\n        window.removeEventListener('scroll', this.scrollHandler);\n    }\n\n    scrollHandler = () => {\n        const currentScrollPos = window.pageYOffset;\n        const opacity = Math.min(currentScrollPos / 500, 1);\n        const nextState = {display: currentScrollPos > 0 ? 'inherit' : 'none', opacity};\n        if (this.state.display !== nextState.display || this.state.opacity !== nextState.opacity) {\n            this.setState(nextState);\n        }\n    };\n\n    public render() {\n        return (\n            <Fab\n                color=\"primary\"\n                style={{\n                    position: 'fixed',\n                    bottom: '30px',\n                    right: '30px',\n                    zIndex: 100000,\n                    display: this.state.display,\n                    opacity: this.state.opacity,\n                }}\n                onClick={this.scrollUp}>\n                <KeyboardArrowUp />\n            </Fab>\n        );\n    }\n\n    private scrollUp = () => window.scrollTo(0, 0);\n}\n\nexport default ScrollUpButton;\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport React, {Component} from 'react';\nimport {observable} from 'mobx';\nimport {observer} from 'mobx-react';\nimport {inject, Stores} from '../inject';\n\ninterface IProps {\n    fClose: VoidFunction;\n}\n\n@observer\nclass SettingsDialog extends Component<IProps & Stores<'currentUser'>> {\n    @observable\n    private pass = '';\n\n    public render() {\n        const {pass} = this;\n        const {fClose, currentUser} = this.props;\n        const submitAndClose = () => {\n            currentUser.changePassword(pass);\n            fClose();\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"changepw-dialog\">\n                <DialogTitle id=\"form-dialog-title\">Change Password</DialogTitle>\n                <DialogContent>\n                    <TextField\n                        className=\"newpass\"\n                        autoFocus\n                        margin=\"dense\"\n                        type=\"password\"\n                        label=\"New Password *\"\n                        value={pass}\n                        onChange={(e) => (this.pass = e.target.value)}\n                        fullWidth\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip title={pass.length !== 0 ? '' : 'Password is required'}>\n                        <div>\n                            <Button\n                                className=\"change\"\n                                disabled={pass.length === 0}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                Change\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n}\n\nexport default inject('currentUser')(SettingsDialog);\n","import IconButton from '@material-ui/core/IconButton';\nimport Snackbar from '@material-ui/core/Snackbar';\nimport Close from '@material-ui/icons/Close';\nimport React, {Component} from 'react';\nimport {observable, reaction} from 'mobx';\nimport {observer} from 'mobx-react';\nimport {inject, Stores} from '../inject';\n\n@observer\nclass SnackBarHandler extends Component<Stores<'snackManager'>> {\n    private static MAX_VISIBLE_SNACK_TIME_IN_MS = 6000;\n    private static MIN_VISIBLE_SNACK_TIME_IN_MS = 1000;\n\n    @observable\n    private open = false;\n    @observable\n    private openWhen = 0;\n\n    private dispose: () => void = () => {};\n\n    public componentDidMount = () =>\n        (this.dispose = reaction(() => this.props.snackManager.counter, this.onNewSnack));\n\n    public componentWillUnmount = () => this.dispose();\n\n    public render() {\n        const {message: current, hasNext} = this.props.snackManager;\n        const duration = hasNext()\n            ? SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS\n            : SnackBarHandler.MAX_VISIBLE_SNACK_TIME_IN_MS;\n\n        return (\n            <Snackbar\n                anchorOrigin={{vertical: 'bottom', horizontal: 'left'}}\n                open={this.open}\n                autoHideDuration={duration}\n                onClose={this.closeCurrentSnack}\n                onExited={this.openNextSnack}\n                message={<span id=\"message-id\">{current}</span>}\n                action={\n                    <IconButton\n                        key=\"close\"\n                        aria-label=\"Close\"\n                        color=\"inherit\"\n                        onClick={this.closeCurrentSnack}>\n                        <Close />\n                    </IconButton>\n                }\n            />\n        );\n    }\n\n    private onNewSnack = () => {\n        const {open, openWhen} = this;\n\n        if (!open) {\n            this.openNextSnack();\n            return;\n        }\n\n        const snackOpenSince = Date.now() - openWhen;\n        if (snackOpenSince > SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS) {\n            this.closeCurrentSnack();\n        } else {\n            setTimeout(\n                this.closeCurrentSnack,\n                SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS - snackOpenSince\n            );\n        }\n    };\n\n    private openNextSnack = () => {\n        if (this.props.snackManager.hasNext()) {\n            this.open = true;\n            this.openWhen = Date.now();\n            this.props.snackManager.next();\n        }\n    };\n\n    private closeCurrentSnack = () => (this.open = false);\n}\n\nexport default inject('snackManager')(SnackBarHandler);\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport React from 'react';\n\ninterface IProps {\n    title: string;\n    text: string;\n    fClose: VoidFunction;\n    fOnSubmit: VoidFunction;\n}\n\nexport default function ConfirmDialog({title, text, fClose, fOnSubmit}: IProps) {\n    const submitAndClose = () => {\n        fOnSubmit();\n        fClose();\n    };\n    return (\n        <Dialog\n            open={true}\n            onClose={fClose}\n            aria-labelledby=\"form-dialog-title\"\n            className=\"confirm-dialog\">\n            <DialogTitle id=\"form-dialog-title\">{title}</DialogTitle>\n            <DialogContent>\n                <DialogContentText>{text}</DialogContentText>\n            </DialogContent>\n            <DialogActions>\n                <Button onClick={fClose} className=\"cancel\">\n                    No\n                </Button>\n                <Button\n                    onClick={submitAndClose}\n                    autoFocus\n                    color=\"primary\"\n                    variant=\"contained\"\n                    className=\"confirm\">\n                    Yes\n                </Button>\n            </DialogActions>\n        </Dialog>\n    );\n}\n","import {IMessageExtras} from '../types';\n\nexport enum RenderMode {\n    Markdown = 'text/markdown',\n    Plain = 'text/plain',\n}\n\nexport const contentType = (extras?: IMessageExtras): RenderMode => {\n    const type = extract(extras, 'client::display', 'contentType');\n    const valid = Object.keys(RenderMode)\n        .map((k) => RenderMode[k])\n        .some((mode) => mode === type);\n    return valid ? type : RenderMode.Plain;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst extract = (extras: IMessageExtras | undefined, key: string, path: string): any => {\n    if (!extras) {\n        return null;\n    }\n\n    if (!extras[key]) {\n        return null;\n    }\n\n    if (!extras[key][path]) {\n        return null;\n    }\n\n    return extras[key][path];\n};\n","import IconButton from '@material-ui/core/IconButton';\nimport Typography from '@material-ui/core/Typography';\nimport Visibility from '@material-ui/icons/Visibility';\nimport Copy from '@material-ui/icons/FileCopyOutlined';\nimport VisibilityOff from '@material-ui/icons/VisibilityOff';\nimport React, {Component, CSSProperties} from 'react';\nimport {Stores, inject} from '../inject';\n\ninterface IProps {\n    value: string;\n    style?: CSSProperties;\n}\n\ninterface IState {\n    visible: boolean;\n}\n\nclass CopyableSecret extends Component<IProps & Stores<'snackManager'>, IState> {\n    public state = {visible: false};\n\n    public render() {\n        const {value, style} = this.props;\n        const text = this.state.visible ? value : '•••••••••••••••';\n        return (\n            <div style={style}>\n                <IconButton onClick={this.copyToClipboard} title=\"Copy to clipboard\">\n                    <Copy />\n                </IconButton>\n                <IconButton onClick={this.toggleVisibility} className=\"toggle-visibility\">\n                    {this.state.visible ? <VisibilityOff /> : <Visibility />}\n                </IconButton>\n                <Typography style={{fontFamily: 'monospace', fontSize: 16}}>{text}</Typography>\n            </div>\n        );\n    }\n\n    private toggleVisibility = () => this.setState({visible: !this.state.visible});\n    private copyToClipboard = async () => {\n        const {snackManager, value} = this.props;\n        try {\n            await navigator.clipboard.writeText(value);\n            snackManager.snack('Copied to clipboard');\n        } catch (error) {\n            console.error('Failed to copy to clipboard:', error);\n            snackManager.snack('Failed to copy to clipboard');\n        }\n    };\n}\n\nexport default inject('snackManager')(CopyableSecret);\n","import {TextField, TextFieldProps} from '@material-ui/core';\nimport React from 'react';\n\nexport interface NumberFieldProps {\n    value: number;\n    onChange: (value: number) => void;\n}\n\nexport const NumberField = ({\n    value,\n    onChange,\n    ...props\n}: NumberFieldProps & Omit<TextFieldProps, 'value' | 'onChange'>) => {\n    const [stringValue, setStringValue] = React.useState<string>(value.toString());\n    const [error, setError] = React.useState('');\n\n    return (\n        <TextField\n            value={stringValue}\n            type=\"number\"\n            helperText={error}\n            error={error !== ''}\n            onChange={(event) => {\n                setStringValue(event.target.value);\n                const i = parseInt(event.target.value, 10);\n                if (!Number.isNaN(i)) {\n                    onChange(i);\n                    setError('');\n                } else {\n                    setError('Invalid number');\n                }\n            }}\n            {...props}\n        />\n    );\n};\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport {NumberField} from '../common/NumberField';\nimport React, {Component} from 'react';\n\ninterface IProps {\n    fClose: VoidFunction;\n    fOnSubmit: (name: string, description: string, defaultPriority: number) => void;\n}\n\ninterface IState {\n    name: string;\n    description: string;\n    defaultPriority: number;\n}\n\nexport default class AddDialog extends Component<IProps, IState> {\n    public state = {name: '', description: '', defaultPriority: 0};\n\n    public render() {\n        const {fClose, fOnSubmit} = this.props;\n        const {name, description, defaultPriority} = this.state;\n        const submitEnabled = this.state.name.length !== 0;\n        const submitAndClose = () => {\n            fOnSubmit(name, description, defaultPriority);\n            fClose();\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"app-dialog\">\n                <DialogTitle id=\"form-dialog-title\">Create an application</DialogTitle>\n                <DialogContent>\n                    <DialogContentText>\n                        An application is allowed to send messages.\n                    </DialogContentText>\n                    <TextField\n                        autoFocus\n                        margin=\"dense\"\n                        className=\"name\"\n                        label=\"Name *\"\n                        type=\"text\"\n                        value={name}\n                        onChange={this.handleChange.bind(this, 'name')}\n                        fullWidth\n                    />\n                    <TextField\n                        margin=\"dense\"\n                        className=\"description\"\n                        label=\"Short Description\"\n                        value={description}\n                        onChange={this.handleChange.bind(this, 'description')}\n                        fullWidth\n                        multiline\n                    />\n                    <NumberField\n                        margin=\"dense\"\n                        className=\"priority\"\n                        label=\"Default Priority\"\n                        value={defaultPriority}\n                        onChange={(value) => this.setState({defaultPriority: value})}\n                        fullWidth\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip title={submitEnabled ? '' : 'name is required'}>\n                        <div>\n                            <Button\n                                className=\"create\"\n                                disabled={!submitEnabled}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                Create\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n\n    private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {\n        const state = this.state;\n        state[propertyName] = event.target.value;\n        this.setState(state);\n    }\n}\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport {NumberField} from '../common/NumberField';\nimport React, {Component} from 'react';\n\ninterface IProps {\n    fClose: VoidFunction;\n    fOnSubmit: (name: string, description: string, defaultPriority: number) => void;\n    initialName: string;\n    initialDescription: string;\n    initialDefaultPriority: number;\n}\n\ninterface IState {\n    name: string;\n    description: string;\n    defaultPriority: number;\n}\n\nexport default class UpdateDialog extends Component<IProps, IState> {\n    public state = {name: '', description: '', defaultPriority: 0};\n\n    constructor(props: IProps) {\n        super(props);\n        this.state = {\n            name: props.initialName,\n            description: props.initialDescription,\n            defaultPriority: props.initialDefaultPriority,\n        };\n    }\n\n    public render() {\n        const {fClose, fOnSubmit} = this.props;\n        const {name, description, defaultPriority} = this.state;\n        const submitEnabled = this.state.name.length !== 0;\n        const submitAndClose = () => {\n            fOnSubmit(name, description, defaultPriority);\n            fClose();\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"app-dialog\">\n                <DialogTitle id=\"form-dialog-title\">Update an application</DialogTitle>\n                <DialogContent>\n                    <DialogContentText>\n                        An application is allowed to send messages.\n                    </DialogContentText>\n                    <TextField\n                        autoFocus\n                        margin=\"dense\"\n                        className=\"name\"\n                        label=\"Name *\"\n                        type=\"text\"\n                        value={name}\n                        onChange={this.handleChange.bind(this, 'name')}\n                        fullWidth\n                    />\n                    <TextField\n                        margin=\"dense\"\n                        className=\"description\"\n                        label=\"Short Description\"\n                        value={description}\n                        onChange={this.handleChange.bind(this, 'description')}\n                        fullWidth\n                        multiline\n                    />\n                    <NumberField\n                        margin=\"dense\"\n                        className=\"priority\"\n                        label=\"Default Priority\"\n                        value={defaultPriority}\n                        onChange={(value) => this.setState({defaultPriority: value})}\n                        fullWidth\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip title={submitEnabled ? '' : 'name is required'}>\n                        <div>\n                            <Button\n                                className=\"update\"\n                                disabled={!submitEnabled}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                Update\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n\n    private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {\n        const state = this.state;\n        state[propertyName] = event.target.value;\n        this.setState(state);\n    }\n}\n","import {Typography} from '@material-ui/core';\nimport React from 'react';\nimport TimeAgo from 'react-timeago';\n\nexport const LastUsedCell: React.FC<{lastUsed: string | null}> = ({lastUsed}) => {\n    if (lastUsed === null) {\n        return <Typography>Never</Typography>;\n    }\n\n    if (+new Date(lastUsed) + 300000 > Date.now()) {\n        return <Typography title={lastUsed}>Recently</Typography>;\n    }\n\n    return <TimeAgo date={lastUsed} />;\n};\n","import Grid from '@material-ui/core/Grid';\nimport IconButton from '@material-ui/core/IconButton';\nimport Paper from '@material-ui/core/Paper';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableHead from '@material-ui/core/TableHead';\nimport TableRow from '@material-ui/core/TableRow';\nimport Delete from '@material-ui/icons/Delete';\nimport Edit from '@material-ui/icons/Edit';\nimport CloudUpload from '@material-ui/icons/CloudUpload';\nimport React, {ChangeEvent, Component, SFC} from 'react';\nimport ConfirmDialog from '../common/ConfirmDialog';\nimport DefaultPage from '../common/DefaultPage';\nimport Button from '@material-ui/core/Button';\nimport CopyableSecret from '../common/CopyableSecret';\nimport AddApplicationDialog from './AddApplicationDialog';\nimport {observer} from 'mobx-react';\nimport {observable} from 'mobx';\nimport {inject, Stores} from '../inject';\nimport * as config from '../config';\nimport UpdateDialog from './UpdateApplicationDialog';\nimport {IApplication} from '../types';\nimport {LastUsedCell} from '../common/LastUsedCell';\n\n@observer\nclass Applications extends Component<Stores<'appStore'>> {\n    @observable\n    private deleteId: number | false = false;\n    @observable\n    private updateId: number | false = false;\n    @observable\n    private createDialog = false;\n\n    private uploadId = -1;\n    private upload: HTMLInputElement | null = null;\n\n    public componentDidMount = () => this.props.appStore.refresh();\n\n    public render() {\n        const {\n            createDialog,\n            deleteId,\n            updateId,\n            props: {appStore},\n        } = this;\n        const apps = appStore.getItems();\n        return (\n            <DefaultPage\n                title=\"Applications\"\n                rightControl={\n                    <Button\n                        id=\"create-app\"\n                        variant=\"contained\"\n                        color=\"primary\"\n                        onClick={() => (this.createDialog = true)}>\n                        Create Application\n                    </Button>\n                }\n                maxWidth={1000}>\n                <Grid item xs={12}>\n                    <Paper elevation={6} style={{overflowX: 'auto'}}>\n                        <Table id=\"app-table\">\n                            <TableHead>\n                                <TableRow>\n                                    <TableCell padding=\"checkbox\" style={{width: 80}} />\n                                    <TableCell>Name</TableCell>\n                                    <TableCell>Token</TableCell>\n                                    <TableCell>Description</TableCell>\n                                    <TableCell>Priority</TableCell>\n                                    <TableCell>Last Used</TableCell>\n                                    <TableCell />\n                                    <TableCell />\n                                </TableRow>\n                            </TableHead>\n                            <TableBody>\n                                {apps.map((app: IApplication) => (\n                                    <Row\n                                        key={app.id}\n                                        description={app.description}\n                                        defaultPriority={app.defaultPriority}\n                                        image={app.image}\n                                        name={app.name}\n                                        value={app.token}\n                                        lastUsed={app.lastUsed}\n                                        fUpload={() => this.uploadImage(app.id)}\n                                        fDelete={() => (this.deleteId = app.id)}\n                                        fEdit={() => (this.updateId = app.id)}\n                                        noDelete={app.internal}\n                                    />\n                                ))}\n                            </TableBody>\n                        </Table>\n                        <input\n                            ref={(upload) => (this.upload = upload)}\n                            type=\"file\"\n                            style={{display: 'none'}}\n                            onChange={this.onUploadImage}\n                        />\n                    </Paper>\n                </Grid>\n                {createDialog && (\n                    <AddApplicationDialog\n                        fClose={() => (this.createDialog = false)}\n                        fOnSubmit={appStore.create}\n                    />\n                )}\n                {updateId !== false && (\n                    <UpdateDialog\n                        fClose={() => (this.updateId = false)}\n                        fOnSubmit={(name, description, defaultPriority) =>\n                            appStore.update(updateId, name, description, defaultPriority)\n                        }\n                        initialDescription={appStore.getByID(updateId).description}\n                        initialName={appStore.getByID(updateId).name}\n                        initialDefaultPriority={appStore.getByID(updateId).defaultPriority}\n                    />\n                )}\n                {deleteId !== false && (\n                    <ConfirmDialog\n                        title=\"Confirm Delete\"\n                        text={'Delete ' + appStore.getByID(deleteId).name + '?'}\n                        fClose={() => (this.deleteId = false)}\n                        fOnSubmit={() => appStore.remove(deleteId)}\n                    />\n                )}\n            </DefaultPage>\n        );\n    }\n\n    private uploadImage = (id: number) => {\n        this.uploadId = id;\n        if (this.upload) {\n            this.upload.click();\n        }\n    };\n\n    private onUploadImage = (e: ChangeEvent<HTMLInputElement>) => {\n        const file = e.target.files?.[0];\n        if (!file) {\n            return;\n        }\n        if (['image/png', 'image/jpeg', 'image/gif'].indexOf(file.type) !== -1) {\n            this.props.appStore.uploadImage(this.uploadId, file);\n        } else {\n            alert('Uploaded file must be of type png, jpeg or gif.');\n        }\n    };\n}\n\ninterface IRowProps {\n    name: string;\n    value: string;\n    noDelete: boolean;\n    description: string;\n    defaultPriority: number;\n    lastUsed: string | null;\n    fUpload: VoidFunction;\n    image: string;\n    fDelete: VoidFunction;\n    fEdit: VoidFunction;\n}\n\nconst Row: SFC<IRowProps> = observer(\n    ({\n        name,\n        value,\n        noDelete,\n        description,\n        defaultPriority,\n        lastUsed,\n        fDelete,\n        fUpload,\n        image,\n        fEdit,\n    }) => (\n        <TableRow>\n            <TableCell padding=\"default\">\n                <div style={{display: 'flex'}}>\n                    <img src={config.get('url') + image} alt=\"app logo\" width=\"40\" height=\"40\" />\n                    <IconButton onClick={fUpload} style={{height: 40}}>\n                        <CloudUpload />\n                    </IconButton>\n                </div>\n            </TableCell>\n            <TableCell>{name}</TableCell>\n            <TableCell>\n                <CopyableSecret value={value} style={{display: 'flex', alignItems: 'center'}} />\n            </TableCell>\n            <TableCell>{description}</TableCell>\n            <TableCell>{defaultPriority}</TableCell>\n            <TableCell>\n                <LastUsedCell lastUsed={lastUsed} />\n            </TableCell>\n            <TableCell align=\"right\" padding=\"none\">\n                <IconButton onClick={fEdit} className=\"edit\">\n                    <Edit />\n                </IconButton>\n            </TableCell>\n            <TableCell align=\"right\" padding=\"none\">\n                <IconButton onClick={fDelete} className=\"delete\" disabled={noDelete}>\n                    <Delete />\n                </IconButton>\n            </TableCell>\n        </TableRow>\n    )\n);\n\nexport default inject('appStore')(Applications);\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport React, {Component} from 'react';\n\ninterface IProps {\n    fClose: VoidFunction;\n    fOnSubmit: (name: string) => void;\n}\n\nexport default class AddDialog extends Component<IProps, {name: string}> {\n    public state = {name: ''};\n\n    public render() {\n        const {fClose, fOnSubmit} = this.props;\n        const {name} = this.state;\n        const submitEnabled = this.state.name.length !== 0;\n        const submitAndClose = () => {\n            fOnSubmit(name);\n            fClose();\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"client-dialog\">\n                <DialogTitle id=\"form-dialog-title\">Create a client</DialogTitle>\n                <DialogContent>\n                    <TextField\n                        autoFocus\n                        margin=\"dense\"\n                        className=\"name\"\n                        label=\"Name *\"\n                        type=\"email\"\n                        value={name}\n                        onChange={this.handleChange.bind(this, 'name')}\n                        fullWidth\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip\n                        placement={'bottom-start'}\n                        title={submitEnabled ? '' : 'name is required'}>\n                        <div>\n                            <Button\n                                className=\"create\"\n                                disabled={!submitEnabled}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                Create\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n\n    private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {\n        const state = this.state;\n        state[propertyName] = event.target.value;\n        this.setState(state);\n    }\n}\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport React, {Component} from 'react';\n\ninterface IProps {\n    fClose: VoidFunction;\n    fOnSubmit: (name: string) => void;\n    initialName: string;\n}\n\ninterface IState {\n    name: string;\n}\n\nexport default class UpdateDialog extends Component<IProps, IState> {\n    public state = {name: ''};\n\n    constructor(props: IProps) {\n        super(props);\n        this.state = {\n            name: props.initialName,\n        };\n    }\n\n    public render() {\n        const {fClose, fOnSubmit} = this.props;\n        const {name} = this.state;\n        const submitEnabled = this.state.name.length !== 0;\n        const submitAndClose = () => {\n            fOnSubmit(name);\n            fClose();\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"client-dialog\">\n                <DialogTitle id=\"form-dialog-title\">Update a Client</DialogTitle>\n                <DialogContent>\n                    <DialogContentText>\n                        A client manages messages, clients, applications and users (with admin\n                        permissions).\n                    </DialogContentText>\n                    <TextField\n                        autoFocus\n                        margin=\"dense\"\n                        className=\"name\"\n                        label=\"Name *\"\n                        type=\"text\"\n                        value={name}\n                        onChange={this.handleChange.bind(this, 'name')}\n                        fullWidth\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip title={submitEnabled ? '' : 'name is required'}>\n                        <div>\n                            <Button\n                                className=\"update\"\n                                disabled={!submitEnabled}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                Update\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n\n    private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {\n        const state = {};\n        state[propertyName] = event.target.value;\n        this.setState(state);\n    }\n}\n","import Grid from '@material-ui/core/Grid';\nimport IconButton from '@material-ui/core/IconButton';\nimport Paper from '@material-ui/core/Paper';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableHead from '@material-ui/core/TableHead';\nimport TableRow from '@material-ui/core/TableRow';\nimport Delete from '@material-ui/icons/Delete';\nimport Edit from '@material-ui/icons/Edit';\nimport React, {Component, SFC} from 'react';\nimport ConfirmDialog from '../common/ConfirmDialog';\nimport DefaultPage from '../common/DefaultPage';\nimport Button from '@material-ui/core/Button';\nimport AddClientDialog from './AddClientDialog';\nimport UpdateDialog from './UpdateClientDialog';\nimport {observer} from 'mobx-react';\nimport {observable} from 'mobx';\nimport {inject, Stores} from '../inject';\nimport {IClient} from '../types';\nimport CopyableSecret from '../common/CopyableSecret';\nimport {LastUsedCell} from '../common/LastUsedCell';\n\n@observer\nclass Clients extends Component<Stores<'clientStore'>> {\n    @observable\n    private showDialog = false;\n    @observable\n    private deleteId: false | number = false;\n    @observable\n    private updateId: false | number = false;\n\n    public componentDidMount = () => this.props.clientStore.refresh();\n\n    public render() {\n        const {\n            deleteId,\n            updateId,\n            showDialog,\n            props: {clientStore},\n        } = this;\n        const clients = clientStore.getItems();\n\n        return (\n            <DefaultPage\n                title=\"Clients\"\n                rightControl={\n                    <Button\n                        id=\"create-client\"\n                        variant=\"contained\"\n                        color=\"primary\"\n                        onClick={() => (this.showDialog = true)}>\n                        Create Client\n                    </Button>\n                }>\n                <Grid item xs={12}>\n                    <Paper elevation={6} style={{overflowX: 'auto'}}>\n                        <Table id=\"client-table\">\n                            <TableHead>\n                                <TableRow style={{textAlign: 'center'}}>\n                                    <TableCell>Name</TableCell>\n                                    <TableCell style={{width: 200}}>Token</TableCell>\n                                    <TableCell>Last Used</TableCell>\n                                    <TableCell />\n                                    <TableCell />\n                                </TableRow>\n                            </TableHead>\n                            <TableBody>\n                                {clients.map((client: IClient) => (\n                                    <Row\n                                        key={client.id}\n                                        name={client.name}\n                                        value={client.token}\n                                        lastUsed={client.lastUsed}\n                                        fEdit={() => (this.updateId = client.id)}\n                                        fDelete={() => (this.deleteId = client.id)}\n                                    />\n                                ))}\n                            </TableBody>\n                        </Table>\n                    </Paper>\n                </Grid>\n                {showDialog && (\n                    <AddClientDialog\n                        fClose={() => (this.showDialog = false)}\n                        fOnSubmit={clientStore.create}\n                    />\n                )}\n                {updateId !== false && (\n                    <UpdateDialog\n                        fClose={() => (this.updateId = false)}\n                        fOnSubmit={(name) => clientStore.update(updateId, name)}\n                        initialName={clientStore.getByID(updateId).name}\n                    />\n                )}\n                {deleteId !== false && (\n                    <ConfirmDialog\n                        title=\"Confirm Delete\"\n                        text={'Delete ' + clientStore.getByID(deleteId).name + '?'}\n                        fClose={() => (this.deleteId = false)}\n                        fOnSubmit={() => clientStore.remove(deleteId)}\n                    />\n                )}\n            </DefaultPage>\n        );\n    }\n}\n\ninterface IRowProps {\n    name: string;\n    value: string;\n    lastUsed: string | null;\n    fEdit: VoidFunction;\n    fDelete: VoidFunction;\n}\n\nconst Row: SFC<IRowProps> = ({name, value, lastUsed, fEdit, fDelete}) => (\n    <TableRow>\n        <TableCell>{name}</TableCell>\n        <TableCell>\n            <CopyableSecret\n                value={value}\n                style={{display: 'flex', alignItems: 'center', width: 250}}\n            />\n        </TableCell>\n        <TableCell>\n            <LastUsedCell lastUsed={lastUsed} />\n        </TableCell>\n        <TableCell align=\"right\" padding=\"none\">\n            <IconButton onClick={fEdit} className=\"edit\">\n                <Edit />\n            </IconButton>\n        </TableCell>\n        <TableCell align=\"right\" padding=\"none\">\n            <IconButton onClick={fDelete} className=\"delete\">\n                <Delete />\n            </IconButton>\n        </TableCell>\n    </TableRow>\n);\n\nexport default inject('clientStore')(Clients);\n","import React, {Component, SFC} from 'react';\nimport {Link} from 'react-router-dom';\nimport Grid from '@material-ui/core/Grid';\nimport Paper from '@material-ui/core/Paper';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableHead from '@material-ui/core/TableHead';\nimport TableRow from '@material-ui/core/TableRow';\nimport Settings from '@material-ui/icons/Settings';\nimport {Switch, Button} from '@material-ui/core';\nimport DefaultPage from '../common/DefaultPage';\nimport CopyableSecret from '../common/CopyableSecret';\nimport {observer} from 'mobx-react';\nimport {inject, Stores} from '../inject';\nimport {IPlugin} from '../types';\n\n@observer\nclass Plugins extends Component<Stores<'pluginStore'>> {\n    public componentDidMount = () => this.props.pluginStore.refresh();\n\n    public render() {\n        const {\n            props: {pluginStore},\n        } = this;\n        const plugins = pluginStore.getItems();\n        return (\n            <DefaultPage title=\"Plugins\" maxWidth={1000}>\n                <Grid item xs={12}>\n                    <Paper elevation={6} style={{overflowX: 'auto'}}>\n                        <Table id=\"plugin-table\">\n                            <TableHead>\n                                <TableRow>\n                                    <TableCell>ID</TableCell>\n                                    <TableCell>Enabled</TableCell>\n                                    <TableCell>Name</TableCell>\n                                    <TableCell>Token</TableCell>\n                                    <TableCell>Details</TableCell>\n                                </TableRow>\n                            </TableHead>\n                            <TableBody>\n                                {plugins.map((plugin: IPlugin) => (\n                                    <Row\n                                        key={plugin.token}\n                                        id={plugin.id}\n                                        token={plugin.token}\n                                        name={plugin.name}\n                                        enabled={plugin.enabled}\n                                        fToggleStatus={() =>\n                                            this.props.pluginStore.changeEnabledState(\n                                                plugin.id,\n                                                !plugin.enabled\n                                            )\n                                        }\n                                    />\n                                ))}\n                            </TableBody>\n                        </Table>\n                    </Paper>\n                </Grid>\n            </DefaultPage>\n        );\n    }\n}\n\ninterface IRowProps {\n    id: number;\n    name: string;\n    token: string;\n    enabled: boolean;\n    fToggleStatus: VoidFunction;\n}\n\nconst Row: SFC<IRowProps> = observer(({name, id, token, enabled, fToggleStatus}) => (\n    <TableRow>\n        <TableCell>{id}</TableCell>\n        <TableCell>\n            <Switch\n                checked={enabled}\n                onClick={fToggleStatus}\n                className=\"switch\"\n                data-enabled={enabled}\n            />\n        </TableCell>\n        <TableCell>{name}</TableCell>\n        <TableCell>\n            <CopyableSecret value={token} style={{display: 'flex', alignItems: 'center'}} />\n        </TableCell>\n        <TableCell align=\"right\" padding=\"none\">\n            <Link to={'/plugins/' + id}>\n                <Button>\n                    <Settings />\n                </Button>\n            </Link>\n        </TableCell>\n    </TableRow>\n));\n\nexport default inject('pluginStore')(Plugins);\n","import React from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport gfm from 'remark-gfm';\n\nexport const Markdown = ({children}: {children: string}) => (\n    <ReactMarkdown plugins={[gfm]}>{children}</ReactMarkdown>\n);\n","import Paper from '@material-ui/core/Paper';\nimport {withStyles, WithStyles} from '@material-ui/core/styles';\nimport * as React from 'react';\n\nconst styles = () => ({\n    paper: {\n        padding: 16,\n    },\n});\n\ninterface IProps extends WithStyles<'paper'> {\n    style?: React.CSSProperties;\n}\n\nconst Container: React.FC<IProps> = ({classes, children, style}) => (\n    <Paper elevation={6} className={classes.paper} style={style}>\n        {children}\n    </Paper>\n);\n\nexport default withStyles(styles)(Container);\n","import React, {Component} from 'react';\nimport {RouteComponentProps} from 'react-router';\nimport {Markdown} from '../common/Markdown';\nimport {UnControlled as CodeMirror} from 'react-codemirror2';\nimport 'codemirror/lib/codemirror.css';\nimport 'codemirror/theme/material.css';\nimport 'codemirror/mode/yaml/yaml';\nimport Info from '@material-ui/icons/Info';\nimport Build from '@material-ui/icons/Build';\nimport Subject from '@material-ui/icons/Subject';\nimport Refresh from '@material-ui/icons/Refresh';\nimport Button from '@material-ui/core/Button';\nimport Typography from '@material-ui/core/Typography';\nimport DefaultPage from '../common/DefaultPage';\nimport * as config from '../config';\nimport Container from '../common/Container';\nimport {inject, Stores} from '../inject';\nimport {IPlugin} from '../types';\nimport LoadingSpinner from '../common/LoadingSpinner';\n\ntype IProps = RouteComponentProps<{id: string}>;\n\ninterface IState {\n    displayText: string | null;\n    currentConfig: string | null;\n}\n\nclass PluginDetailView extends Component<IProps & Stores<'pluginStore'>, IState> {\n    private pluginID: number = parseInt(this.props.match.params.id, 10);\n    private pluginInfo = () => this.props.pluginStore.getByID(this.pluginID);\n\n    public state: IState = {\n        displayText: null,\n        currentConfig: null,\n    };\n\n    public componentWillMount() {\n        this.refreshFeatures();\n    }\n\n    public componentWillReceiveProps(nextProps: IProps & Stores<'pluginStore'>) {\n        this.pluginID = parseInt(nextProps.match.params.id, 10);\n        this.refreshFeatures();\n    }\n\n    private async refreshFeatures() {\n        await this.props.pluginStore.refreshIfMissing(this.pluginID);\n        return await Promise.all([this.refreshConfigurer(), this.refreshDisplayer()]);\n    }\n\n    private async refreshConfigurer() {\n        const {\n            props: {pluginStore},\n        } = this;\n        if (this.pluginInfo().capabilities.indexOf('configurer') !== -1) {\n            const response = await pluginStore.requestConfig(this.pluginID);\n            this.setState({currentConfig: response});\n        }\n    }\n\n    private async refreshDisplayer() {\n        const {\n            props: {pluginStore},\n        } = this;\n        if (this.pluginInfo().capabilities.indexOf('displayer') !== -1) {\n            const response = await pluginStore.requestDisplay(this.pluginID);\n            this.setState({displayText: response});\n        }\n    }\n\n    public render() {\n        const pluginInfo = this.props.pluginStore.getByIDOrUndefined(this.pluginID);\n        if (pluginInfo === undefined) {\n            return <LoadingSpinner />;\n        }\n        return (\n            <DefaultPage title={pluginInfo.name} maxWidth={1000}>\n                <PanelWrapper name={'Plugin Info'} icon={Info}>\n                    <PluginInfo pluginInfo={pluginInfo} />\n                </PanelWrapper>\n                {pluginInfo.capabilities.indexOf('configurer') !== -1 ? (\n                    <PanelWrapper\n                        name={'Configurer'}\n                        description={'This is the configuration panel for this plugin.'}\n                        icon={Build}\n                        refresh={this.refreshConfigurer.bind(this)}>\n                        <ConfigurerPanel\n                            pluginInfo={pluginInfo}\n                            initialConfig={\n                                this.state.currentConfig !== null\n                                    ? this.state.currentConfig\n                                    : 'Loading...'\n                            }\n                            save={async (newConfig) => {\n                                await this.props.pluginStore.changeConfig(this.pluginID, newConfig);\n                                await this.refreshFeatures();\n                            }}\n                        />\n                    </PanelWrapper>\n                ) : null}{' '}\n                {pluginInfo.capabilities.indexOf('displayer') !== -1 ? (\n                    <PanelWrapper\n                        name={'Displayer'}\n                        description={'This is the information generated by the plugin.'}\n                        refresh={this.refreshDisplayer.bind(this)}\n                        icon={Subject}>\n                        <DisplayerPanel\n                            pluginInfo={pluginInfo}\n                            displayText={\n                                this.state.displayText !== null\n                                    ? this.state.displayText\n                                    : 'Loading...'\n                            }\n                        />\n                    </PanelWrapper>\n                ) : null}\n            </DefaultPage>\n        );\n    }\n}\n\ninterface IPanelWrapperProps {\n    name: string;\n    description?: string;\n    refresh?: () => Promise<void>;\n    icon?: React.ComponentType;\n}\n\nconst PanelWrapper: React.FC<IPanelWrapperProps> = ({\n    name,\n    description,\n    refresh,\n    icon,\n    children,\n}) => {\n    const Icon = icon;\n    return (\n        <div\n            style={{\n                width: '100%',\n                paddingLeft: '16px',\n                paddingRight: '16px',\n            }}>\n            <Container\n                style={{\n                    display: 'block',\n                    width: '100%',\n                    margin: '12px 0px',\n                }}>\n                <Typography variant=\"h5\">\n                    {Icon ? (\n                        <span>\n                            <Icon />\n                            &nbsp;\n                        </span>\n                    ) : null}\n                    {name}\n                    {refresh ? (\n                        <Button\n                            style={{float: 'right'}}\n                            onClick={() => {\n                                refresh();\n                            }}>\n                            <Refresh />\n                        </Button>\n                    ) : null}\n                </Typography>\n                {description ? <Typography variant=\"subtitle1\">{description}</Typography> : null}\n                <hr />\n                <div className={name.toLowerCase().trim().replace(/ /g, '-')}>{children}</div>\n            </Container>\n        </div>\n    );\n};\n\ninterface IConfigurerPanelProps {\n    pluginInfo: IPlugin;\n    initialConfig: string;\n    save: (newConfig: string) => Promise<void>;\n}\nclass ConfigurerPanel extends Component<IConfigurerPanelProps, {unsavedChanges: string | null}> {\n    public state = {unsavedChanges: null};\n\n    public render() {\n        return (\n            <div>\n                <CodeMirror\n                    value={this.props.initialConfig}\n                    options={{\n                        mode: 'yaml',\n                        theme: 'material',\n                        lineNumbers: true,\n                    }}\n                    onChange={(_, _1, value) => {\n                        let newConf: string | null = value;\n                        if (value === this.props.initialConfig) {\n                            newConf = null;\n                        }\n                        this.setState({unsavedChanges: newConf});\n                    }}\n                />\n                <br />\n                <Button\n                    variant=\"contained\"\n                    color=\"primary\"\n                    fullWidth={true}\n                    disabled={\n                        this.state.unsavedChanges === null ||\n                        this.state.unsavedChanges === this.props.initialConfig\n                    }\n                    className=\"config-save\"\n                    onClick={() => {\n                        const newConfig = this.state.unsavedChanges;\n                        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n                        this.props.save(newConfig!).then(() => {\n                            this.setState({unsavedChanges: null});\n                        });\n                    }}>\n                    <Typography variant=\"button\">Save</Typography>\n                </Button>\n            </div>\n        );\n    }\n}\n\ninterface IDisplayerPanelProps {\n    pluginInfo: IPlugin;\n    displayText: string;\n}\nconst DisplayerPanel: React.FC<IDisplayerPanelProps> = ({displayText}) => (\n    <Typography variant=\"body2\">\n        <Markdown>{displayText}</Markdown>\n    </Typography>\n);\n\nclass PluginInfo extends Component<{pluginInfo: IPlugin}> {\n    public render() {\n        const {\n            props: {\n                pluginInfo: {name, author, modulePath, website, license, capabilities, id, token},\n            },\n        } = this;\n        return (\n            <div style={{wordWrap: 'break-word'}}>\n                {name ? (\n                    <Typography variant=\"body2\" className=\"name\">\n                        Name: <span>{name}</span>\n                    </Typography>\n                ) : null}\n                {author ? (\n                    <Typography variant=\"body2\" className=\"author\">\n                        Author: <span>{author}</span>\n                    </Typography>\n                ) : null}\n                <Typography variant=\"body2\" className=\"module-path\">\n                    Module Path: <span>{modulePath}</span>\n                </Typography>\n                {website ? (\n                    <Typography variant=\"body2\" className=\"website\">\n                        Website: <span>{website}</span>\n                    </Typography>\n                ) : null}\n                {license ? (\n                    <Typography variant=\"body2\" className=\"license\">\n                        License: <span>{license}</span>\n                    </Typography>\n                ) : null}\n                <Typography variant=\"body2\" className=\"capabilities\">\n                    Capabilities: <span>{capabilities.join(', ')}</span>\n                </Typography>\n                {capabilities.indexOf('webhooker') !== -1 ? (\n                    <Typography variant=\"body2\">\n                        Custom Route Prefix:{' '}\n                        {((url) => (\n                            <a\n                                href={url}\n                                target=\"_blank\"\n                                rel=\"noopener noreferrer\"\n                                className=\"custom-route\">\n                                {url}\n                            </a>\n                        ))(`${config.get('url')}plugin/${id}/custom/${token}/`)}\n                    </Typography>\n                ) : null}\n            </div>\n        );\n    }\n}\n\nexport default inject('pluginStore')(PluginDetailView);\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport React, {ChangeEvent, Component} from 'react';\n\ninterface IProps {\n    name?: string;\n    fClose: VoidFunction;\n    fOnSubmit: (name: string, pass: string) => Promise<boolean>;\n}\n\ninterface IState {\n    name: string;\n    pass: string;\n}\n\nexport default class RegistrationDialog extends Component<IProps, IState> {\n    public state = {\n        name: '',\n        pass: '',\n    };\n\n    public render() {\n        const {fClose, fOnSubmit} = this.props;\n        const {name, pass} = this.state;\n        const namePresent = this.state.name.length !== 0;\n        const passPresent = this.state.pass.length !== 0;\n        const submitAndClose = (): void => {\n            fOnSubmit(name, pass).then((success) => {\n                if (success) {\n                    fClose();\n                }\n            });\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"add-edit-user-dialog\">\n                <DialogTitle id=\"form-dialog-title\">Registration</DialogTitle>\n                <DialogContent>\n                    <TextField\n                        autoFocus\n                        margin=\"dense\"\n                        className=\"name\"\n                        label=\"Name *\"\n                        type=\"email\"\n                        value={name}\n                        onChange={this.handleChange.bind(this, 'name')}\n                        fullWidth\n                    />\n                    <TextField\n                        margin=\"dense\"\n                        className=\"password\"\n                        type=\"password\"\n                        value={pass}\n                        fullWidth\n                        label=\"Pass *\"\n                        onChange={this.handleChange.bind(this, 'pass')}\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip\n                        placement={'bottom-start'}\n                        title={\n                            namePresent\n                                ? passPresent\n                                    ? ''\n                                    : 'password is required'\n                                : 'name is required'\n                        }>\n                        <div>\n                            <Button\n                                className=\"save-create\"\n                                disabled={!passPresent || !namePresent}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                Register\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n\n    private handleChange(propertyName: string, event: ChangeEvent<HTMLInputElement>) {\n        const state = this.state;\n        state[propertyName] = event.target.value;\n        this.setState(state);\n    }\n}\n","import Button from '@material-ui/core/Button';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport React, {Component, FormEvent} from 'react';\nimport Container from '../common/Container';\nimport DefaultPage from '../common/DefaultPage';\nimport {observable} from 'mobx';\nimport {observer} from 'mobx-react';\nimport {inject, Stores} from '../inject';\nimport * as config from '../config';\nimport RegistrationDialog from './Register';\n\n@observer\nclass Login extends Component<Stores<'currentUser'>> {\n    @observable\n    private username = '';\n    @observable\n    private password = '';\n    @observable\n    private registerDialog = false;\n\n    public render() {\n        const {username, password, registerDialog} = this;\n        return (\n            <DefaultPage title=\"Login\" rightControl={this.registerButton()} maxWidth={250}>\n                <Grid item xs={12} style={{textAlign: 'center'}}>\n                    <Container>\n                        <form onSubmit={this.preventDefault} id=\"login-form\">\n                            <TextField\n                                autoFocus\n                                className=\"name\"\n                                label=\"Username\"\n                                margin=\"dense\"\n                                autoComplete=\"username\"\n                                value={username}\n                                onChange={(e) => (this.username = e.target.value)}\n                            />\n                            <TextField\n                                type=\"password\"\n                                className=\"password\"\n                                label=\"Password\"\n                                margin=\"normal\"\n                                autoComplete=\"current-password\"\n                                value={password}\n                                onChange={(e) => (this.password = e.target.value)}\n                            />\n                            <Button\n                                type=\"submit\"\n                                variant=\"contained\"\n                                size=\"large\"\n                                className=\"login\"\n                                color=\"primary\"\n                                disabled={!!this.props.currentUser.connectionErrorMessage}\n                                style={{marginTop: 15, marginBottom: 5}}\n                                onClick={this.login}>\n                                Login\n                            </Button>\n                        </form>\n                    </Container>\n                </Grid>\n                {registerDialog && (\n                    <RegistrationDialog\n                        fClose={() => (this.registerDialog = false)}\n                        fOnSubmit={this.props.currentUser.register}\n                    />\n                )}\n            </DefaultPage>\n        );\n    }\n\n    private login = (e: React.MouseEvent<HTMLButtonElement>) => {\n        e.preventDefault();\n        this.props.currentUser.login(this.username, this.password);\n    };\n\n    private registerButton = () => {\n        if (config.get('register'))\n            return (\n                <Button\n                    id=\"register\"\n                    variant=\"contained\"\n                    color=\"primary\"\n                    onClick={() => (this.registerDialog = true)}>\n                    Register\n                </Button>\n            );\n        else return null;\n    };\n\n    private preventDefault = (e: FormEvent<HTMLFormElement>) => e.preventDefault();\n}\n\nexport default inject('currentUser')(Login);\n","import IconButton from '@material-ui/core/IconButton';\nimport {createStyles, Theme, withStyles, WithStyles} from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport Delete from '@material-ui/icons/Delete';\nimport React from 'react';\nimport TimeAgo from 'react-timeago';\nimport Container from '../common/Container';\nimport * as config from '../config';\nimport {Markdown} from '../common/Markdown';\nimport {RenderMode, contentType} from './extras';\nimport {IMessageExtras} from '../types';\n\nconst styles = (theme: Theme) =>\n    createStyles({\n        header: {\n            display: 'flex',\n            flexWrap: 'wrap',\n            marginBottom: 0,\n        },\n        headerTitle: {\n            flex: 1,\n        },\n        trash: {\n            marginTop: -15,\n            marginRight: -15,\n        },\n        wrapperPadding: {\n            padding: 12,\n        },\n        messageContentWrapper: {\n            width: '100%',\n            maxWidth: 585,\n        },\n        image: {\n            marginRight: 15,\n            [theme.breakpoints.down('sm')]: {\n                width: 32,\n                height: 32,\n            },\n        },\n        date: {\n            [theme.breakpoints.down('sm')]: {\n                order: 1,\n                flexBasis: '100%',\n                opacity: 0.7,\n            },\n        },\n        imageWrapper: {\n            display: 'flex',\n        },\n        plainContent: {\n            whiteSpace: 'pre-wrap',\n        },\n        content: {\n            wordBreak: 'break-all',\n            '& p': {\n                margin: 0,\n            },\n            '& a': {\n                color: '#ff7f50',\n            },\n            '& pre': {\n                overflow: 'auto',\n            },\n            '& img': {\n                maxWidth: '100%',\n            },\n        },\n    });\n\ninterface IProps {\n    title: string;\n    image?: string;\n    date: string;\n    content: string;\n    priority: number;\n    fDelete: VoidFunction;\n    extras?: IMessageExtras;\n    height: (height: number) => void;\n}\n\nconst priorityColor = (priority: number) => {\n    if (priority >= 4 && priority <= 7) {\n        return 'rgba(230, 126, 34, 0.7)';\n    } else if (priority > 7) {\n        return '#e74c3c';\n    } else {\n        return 'transparent';\n    }\n};\n\nclass Message extends React.PureComponent<IProps & WithStyles<typeof styles>> {\n    private node: HTMLDivElement | null = null;\n\n    public componentDidMount = () =>\n        this.props.height(this.node ? this.node.getBoundingClientRect().height : 0);\n\n    private renderContent = () => {\n        const content = this.props.content;\n        switch (contentType(this.props.extras)) {\n            case RenderMode.Markdown:\n                return <Markdown>{content}</Markdown>;\n            case RenderMode.Plain:\n            default:\n                return <span className={this.props.classes.plainContent}>{content}</span>;\n        }\n    };\n\n    public render(): React.ReactNode {\n        const {fDelete, classes, title, date, image, priority} = this.props;\n\n        return (\n            <div className={`${classes.wrapperPadding} message`} ref={(ref) => (this.node = ref)}>\n                <Container\n                    style={{\n                        display: 'flex',\n                        borderLeftColor: priorityColor(priority),\n                        borderLeftWidth: 6,\n                        borderLeftStyle: 'solid',\n                    }}>\n                    <div className={classes.imageWrapper}>\n                        {image !== null ? (\n                            <img\n                                src={config.get('url') + image}\n                                alt=\"app logo\"\n                                width=\"70\"\n                                height=\"70\"\n                                className={classes.image}\n                            />\n                        ) : null}\n                    </div>\n                    <div className={classes.messageContentWrapper}>\n                        <div className={classes.header}>\n                            <Typography className={`${classes.headerTitle} title`} variant=\"h5\">\n                                {title}\n                            </Typography>\n                            <Typography variant=\"body1\" className={classes.date}>\n                                <TimeAgo date={date} />\n                            </Typography>\n                            <IconButton onClick={fDelete} className={`${classes.trash} delete`}>\n                                <Delete />\n                            </IconButton>\n                        </div>\n                        <Typography component=\"div\" className={`${classes.content} content`}>\n                            {this.renderContent()}\n                        </Typography>\n                    </div>\n                </Container>\n            </div>\n        );\n    }\n}\n\nexport default withStyles(styles, {withTheme: true})(Message);\n","import Grid from '@material-ui/core/Grid';\nimport Typography from '@material-ui/core/Typography';\nimport React, {Component} from 'react';\nimport {RouteComponentProps} from 'react-router';\nimport DefaultPage from '../common/DefaultPage';\nimport Button from '@material-ui/core/Button';\nimport Message from './Message';\nimport {observer} from 'mobx-react';\nimport {inject, Stores} from '../inject';\nimport {observable} from 'mobx';\nimport ReactInfinite from 'react-infinite';\nimport {IMessage} from '../types';\nimport ConfirmDialog from '../common/ConfirmDialog';\nimport LoadingSpinner from '../common/LoadingSpinner';\n\ntype IProps = RouteComponentProps<{id: string}>;\n\ninterface IState {\n    appId: number;\n}\n\n@observer\nclass Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>, IState> {\n    @observable\n    private heights: Record<string, number> = {};\n    @observable\n    private deleteAll = false;\n\n    private static appId(props: IProps) {\n        if (props === undefined) {\n            return -1;\n        }\n        const {match} = props;\n        return match.params.id !== undefined ? parseInt(match.params.id, 10) : -1;\n    }\n\n    public state = {appId: -1};\n\n    private isLoadingMore = false;\n\n    public componentWillReceiveProps(nextProps: IProps & Stores<'messagesStore' | 'appStore'>) {\n        this.updateAllWithProps(nextProps);\n    }\n\n    public componentWillMount() {\n        window.onscroll = () => {\n            if (\n                window.innerHeight + window.pageYOffset >=\n                document.body.offsetHeight - window.innerHeight * 2\n            ) {\n                this.checkIfLoadMore();\n            }\n        };\n        this.updateAll();\n    }\n\n    public render() {\n        const {appId} = this.state;\n        const {messagesStore, appStore} = this.props;\n        const messages = messagesStore.get(appId);\n        const hasMore = messagesStore.canLoadMore(appId);\n        const name = appStore.getName(appId);\n        const hasMessages = messages.length !== 0;\n\n        return (\n            <DefaultPage\n                title={name}\n                rightControl={\n                    <div>\n                        <Button\n                            id=\"refresh-all\"\n                            variant=\"contained\"\n                            color=\"primary\"\n                            onClick={() => messagesStore.refreshByApp(appId)}\n                            style={{marginRight: 5}}>\n                            Refresh\n                        </Button>\n                        <Button\n                            id=\"delete-all\"\n                            variant=\"contained\"\n                            disabled={!hasMessages}\n                            color=\"primary\"\n                            onClick={() => {\n                                this.deleteAll = true;\n                            }}>\n                            Delete All\n                        </Button>\n                    </div>\n                }>\n                {!messagesStore.loaded(appId) ? (\n                    <LoadingSpinner />\n                ) : hasMessages ? (\n                    <div style={{width: '100%'}} id=\"messages\">\n                        <ReactInfinite\n                            key={appId}\n                            useWindowAsScrollContainer\n                            preloadBatchSize={window.innerHeight * 3}\n                            elementHeight={messages.map((m) => this.heights[m.id] || 1)}>\n                            {messages.map(this.renderMessage)}\n                        </ReactInfinite>\n\n                        {hasMore ? <LoadingSpinner /> : this.label(\"You've reached the end\")}\n                    </div>\n                ) : (\n                    this.label('No messages')\n                )}\n\n                {this.deleteAll && (\n                    <ConfirmDialog\n                        title=\"Confirm Delete\"\n                        text={'Delete all messages?'}\n                        fClose={() => (this.deleteAll = false)}\n                        fOnSubmit={() => messagesStore.removeByApp(appId)}\n                    />\n                )}\n            </DefaultPage>\n        );\n    }\n\n    private updateAllWithProps = (props: IProps & Stores<'messagesStore'>) => {\n        const appId = Messages.appId(props);\n        this.setState({appId});\n        if (!props.messagesStore.exists(appId)) {\n            props.messagesStore.loadMore(appId);\n        }\n    };\n\n    private updateAll = () => this.updateAllWithProps(this.props);\n\n    private deleteMessage = (message: IMessage) => () =>\n        this.props.messagesStore.removeSingle(message);\n\n    private renderMessage = (message: IMessage) => (\n        <Message\n            key={message.id}\n            height={(height: number) => {\n                if (!this.heights[message.id]) {\n                    this.heights[message.id] = height;\n                }\n            }}\n            fDelete={this.deleteMessage(message)}\n            title={message.title}\n            date={message.date}\n            content={message.message}\n            image={message.image}\n            extras={message.extras}\n            priority={message.priority}\n        />\n    );\n\n    private checkIfLoadMore() {\n        const {appId} = this.state;\n        if (!this.isLoadingMore && this.props.messagesStore.canLoadMore(appId)) {\n            this.isLoadingMore = true;\n            this.props.messagesStore.loadMore(appId).then(() => (this.isLoadingMore = false));\n        }\n    }\n\n    private label = (text: string) => (\n        <Grid item xs={12}>\n            <Typography variant=\"caption\" component=\"div\" gutterBottom align=\"center\">\n                {text}\n            </Typography>\n        </Grid>\n    );\n}\n\nexport default inject('messagesStore', 'appStore')(Messages);\n","import Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Switch from '@material-ui/core/Switch';\nimport TextField from '@material-ui/core/TextField';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport React, {ChangeEvent, Component} from 'react';\n\ninterface IProps {\n    name?: string;\n    admin?: boolean;\n    fClose: VoidFunction;\n    fOnSubmit: (name: string, pass: string, admin: boolean) => void;\n    isEdit?: boolean;\n}\n\ninterface IState {\n    name: string;\n    pass: string;\n    admin: boolean;\n}\n\nexport default class AddEditDialog extends Component<IProps, IState> {\n    public state = {\n        name: this.props.name ?? '',\n        pass: '',\n        admin: this.props.admin ?? false,\n    };\n\n    public render() {\n        const {fClose, fOnSubmit, isEdit} = this.props;\n        const {name, pass, admin} = this.state;\n        const namePresent = this.state.name.length !== 0;\n        const passPresent = this.state.pass.length !== 0 || isEdit;\n        const submitAndClose = () => {\n            fOnSubmit(name, pass, admin);\n            fClose();\n        };\n        return (\n            <Dialog\n                open={true}\n                onClose={fClose}\n                aria-labelledby=\"form-dialog-title\"\n                id=\"add-edit-user-dialog\">\n                <DialogTitle id=\"form-dialog-title\">\n                    {isEdit ? 'Edit ' + this.props.name : 'Add a user'}\n                </DialogTitle>\n                <DialogContent>\n                    <TextField\n                        autoFocus\n                        margin=\"dense\"\n                        className=\"name\"\n                        label=\"Name *\"\n                        type=\"email\"\n                        value={name}\n                        onChange={this.handleChange.bind(this, 'name')}\n                        fullWidth\n                    />\n                    <TextField\n                        margin=\"dense\"\n                        className=\"password\"\n                        type=\"password\"\n                        value={pass}\n                        fullWidth\n                        label={isEdit ? 'Pass (empty if no change)' : 'Pass *'}\n                        onChange={this.handleChange.bind(this, 'pass')}\n                    />\n                    <FormControlLabel\n                        control={\n                            <Switch\n                                checked={admin}\n                                className=\"admin-rights\"\n                                onChange={this.handleChecked.bind(this, 'admin')}\n                                value=\"admin\"\n                            />\n                        }\n                        label=\"has administrator rights\"\n                    />\n                </DialogContent>\n                <DialogActions>\n                    <Button onClick={fClose}>Cancel</Button>\n                    <Tooltip\n                        placement={'bottom-start'}\n                        title={\n                            namePresent\n                                ? passPresent\n                                    ? ''\n                                    : 'password is required'\n                                : 'name is required'\n                        }>\n                        <div>\n                            <Button\n                                className=\"save-create\"\n                                disabled={!passPresent || !namePresent}\n                                onClick={submitAndClose}\n                                color=\"primary\"\n                                variant=\"contained\">\n                                {isEdit ? 'Save' : 'Create'}\n                            </Button>\n                        </div>\n                    </Tooltip>\n                </DialogActions>\n            </Dialog>\n        );\n    }\n\n    private handleChange(propertyName: string, event: ChangeEvent<HTMLInputElement>) {\n        const state = this.state;\n        state[propertyName] = event.target.value;\n        this.setState(state);\n    }\n\n    private handleChecked(propertyName: string, event: ChangeEvent<HTMLInputElement>) {\n        const state = this.state;\n        state[propertyName] = event.target.checked;\n        this.setState(state);\n    }\n}\n","import Grid from '@material-ui/core/Grid';\nimport IconButton from '@material-ui/core/IconButton';\nimport Paper from '@material-ui/core/Paper';\nimport {withStyles, WithStyles} from '@material-ui/core/styles';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableHead from '@material-ui/core/TableHead';\nimport TableRow from '@material-ui/core/TableRow';\nimport Delete from '@material-ui/icons/Delete';\nimport Edit from '@material-ui/icons/Edit';\nimport React, {Component, SFC} from 'react';\nimport ConfirmDialog from '../common/ConfirmDialog';\nimport DefaultPage from '../common/DefaultPage';\nimport Button from '@material-ui/core/Button';\nimport AddEditDialog from './AddEditUserDialog';\nimport {observer} from 'mobx-react';\nimport {observable} from 'mobx';\nimport {inject, Stores} from '../inject';\nimport {IUser} from '../types';\n\nconst styles = () => ({\n    wrapper: {\n        margin: '0 auto',\n        maxWidth: 700,\n    },\n});\n\ninterface IRowProps {\n    name: string;\n    admin: boolean;\n    fDelete: VoidFunction;\n    fEdit: VoidFunction;\n}\n\nconst UserRow: SFC<IRowProps> = ({name, admin, fDelete, fEdit}) => (\n    <TableRow>\n        <TableCell>{name}</TableCell>\n        <TableCell>{admin ? 'Yes' : 'No'}</TableCell>\n        <TableCell align=\"right\" padding=\"none\">\n            <IconButton onClick={fEdit} className=\"edit\">\n                <Edit />\n            </IconButton>\n            <IconButton onClick={fDelete} className=\"delete\">\n                <Delete />\n            </IconButton>\n        </TableCell>\n    </TableRow>\n);\n\n@observer\nclass Users extends Component<WithStyles<'wrapper'> & Stores<'userStore'>> {\n    @observable\n    private createDialog = false;\n    @observable\n    private deleteId: number | false = false;\n    @observable\n    private editId: number | false = false;\n\n    public componentDidMount = () => this.props.userStore.refresh();\n\n    public render() {\n        const {\n            deleteId,\n            editId,\n            createDialog,\n            props: {userStore},\n        } = this;\n        const users = userStore.getItems();\n        return (\n            <DefaultPage\n                title=\"Users\"\n                rightControl={\n                    <Button\n                        id=\"create-user\"\n                        variant=\"contained\"\n                        color=\"primary\"\n                        onClick={() => (this.createDialog = true)}>\n                        Create User\n                    </Button>\n                }>\n                <Grid item xs={12}>\n                    <Paper elevation={6} style={{overflowX: 'auto'}}>\n                        <Table id=\"user-table\">\n                            <TableHead>\n                                <TableRow style={{textAlign: 'center'}}>\n                                    <TableCell>Name</TableCell>\n                                    <TableCell>Admin</TableCell>\n                                    <TableCell />\n                                </TableRow>\n                            </TableHead>\n                            <TableBody>\n                                {users.map((user: IUser) => (\n                                    <UserRow\n                                        key={user.id}\n                                        name={user.name}\n                                        admin={user.admin}\n                                        fDelete={() => (this.deleteId = user.id)}\n                                        fEdit={() => (this.editId = user.id)}\n                                    />\n                                ))}\n                            </TableBody>\n                        </Table>\n                    </Paper>\n                </Grid>\n                {createDialog && (\n                    <AddEditDialog\n                        fClose={() => (this.createDialog = false)}\n                        fOnSubmit={userStore.create}\n                    />\n                )}\n                {editId !== false && (\n                    <AddEditDialog\n                        fClose={() => (this.editId = false)}\n                        fOnSubmit={userStore.update.bind(this, editId)}\n                        name={userStore.getByID(editId).name}\n                        admin={userStore.getByID(editId).admin}\n                        isEdit={true}\n                    />\n                )}\n                {deleteId !== false && (\n                    <ConfirmDialog\n                        title=\"Confirm Delete\"\n                        text={'Delete ' + userStore.getByID(deleteId).name + '?'}\n                        fClose={() => (this.deleteId = false)}\n                        fOnSubmit={() => userStore.remove(deleteId)}\n                    />\n                )}\n            </DefaultPage>\n        );\n    }\n}\n\nexport default withStyles(styles)(inject('userStore')(Users));\n","import React from 'react';\nimport Button from '@material-ui/core/Button';\nimport Typography from '@material-ui/core/Typography';\n\ninterface ConnectionErrorBannerProps {\n    height: number;\n    retry: () => void;\n    message: string;\n}\n\nexport const ConnectionErrorBanner = ({height, retry, message}: ConnectionErrorBannerProps) => (\n    <div\n        style={{\n            backgroundColor: '#e74c3c',\n            height,\n            width: '100%',\n            zIndex: 1300,\n            position: 'relative',\n        }}>\n        <Typography align=\"center\" variant=\"h6\" style={{lineHeight: `${height}px`}}>\n            {message}{' '}\n            <Button variant=\"outlined\" onClick={retry}>\n                Retry\n            </Button>\n        </Typography>\n    </div>\n);\n","import {createMuiTheme, MuiThemeProvider, Theme, WithStyles, withStyles} from '@material-ui/core';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport * as React from 'react';\nimport {HashRouter, Redirect, Route, Switch} from 'react-router-dom';\nimport Header from './Header';\nimport LoadingSpinner from '../common/LoadingSpinner';\nimport Navigation from './Navigation';\nimport ScrollUpButton from '../common/ScrollUpButton';\nimport SettingsDialog from '../common/SettingsDialog';\nimport SnackBarHandler from '../snack/SnackBarHandler';\nimport * as config from '../config';\nimport Applications from '../application/Applications';\nimport Clients from '../client/Clients';\nimport Plugins from '../plugin/Plugins';\nimport PluginDetailView from '../plugin/PluginDetailView';\nimport Login from '../user/Login';\nimport Messages from '../message/Messages';\nimport Users from '../user/Users';\nimport {observer} from 'mobx-react';\nimport {observable} from 'mobx';\nimport {inject, Stores} from '../inject';\nimport {ConnectionErrorBanner} from '../common/ConnectionErrorBanner';\n\nconst styles = (theme: Theme) => ({\n    content: {\n        margin: '0 auto',\n        marginTop: 64,\n        padding: theme.spacing(4),\n        width: '100%',\n        [theme.breakpoints.down('xs')]: {\n            marginTop: 0,\n        },\n    },\n});\n\nconst localStorageThemeKey = 'gotify-theme';\ntype ThemeKey = 'dark' | 'light';\nconst themeMap: Record<ThemeKey, Theme> = {\n    light: createMuiTheme({\n        palette: {\n            type: 'light',\n        },\n    }),\n    dark: createMuiTheme({\n        palette: {\n            type: 'dark',\n        },\n    }),\n};\n\nconst isThemeKey = (value: string | null): value is ThemeKey =>\n    value === 'light' || value === 'dark';\n\n@observer\nclass Layout extends React.Component<\n    WithStyles<'content'> & Stores<'currentUser' | 'snackManager'>\n> {\n    @observable\n    private currentTheme: ThemeKey = 'dark';\n    @observable\n    private showSettings = false;\n    @observable\n    private navOpen = false;\n\n    private setNavOpen(open: boolean) {\n        this.navOpen = open;\n    }\n\n    public componentDidMount() {\n        const localStorageTheme = window.localStorage.getItem(localStorageThemeKey);\n        if (isThemeKey(localStorageTheme)) {\n            this.currentTheme = localStorageTheme;\n        } else {\n            window.localStorage.setItem(localStorageThemeKey, this.currentTheme);\n        }\n    }\n\n    public render() {\n        const {showSettings, currentTheme} = this;\n        const {\n            classes,\n            currentUser: {\n                loggedIn,\n                authenticating,\n                user: {name, admin},\n                logout,\n                tryReconnect,\n                connectionErrorMessage,\n            },\n        } = this.props;\n        const theme = themeMap[currentTheme];\n        const loginRoute = () => (loggedIn ? <Redirect to=\"/\" /> : <Login />);\n        const {version} = config.get('version');\n        return (\n            <MuiThemeProvider theme={theme}>\n                <HashRouter>\n                    <div>\n                        {!connectionErrorMessage ? null : (\n                            <ConnectionErrorBanner\n                                height={64}\n                                retry={() => tryReconnect()}\n                                message={connectionErrorMessage}\n                            />\n                        )}\n                        <div style={{display: 'flex', flexDirection: 'column'}}>\n                            <CssBaseline />\n                            <Header\n                                style={{top: !connectionErrorMessage ? 0 : 64}}\n                                admin={admin}\n                                name={name}\n                                version={version}\n                                loggedIn={loggedIn}\n                                toggleTheme={this.toggleTheme.bind(this)}\n                                showSettings={() => (this.showSettings = true)}\n                                logout={logout}\n                                setNavOpen={this.setNavOpen.bind(this)}\n                            />\n                            <div style={{display: 'flex'}}>\n                                <Navigation\n                                    loggedIn={loggedIn}\n                                    navOpen={this.navOpen}\n                                    setNavOpen={this.setNavOpen.bind(this)}\n                                />\n                                <main className={classes.content}>\n                                    <Switch>\n                                        {authenticating ? (\n                                            <Route path=\"/\">\n                                                <LoadingSpinner />\n                                            </Route>\n                                        ) : null}\n                                        <Route exact path=\"/login\" render={loginRoute} />\n                                        {loggedIn ? null : <Redirect to=\"/login\" />}\n                                        <Route exact path=\"/\" component={Messages} />\n                                        <Route exact path=\"/messages/:id\" component={Messages} />\n                                        <Route\n                                            exact\n                                            path=\"/applications\"\n                                            component={Applications}\n                                        />\n                                        <Route exact path=\"/clients\" component={Clients} />\n                                        <Route exact path=\"/users\" component={Users} />\n                                        <Route exact path=\"/plugins\" component={Plugins} />\n                                        <Route\n                                            exact\n                                            path=\"/plugins/:id\"\n                                            component={PluginDetailView}\n                                        />\n                                    </Switch>\n                                </main>\n                            </div>\n                            {showSettings && (\n                                <SettingsDialog fClose={() => (this.showSettings = false)} />\n                            )}\n                            <ScrollUpButton />\n                            <SnackBarHandler />\n                        </div>\n                    </div>\n                </HashRouter>\n            </MuiThemeProvider>\n        );\n    }\n\n    private toggleTheme() {\n        this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';\n        localStorage.setItem(localStorageThemeKey, this.currentTheme);\n    }\n}\n\nexport default withStyles(styles, {withTheme: true})(inject('currentUser', 'snackManager')(Layout));\n","import axios, {AxiosError, AxiosResponse} from 'axios';\nimport * as config from './config';\nimport {Base64} from 'js-base64';\nimport {detect} from 'detect-browser';\nimport {SnackReporter} from './snack/SnackManager';\nimport {observable} from 'mobx';\nimport {IClient, IUser} from './types';\n\nconst tokenKey = 'gotify-login-key';\n\nexport class CurrentUser {\n    private tokenCache: string | null = null;\n    private reconnectTimeoutId: number | null = null;\n    private reconnectTime = 7500;\n    @observable\n    public loggedIn = false;\n    @observable\n    public authenticating = true;\n    @observable\n    public user: IUser = {name: 'unknown', admin: false, id: -1};\n    @observable\n    public connectionErrorMessage: string | null = null;\n\n    public constructor(private readonly snack: SnackReporter) {}\n\n    public token = (): string => {\n        if (this.tokenCache !== null) {\n            return this.tokenCache;\n        }\n\n        const localStorageToken = window.localStorage.getItem(tokenKey);\n        if (localStorageToken) {\n            this.tokenCache = localStorageToken;\n            return localStorageToken;\n        }\n\n        return '';\n    };\n\n    private readonly setToken = (token: string) => {\n        this.tokenCache = token;\n        window.localStorage.setItem(tokenKey, token);\n    };\n\n    public register = async (name: string, pass: string): Promise<boolean> =>\n        axios\n            .create()\n            .post(config.get('url') + 'user', {name, pass})\n            .then(() => {\n                this.snack('User Created. Logging in...');\n                this.login(name, pass);\n                return true;\n            })\n            .catch((error: AxiosError) => {\n                if (!error || !error.response) {\n                    this.snack('No network connection or server unavailable.');\n                    return false;\n                }\n                const {data} = error.response;\n                this.snack(\n                    `Register failed: ${data?.error ?? 'unknown'}: ${data?.errorDescription ?? ''}`\n                );\n                return false;\n            });\n\n    public login = async (username: string, password: string) => {\n        this.loggedIn = false;\n        this.authenticating = true;\n        const browser = detect();\n        const name = (browser && browser.name + ' ' + browser.version) || 'unknown browser';\n        axios\n            .create()\n            .request({\n                url: config.get('url') + 'client',\n                method: 'POST',\n                data: {name},\n                // eslint-disable-next-line @typescript-eslint/naming-convention\n                headers: {Authorization: 'Basic ' + Base64.encode(username + ':' + password)},\n            })\n            .then((resp: AxiosResponse<IClient>) => {\n                this.snack(`A client named '${name}' was created for your session.`);\n                this.setToken(resp.data.token);\n                this.tryAuthenticate().catch(() => {\n                    console.log(\n                        'create client succeeded, but authenticated with given token failed'\n                    );\n                });\n            })\n            .catch(() => {\n                this.authenticating = false;\n                return this.snack('Login failed');\n            });\n    };\n\n    public tryAuthenticate = async (): Promise<AxiosResponse<IUser>> => {\n        if (this.token() === '') {\n            this.authenticating = false;\n            return Promise.reject();\n        }\n\n        return (\n            axios\n                .create()\n                // eslint-disable-next-line @typescript-eslint/naming-convention\n                .get(config.get('url') + 'current/user', {headers: {'X-Gotify-Key': this.token()}})\n                .then((passThrough) => {\n                    this.user = passThrough.data;\n                    this.loggedIn = true;\n                    this.authenticating = false;\n                    this.connectionErrorMessage = null;\n                    this.reconnectTime = 7500;\n                    return passThrough;\n                })\n                .catch((error: AxiosError) => {\n                    this.authenticating = false;\n                    if (!error || !error.response) {\n                        this.connectionError('No network connection or server unavailable.');\n                        return Promise.reject(error);\n                    }\n\n                    if (error.response.status >= 500) {\n                        this.connectionError(\n                            `${error.response.statusText} (code: ${error.response.status}).`\n                        );\n                        return Promise.reject(error);\n                    }\n\n                    this.connectionErrorMessage = null;\n\n                    if (error.response.status >= 400 && error.response.status < 500) {\n                        this.logout();\n                    }\n                    return Promise.reject(error);\n                })\n        );\n    };\n\n    public logout = async () => {\n        await axios\n            .get(config.get('url') + 'client')\n            .then((resp: AxiosResponse<IClient[]>) => {\n                resp.data\n                    .filter((client) => client.token === this.tokenCache)\n                    .forEach((client) => axios.delete(config.get('url') + 'client/' + client.id));\n            })\n            .catch(() => Promise.resolve());\n        window.localStorage.removeItem(tokenKey);\n        this.tokenCache = null;\n        this.loggedIn = false;\n    };\n\n    public changePassword = (pass: string) => {\n        axios\n            .post(config.get('url') + 'current/user/password', {pass})\n            .then(() => this.snack('Password changed'));\n    };\n\n    public tryReconnect = (quiet = false) => {\n        this.tryAuthenticate().catch(() => {\n            if (!quiet) {\n                this.snack('Reconnect failed');\n            }\n        });\n    };\n\n    private readonly connectionError = (message: string) => {\n        this.connectionErrorMessage = message;\n        if (this.reconnectTimeoutId !== null) {\n            window.clearTimeout(this.reconnectTimeoutId);\n        }\n        this.reconnectTimeoutId = window.setTimeout(\n            () => this.tryReconnect(true),\n            this.reconnectTime\n        );\n        this.reconnectTime = Math.min(this.reconnectTime * 2, 120000);\n    };\n}\n","import {action, observable} from 'mobx';\n\ninterface HasID {\n    id: number;\n}\n\nexport interface IClearable {\n    clear(): void;\n}\n\n/**\n * Base implementation for handling items with ids.\n */\nexport abstract class BaseStore<T extends HasID> implements IClearable {\n    @observable\n    protected items: T[] = [];\n\n    protected abstract requestItems(): Promise<T[]>;\n\n    protected abstract requestDelete(id: number): Promise<void>;\n\n    @action\n    public remove = async (id: number): Promise<void> => {\n        await this.requestDelete(id);\n        await this.refresh();\n    };\n\n    @action\n    public refresh = async (): Promise<void> => {\n        this.items = await this.requestItems().then((items) => items || []);\n    };\n\n    @action\n    public refreshIfMissing = async (id: number): Promise<void> => {\n        if (this.getByIDOrUndefined(id) === undefined) {\n            await this.refresh();\n        }\n    };\n\n    public getByID = (id: number): T => {\n        const item = this.getByIDOrUndefined(id);\n        if (item === undefined) {\n            throw new Error('cannot find item with id ' + id);\n        }\n        return item;\n    };\n\n    public getByIDOrUndefined = (id: number): T | undefined =>\n        this.items.find((hasId: HasID) => hasId.id === id);\n\n    public getItems = (): T[] => this.items;\n\n    @action\n    public clear = (): void => {\n        this.items = [];\n    };\n}\n","import {BaseStore} from '../common/BaseStore';\nimport axios from 'axios';\nimport * as config from '../config';\nimport {action} from 'mobx';\nimport {SnackReporter} from '../snack/SnackManager';\nimport {IApplication} from '../types';\n\nexport class AppStore extends BaseStore<IApplication> {\n    public onDelete: () => void = () => {};\n\n    public constructor(private readonly snack: SnackReporter) {\n        super();\n    }\n\n    protected requestItems = (): Promise<IApplication[]> =>\n        axios\n            .get<IApplication[]>(`${config.get('url')}application`)\n            .then((response) => response.data);\n\n    protected requestDelete = (id: number): Promise<void> =>\n        axios.delete(`${config.get('url')}application/${id}`).then(() => {\n            this.onDelete();\n            return this.snack('Application deleted');\n        });\n\n    @action\n    public uploadImage = async (id: number, file: Blob): Promise<void> => {\n        const formData = new FormData();\n        formData.append('file', file);\n        await axios.post(`${config.get('url')}application/${id}/image`, formData, {\n            headers: {'content-type': 'multipart/form-data'},\n        });\n        await this.refresh();\n        this.snack('Application image updated');\n    };\n\n    @action\n    public update = async (\n        id: number,\n        name: string,\n        description: string,\n        defaultPriority: number\n    ): Promise<void> => {\n        await axios.put(`${config.get('url')}application/${id}`, {\n            name,\n            description,\n            defaultPriority,\n        });\n        await this.refresh();\n        this.snack('Application updated');\n    };\n\n    @action\n    public create = async (\n        name: string,\n        description: string,\n        defaultPriority: number\n    ): Promise<void> => {\n        await axios.post(`${config.get('url')}application`, {\n            name,\n            description,\n            defaultPriority,\n        });\n        await this.refresh();\n        this.snack('Application created');\n    };\n\n    public getName = (id: number): string => {\n        const app = this.getByIDOrUndefined(id);\n        return id === -1 ? 'All Messages' : app !== undefined ? app.name : 'unknown';\n    };\n}\n","import {SnackReporter} from '../snack/SnackManager';\nimport {CurrentUser} from '../CurrentUser';\nimport * as config from '../config';\nimport {AxiosError} from 'axios';\nimport {IMessage} from '../types';\n\nexport class WebSocketStore {\n    private wsActive = false;\n    private ws: WebSocket | null = null;\n\n    public constructor(\n        private readonly snack: SnackReporter,\n        private readonly currentUser: CurrentUser\n    ) {}\n\n    public listen = (callback: (msg: IMessage) => void) => {\n        if (!this.currentUser.token() || this.wsActive) {\n            return;\n        }\n        this.wsActive = true;\n\n        const wsUrl = config.get('url').replace('http', 'ws').replace('https', 'wss');\n        const ws = new WebSocket(wsUrl + 'stream?token=' + this.currentUser.token());\n\n        ws.onerror = (e) => {\n            this.wsActive = false;\n            console.log('WebSocket connection errored', e);\n        };\n\n        ws.onmessage = (data) => callback(JSON.parse(data.data));\n\n        ws.onclose = () => {\n            this.wsActive = false;\n            this.currentUser\n                .tryAuthenticate()\n                .then(() => {\n                    this.snack('WebSocket connection closed, trying again in 30 seconds.');\n                    setTimeout(() => this.listen(callback), 30000);\n                })\n                .catch((error: AxiosError) => {\n                    if (error?.response?.status === 401) {\n                        this.snack('Could not authenticate with client token, logging out.');\n                    }\n                });\n        };\n\n        this.ws = ws;\n    };\n\n    public close = () => this.ws?.close(1000, 'WebSocketStore#close');\n}\n","import {action, observable} from 'mobx';\n\nexport interface SnackReporter {\n    (message: string): void;\n}\n\nexport class SnackManager {\n    @observable\n    private messages: string[] = [];\n    @observable\n    public message: string | null = null;\n    @observable\n    public counter = 0;\n\n    @action\n    public next = (): void => {\n        if (!this.hasNext()) {\n            throw new Error('There is nothing here :(');\n        }\n        this.message = this.messages.shift() as string;\n    };\n\n    public hasNext = () => this.messages.length > 0;\n\n    @action\n    public snack: SnackReporter = (message: string): void => {\n        this.messages.push(message);\n        this.counter++;\n    };\n}\n","import {BaseStore} from '../common/BaseStore';\nimport axios from 'axios';\nimport * as config from '../config';\nimport {action} from 'mobx';\nimport {SnackReporter} from '../snack/SnackManager';\nimport {IUser} from '../types';\n\nexport class UserStore extends BaseStore<IUser> {\n    constructor(private readonly snack: SnackReporter) {\n        super();\n    }\n\n    protected requestItems = (): Promise<IUser[]> =>\n        axios.get<IUser[]>(`${config.get('url')}user`).then((response) => response.data);\n\n    protected requestDelete(id: number): Promise<void> {\n        return axios\n            .delete(`${config.get('url')}user/${id}`)\n            .then(() => this.snack('User deleted'));\n    }\n\n    @action\n    public create = async (name: string, pass: string, admin: boolean) => {\n        await axios.post(`${config.get('url')}user`, {name, pass, admin});\n        await this.refresh();\n        this.snack('User created');\n    };\n\n    @action\n    public update = async (id: number, name: string, pass: string | null, admin: boolean) => {\n        await axios.post(config.get('url') + 'user/' + id, {name, pass, admin});\n        await this.refresh();\n        this.snack('User updated');\n    };\n}\n","import {BaseStore} from '../common/BaseStore';\nimport {action, IObservableArray, observable, reaction} from 'mobx';\nimport axios, {AxiosResponse} from 'axios';\nimport * as config from '../config';\nimport {createTransformer} from 'mobx-utils';\nimport {SnackReporter} from '../snack/SnackManager';\nimport {IApplication, IMessage, IPagedMessages} from '../types';\n\nconst AllMessages = -1;\n\ninterface MessagesState {\n    messages: IObservableArray<IMessage>;\n    hasMore: boolean;\n    nextSince: number;\n    loaded: boolean;\n}\n\nexport class MessagesStore {\n    @observable\n    private state: Record<string, MessagesState> = {};\n\n    private loading = false;\n\n    public constructor(\n        private readonly appStore: BaseStore<IApplication>,\n        private readonly snack: SnackReporter\n    ) {\n        reaction(() => appStore.getItems(), this.createEmptyStatesForApps);\n    }\n\n    private stateOf = (appId: number, create = true) => {\n        if (!this.state[appId] && create) {\n            this.state[appId] = this.emptyState();\n        }\n        return this.state[appId] || this.emptyState();\n    };\n\n    public loaded = (appId: number) => this.stateOf(appId, /*create*/ false).loaded;\n\n    public canLoadMore = (appId: number) => this.stateOf(appId, /*create*/ false).hasMore;\n\n    @action\n    public loadMore = async (appId: number) => {\n        const state = this.stateOf(appId);\n        if (!state.hasMore || this.loading) {\n            return Promise.resolve();\n        }\n        this.loading = true;\n\n        const pagedResult = await this.fetchMessages(appId, state.nextSince).then(\n            (resp) => resp.data\n        );\n\n        state.messages.replace([...state.messages, ...pagedResult.messages]);\n        state.nextSince = pagedResult.paging.since ?? 0;\n        state.hasMore = 'next' in pagedResult.paging;\n        state.loaded = true;\n        this.loading = false;\n        return Promise.resolve();\n    };\n\n    @action\n    public publishSingleMessage = (message: IMessage) => {\n        if (this.exists(AllMessages)) {\n            this.stateOf(AllMessages).messages.unshift(message);\n        }\n        if (this.exists(message.appid)) {\n            this.stateOf(message.appid).messages.unshift(message);\n        }\n    };\n\n    @action\n    public removeByApp = async (appId: number) => {\n        if (appId === AllMessages) {\n            await axios.delete(config.get('url') + 'message');\n            this.snack('Deleted all messages');\n            this.clearAll();\n        } else {\n            await axios.delete(config.get('url') + 'application/' + appId + '/message');\n            this.snack(`Deleted all messages from ${this.appStore.getByID(appId).name}`);\n            this.clear(AllMessages);\n            this.clear(appId);\n        }\n        await this.loadMore(appId);\n    };\n\n    @action\n    public removeSingle = async (message: IMessage) => {\n        await axios.delete(config.get('url') + 'message/' + message.id);\n        if (this.exists(AllMessages)) {\n            this.removeFromList(this.state[AllMessages].messages, message);\n        }\n        if (this.exists(message.appid)) {\n            this.removeFromList(this.state[message.appid].messages, message);\n        }\n        this.snack('Message deleted');\n    };\n\n    @action\n    public clearAll = () => {\n        this.state = {};\n        this.createEmptyStatesForApps(this.appStore.getItems());\n    };\n\n    @action\n    public refreshByApp = async (appId: number) => {\n        this.clearAll();\n        this.loadMore(appId);\n    };\n\n    public exists = (id: number) => this.stateOf(id).loaded;\n\n    private removeFromList(messages: IMessage[], messageToDelete: IMessage): false | number {\n        if (messages) {\n            const index = messages.findIndex((message) => message.id === messageToDelete.id);\n            if (index !== -1) {\n                messages.splice(index, 1);\n                return index;\n            }\n        }\n        return false;\n    }\n\n    private clear = (appId: number) => (this.state[appId] = this.emptyState());\n\n    private fetchMessages = (\n        appId: number,\n        since: number\n    ): Promise<AxiosResponse<IPagedMessages>> => {\n        if (appId === AllMessages) {\n            return axios.get(config.get('url') + 'message?since=' + since);\n        } else {\n            return axios.get(\n                config.get('url') + 'application/' + appId + '/message?since=' + since\n            );\n        }\n    };\n\n    private getUnCached = (appId: number): Array<IMessage & {image: string | null}> => {\n        const appToImage = this.appStore\n            .getItems()\n            .reduce((all, app) => ({...all, [app.id]: app.image}), {});\n\n        return this.stateOf(appId, false).messages.map((message: IMessage) => ({\n            ...message,\n            image: appToImage[message.appid] || null,\n        }));\n    };\n\n    public get = createTransformer(this.getUnCached);\n\n    private clearCache = () => (this.get = createTransformer(this.getUnCached));\n\n    private createEmptyStatesForApps = (apps: IApplication[]) => {\n        apps.map((app) => app.id).forEach((id) => this.stateOf(id, /*create*/ true));\n        this.clearCache();\n    };\n\n    private emptyState = (): MessagesState => ({\n        messages: observable.array(),\n        hasMore: true,\n        nextSince: 0,\n        loaded: false,\n    });\n}\n","import {BaseStore} from '../common/BaseStore';\nimport axios from 'axios';\nimport * as config from '../config';\nimport {action} from 'mobx';\nimport {SnackReporter} from '../snack/SnackManager';\nimport {IClient} from '../types';\n\nexport class ClientStore extends BaseStore<IClient> {\n    public constructor(private readonly snack: SnackReporter) {\n        super();\n    }\n\n    protected requestItems = (): Promise<IClient[]> =>\n        axios.get<IClient[]>(`${config.get('url')}client`).then((response) => response.data);\n\n    protected requestDelete(id: number): Promise<void> {\n        return axios\n            .delete(`${config.get('url')}client/${id}`)\n            .then(() => this.snack('Client deleted'));\n    }\n\n    @action\n    public update = async (id: number, name: string): Promise<void> => {\n        await axios.put(`${config.get('url')}client/${id}`, {name});\n        await this.refresh();\n        this.snack('Client updated');\n    };\n\n    @action\n    public createNoNotifcation = async (name: string): Promise<IClient> => {\n        const client = await axios.post(`${config.get('url')}client`, {name});\n        await this.refresh();\n        return client.data;\n    };\n\n    @action\n    public create = async (name: string): Promise<void> => {\n        await this.createNoNotifcation(name);\n        this.snack('Client added');\n    };\n}\n","import axios from 'axios';\nimport {action} from 'mobx';\nimport {BaseStore} from '../common/BaseStore';\nimport * as config from '../config';\nimport {SnackReporter} from '../snack/SnackManager';\nimport {IPlugin} from '../types';\n\nexport class PluginStore extends BaseStore<IPlugin> {\n    public onDelete: () => void = () => {};\n\n    public constructor(private readonly snack: SnackReporter) {\n        super();\n    }\n\n    public requestConfig = (id: number): Promise<string> =>\n        axios.get(`${config.get('url')}plugin/${id}/config`).then((response) => response.data);\n\n    public requestDisplay = (id: number): Promise<string> =>\n        axios.get(`${config.get('url')}plugin/${id}/display`).then((response) => response.data);\n\n    protected requestItems = (): Promise<IPlugin[]> =>\n        axios.get<IPlugin[]>(`${config.get('url')}plugin`).then((response) => response.data);\n\n    protected requestDelete = (): Promise<void> => {\n        this.snack('Cannot delete plugin');\n        throw new Error('Cannot delete plugin');\n    };\n\n    public getName = (id: number): string => {\n        const plugin = this.getByIDOrUndefined(id);\n        return id === -1 ? 'All Plugins' : plugin !== undefined ? plugin.name : 'unknown';\n    };\n\n    @action\n    public changeConfig = async (id: number, newConfig: string): Promise<void> => {\n        await axios.post(`${config.get('url')}plugin/${id}/config`, newConfig, {\n            headers: {'content-type': 'application/x-yaml'},\n        });\n        this.snack(`Plugin config updated`);\n        await this.refresh();\n    };\n\n    @action\n    public changeEnabledState = async (id: number, enabled: boolean): Promise<void> => {\n        await axios.post(`${config.get('url')}plugin/${id}/${enabled ? 'enable' : 'disable'}`);\n        this.snack(`Plugin ${enabled ? 'enabled' : 'disabled'}`);\n        await this.refresh();\n    };\n}\n","import {StoreMapping} from './inject';\nimport {reaction} from 'mobx';\nimport * as Notifications from './snack/browserNotification';\n\nexport const registerReactions = (stores: StoreMapping) => {\n    const clearAll = () => {\n        stores.messagesStore.clearAll();\n        stores.appStore.clear();\n        stores.clientStore.clear();\n        stores.userStore.clear();\n        stores.wsStore.close();\n    };\n    const loadAll = () => {\n        stores.wsStore.listen((message) => {\n            stores.messagesStore.publishSingleMessage(message);\n            Notifications.notifyNewMessage(message);\n            if (message.priority >= 4) {\n                const src = 'static/notification.ogg';\n                const audio = new Audio(src);\n                audio.play();\n            }\n        });\n        stores.appStore.refresh();\n    };\n\n    reaction(\n        () => stores.currentUser.loggedIn,\n        (loggedIn) => {\n            if (loggedIn) {\n                loadAll();\n            } else {\n                clearAll();\n            }\n        }\n    );\n\n    reaction(\n        () => stores.currentUser.connectionErrorMessage,\n        (connectionErrorMessage) => {\n            if (!connectionErrorMessage) {\n                clearAll();\n                loadAll();\n            }\n        }\n    );\n};\n","import * as React from 'react';\nimport * as ReactDOM from 'react-dom';\nimport 'typeface-roboto';\nimport {initAxios} from './apiAuth';\nimport * as config from './config';\nimport Layout from './layout/Layout';\nimport {unregister} from './registerServiceWorker';\nimport {CurrentUser} from './CurrentUser';\nimport {AppStore} from './application/AppStore';\nimport {WebSocketStore} from './message/WebSocketStore';\nimport {SnackManager} from './snack/SnackManager';\nimport {InjectProvider, StoreMapping} from './inject';\nimport {UserStore} from './user/UserStore';\nimport {MessagesStore} from './message/MessagesStore';\nimport {ClientStore} from './client/ClientStore';\nimport {PluginStore} from './plugin/PluginStore';\nimport {registerReactions} from './reactions';\n\nconst devUrl = 'http://localhost:3000/';\n\nconst {port, hostname, protocol, pathname} = window.location;\nconst slashes = protocol.concat('//');\nconst path = pathname.endsWith('/') ? pathname : pathname.substring(0, pathname.lastIndexOf('/'));\nconst url = slashes.concat(port ? hostname.concat(':', port) : hostname) + path;\nconst urlWithSlash = url.endsWith('/') ? url : url.concat('/');\n\nconst prodUrl = urlWithSlash;\n\nconst initStores = (): StoreMapping => {\n    const snackManager = new SnackManager();\n    const appStore = new AppStore(snackManager.snack);\n    const userStore = new UserStore(snackManager.snack);\n    const messagesStore = new MessagesStore(appStore, snackManager.snack);\n    const currentUser = new CurrentUser(snackManager.snack);\n    const clientStore = new ClientStore(snackManager.snack);\n    const wsStore = new WebSocketStore(snackManager.snack, currentUser);\n    const pluginStore = new PluginStore(snackManager.snack);\n    appStore.onDelete = () => messagesStore.clearAll();\n\n    return {\n        appStore,\n        snackManager,\n        userStore,\n        messagesStore,\n        currentUser,\n        clientStore,\n        wsStore,\n        pluginStore,\n    };\n};\n\n(function clientJS() {\n    if (process.env.NODE_ENV === 'production') {\n        config.set('url', prodUrl);\n    } else {\n        config.set('url', devUrl);\n        config.set('register', true);\n    }\n    const stores = initStores();\n    initAxios(stores.currentUser, stores.snackManager.snack);\n\n    registerReactions(stores);\n\n    stores.currentUser.tryAuthenticate().catch(() => {});\n\n    window.onbeforeunload = () => {\n        stores.wsStore.close();\n    };\n\n    ReactDOM.render(\n        <InjectProvider stores={stores}>\n            <Layout />\n        </InjectProvider>,\n        document.getElementById('root')\n    );\n    unregister();\n})();\n","import axios from 'axios';\nimport {CurrentUser} from './CurrentUser';\nimport {SnackReporter} from './snack/SnackManager';\n\nexport const initAxios = (currentUser: CurrentUser, snack: SnackReporter) => {\n    axios.interceptors.request.use((config) => {\n        config.headers['X-Gotify-Key'] = currentUser.token();\n        return config;\n    });\n\n    axios.interceptors.response.use(undefined, (error) => {\n        if (!error.response) {\n            snack('Gotify server is not reachable, try refreshing the page.');\n            return Promise.reject(error);\n        }\n\n        const status = error.response.status;\n\n        if (status === 401) {\n            currentUser.tryAuthenticate().then(() => snack('Could not complete request.'));\n        }\n\n        if (status === 400 || status === 403 || status === 500) {\n            snack(error.response.data.error + ': ' + error.response.data.errorDescription);\n        }\n\n        return Promise.reject(error);\n    });\n};\n","export function unregister() {\n    if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.ready.then((registration) => {\n            registration.unregister();\n        });\n    }\n}\n"],"sourceRoot":""}