├── .babelrc
├── .dockerignore
├── .eslintignore
├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── 01_bug_report.md
│ ├── 02_feature_request.md
│ ├── 03_security_vulnerability.md
│ ├── 04_documentation_issue.md
│ ├── 05_question.md
│ ├── 06_discussion.md
│ └── 07_support.md
├── PULL_REQUEST_TEMPLATE.md
└── labels
│ ├── bsd.png
│ ├── bug.png
│ ├── can't reproduce.png
│ ├── code.png
│ ├── critical.png
│ ├── design.png
│ ├── discussion.png
│ ├── docker.png
│ ├── documentation.png
│ ├── duplicate.png
│ ├── enhancement.png
│ ├── feature.png
│ ├── help wanted.png
│ ├── in progress.png
│ ├── invalid.png
│ ├── labels.md
│ ├── linux.png
│ ├── macOS.png
│ ├── more info needed.png
│ ├── not a bug.png
│ ├── on hold.png
│ ├── optimization.png
│ ├── performance.png
│ ├── question.png
│ ├── security.png
│ ├── test.png
│ ├── waiting feedback.png
│ ├── watchlist.png
│ ├── windows.png
│ └── wontfix.png
├── .gitignore
├── .jsdoc.json
├── .prettierrc
├── .travis.yml
├── ABOUT.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── README.md
├── client
├── .eslintrc.js
├── config
│ ├── .eslintrc.js
│ ├── env.js
│ ├── jest
│ │ ├── cssTransform.js
│ │ └── fileTransform.js
│ ├── paths.js
│ ├── polyfills.js
│ ├── webpack.config.dev.js
│ ├── webpack.config.prod.js
│ └── webpackDevServer.config.js
├── scripts
│ ├── .eslintrc.js
│ ├── build.js
│ ├── deprecated-warning.js
│ ├── start.js
│ ├── svg-react-component-generator.js
│ ├── test.js
│ └── typed-css-modules-loader.js
└── src
│ ├── fonts
│ ├── LICENSE.txt
│ ├── Roboto-500
│ │ ├── Roboto-500.eot
│ │ ├── Roboto-500.svg
│ │ ├── Roboto-500.ttf
│ │ ├── Roboto-500.woff
│ │ └── Roboto-500.woff2
│ ├── Roboto-700
│ │ ├── Roboto-700.eot
│ │ ├── Roboto-700.svg
│ │ ├── Roboto-700.ttf
│ │ ├── Roboto-700.woff
│ │ └── Roboto-700.woff2
│ ├── Roboto-700italic
│ │ ├── Roboto-700italic.eot
│ │ ├── Roboto-700italic.svg
│ │ ├── Roboto-700italic.ttf
│ │ ├── Roboto-700italic.woff
│ │ └── Roboto-700italic.woff2
│ ├── Roboto-italic
│ │ ├── Roboto-italic.eot
│ │ ├── Roboto-italic.svg
│ │ ├── Roboto-italic.ttf
│ │ ├── Roboto-italic.woff
│ │ └── Roboto-italic.woff2
│ └── Roboto-regular
│ │ ├── Roboto-regular.eot
│ │ ├── Roboto-regular.svg
│ │ ├── Roboto-regular.ttf
│ │ ├── Roboto-regular.woff
│ │ └── Roboto-regular.woff2
│ ├── images
│ ├── flags
│ │ ├── ad.png
│ │ ├── ae.png
│ │ ├── af.png
│ │ ├── ag.png
│ │ ├── al.png
│ │ ├── am.png
│ │ ├── ao.png
│ │ ├── ar.png
│ │ ├── at.png
│ │ ├── au.png
│ │ ├── az.png
│ │ ├── ba.png
│ │ ├── bb.png
│ │ ├── bd.png
│ │ ├── be.png
│ │ ├── bf.png
│ │ ├── bg.png
│ │ ├── bh.png
│ │ ├── bi.png
│ │ ├── bj.png
│ │ ├── bn.png
│ │ ├── bo.png
│ │ ├── br.png
│ │ ├── bs.png
│ │ ├── bt.png
│ │ ├── bw.png
│ │ ├── by.png
│ │ ├── bz.png
│ │ ├── ca.png
│ │ ├── cd.png
│ │ ├── cf.png
│ │ ├── cg.png
│ │ ├── ch.png
│ │ ├── ci.png
│ │ ├── cl.png
│ │ ├── cm.png
│ │ ├── cn.png
│ │ ├── co.png
│ │ ├── cr.png
│ │ ├── cu.png
│ │ ├── cv.png
│ │ ├── cw.png
│ │ ├── cy.png
│ │ ├── cz.png
│ │ ├── de.png
│ │ ├── dj.png
│ │ ├── dk.png
│ │ ├── dm.png
│ │ ├── do.png
│ │ ├── dz.png
│ │ ├── ec.png
│ │ ├── ee.png
│ │ ├── eg.png
│ │ ├── eh.png
│ │ ├── er.png
│ │ ├── es.png
│ │ ├── et.png
│ │ ├── fi.png
│ │ ├── fj.png
│ │ ├── fm.png
│ │ ├── fr.png
│ │ ├── ga.png
│ │ ├── gb.png
│ │ ├── gd.png
│ │ ├── ge.png
│ │ ├── gh.png
│ │ ├── gm.png
│ │ ├── gn.png
│ │ ├── gq.png
│ │ ├── gr.png
│ │ ├── gt.png
│ │ ├── gw.png
│ │ ├── gy.png
│ │ ├── hk.png
│ │ ├── hn.png
│ │ ├── hr.png
│ │ ├── ht.png
│ │ ├── hu.png
│ │ ├── id.png
│ │ ├── ie.png
│ │ ├── il.png
│ │ ├── in.png
│ │ ├── iq.png
│ │ ├── ir.png
│ │ ├── is.png
│ │ ├── it.png
│ │ ├── je.png
│ │ ├── jm.png
│ │ ├── jo.png
│ │ ├── jp.png
│ │ ├── ke.png
│ │ ├── kg.png
│ │ ├── kh.png
│ │ ├── ki.png
│ │ ├── km.png
│ │ ├── kn.png
│ │ ├── kp.png
│ │ ├── kr.png
│ │ ├── ks.png
│ │ ├── kw.png
│ │ ├── kz.png
│ │ ├── la.png
│ │ ├── lb.png
│ │ ├── lc.png
│ │ ├── li.png
│ │ ├── lk.png
│ │ ├── lr.png
│ │ ├── ls.png
│ │ ├── lt.png
│ │ ├── lu.png
│ │ ├── lv.png
│ │ ├── ly.png
│ │ ├── ma.png
│ │ ├── mc.png
│ │ ├── md.png
│ │ ├── me.png
│ │ ├── mg.png
│ │ ├── mh.png
│ │ ├── mk.png
│ │ ├── ml.png
│ │ ├── mm.png
│ │ ├── mn.png
│ │ ├── mr.png
│ │ ├── mt.png
│ │ ├── mu.png
│ │ ├── mv.png
│ │ ├── mw.png
│ │ ├── mx.png
│ │ ├── my.png
│ │ ├── mz.png
│ │ ├── na.png
│ │ ├── ne.png
│ │ ├── ng.png
│ │ ├── ni.png
│ │ ├── nl.png
│ │ ├── no.png
│ │ ├── np.png
│ │ ├── nr.png
│ │ ├── nz.png
│ │ ├── om.png
│ │ ├── pa.png
│ │ ├── pe.png
│ │ ├── pg.png
│ │ ├── ph.png
│ │ ├── pk.png
│ │ ├── pl.png
│ │ ├── pt.png
│ │ ├── pw.png
│ │ ├── py.png
│ │ ├── qa.png
│ │ ├── ro.png
│ │ ├── rs.png
│ │ ├── ru.png
│ │ ├── rw.png
│ │ ├── sa.png
│ │ ├── sb.png
│ │ ├── sc.png
│ │ ├── sd.png
│ │ ├── se.png
│ │ ├── sg.png
│ │ ├── si.png
│ │ ├── sk.png
│ │ ├── sl.png
│ │ ├── sm.png
│ │ ├── sn.png
│ │ ├── so.png
│ │ ├── sr.png
│ │ ├── st.png
│ │ ├── sv.png
│ │ ├── sy.png
│ │ ├── sz.png
│ │ ├── td.png
│ │ ├── tg.png
│ │ ├── th.png
│ │ ├── tj.png
│ │ ├── tl.png
│ │ ├── tm.png
│ │ ├── tn.png
│ │ ├── to.png
│ │ ├── tr.png
│ │ ├── tt.png
│ │ ├── tv.png
│ │ ├── tw.png
│ │ ├── tz.png
│ │ ├── ua.png
│ │ ├── ug.png
│ │ ├── us.png
│ │ ├── uy.png
│ │ ├── uz.png
│ │ ├── va.png
│ │ ├── vc.png
│ │ ├── ve.png
│ │ ├── vn.png
│ │ ├── vu.png
│ │ ├── ws.png
│ │ ├── ye.png
│ │ ├── za.png
│ │ ├── zm.png
│ │ └── zw.png
│ └── flood.svg
│ ├── index.html
│ ├── javascript
│ ├── actions
│ │ ├── AuthActions.js
│ │ ├── ClientActions.js
│ │ ├── FloodActions.js
│ │ ├── SettingsActions.js
│ │ ├── TorrentActions.js
│ │ └── UIActions.js
│ ├── app.tsx
│ ├── components
│ │ ├── AppWrapper.js
│ │ ├── alerts
│ │ │ ├── Alert.js
│ │ │ └── Alerts.js
│ │ ├── auth
│ │ │ └── AuthForm.js
│ │ ├── general
│ │ │ ├── Badge.js
│ │ │ ├── ClientConnectionInterruption.js
│ │ │ ├── CustomScrollbars.js
│ │ │ ├── Duration.js
│ │ │ ├── GlobalContextMenuMountPoint.js
│ │ │ ├── Icon.scss
│ │ │ ├── Icon.scss.d.ts
│ │ │ ├── Icon.tsx
│ │ │ ├── ListViewport.js
│ │ │ ├── LoadingIndicator.js
│ │ │ ├── NavigationList.js
│ │ │ ├── Portal.js
│ │ │ ├── ProgressBar.js
│ │ │ ├── Ratio.js
│ │ │ ├── RtorrentConnectionTypeSelection.js
│ │ │ ├── Size.js
│ │ │ ├── SortableList.js
│ │ │ ├── SortableListItem.js
│ │ │ ├── SortableListItemDragLayer.js
│ │ │ ├── Tooltip.js
│ │ │ ├── WindowTitle.js
│ │ │ ├── filesystem
│ │ │ │ ├── DirectoryFileList.js
│ │ │ │ ├── DirectoryTree.js
│ │ │ │ ├── DirectoryTreeNode.js
│ │ │ │ ├── FilesystemBrowser.js
│ │ │ │ ├── PriorityMeter.js
│ │ │ │ └── TorrentDestination.js
│ │ │ └── form-elements
│ │ │ │ ├── Dropdown.js
│ │ │ │ └── TextboxRepeater.js
│ │ ├── icons
│ │ │ ├── Active.js
│ │ │ ├── Add.js
│ │ │ ├── AddMini.js
│ │ │ ├── All.js
│ │ │ ├── ArrowIcon.js
│ │ │ ├── BaseIcon.js
│ │ │ ├── CalendarCreatedIcon.js
│ │ │ ├── CalendarIcon.js
│ │ │ ├── Checkmark.js
│ │ │ ├── ChevronLeftIcon.js
│ │ │ ├── ChevronRightIcon.js
│ │ │ ├── CircleCheckmarkIcon.js
│ │ │ ├── CircleExclamationIcon.js
│ │ │ ├── CircleIcon.js
│ │ │ ├── ClipboardIcon.js
│ │ │ ├── ClockIcon.js
│ │ │ ├── Close.js
│ │ │ ├── CommentIcon.js
│ │ │ ├── Completed.js
│ │ │ ├── DetailNotAvailableIcon.js
│ │ │ ├── Disk.js
│ │ │ ├── DiskIcon.js
│ │ │ ├── DotsMini.js
│ │ │ ├── Download.js
│ │ │ ├── DownloadSmall.js
│ │ │ ├── DownloadThickIcon.js
│ │ │ ├── ETA.js
│ │ │ ├── Edit.js
│ │ │ ├── ErrorIcon.js
│ │ │ ├── FeedIcon.js
│ │ │ ├── File.js
│ │ │ ├── Files.js
│ │ │ ├── FolderClosedOutlined.js
│ │ │ ├── FolderClosedSolid.js
│ │ │ ├── FolderOpenOutlined.js
│ │ │ ├── FolderOpenSolid.js
│ │ │ ├── HashIcon.js
│ │ │ ├── Inactive.js
│ │ │ ├── InfinityIcon.js
│ │ │ ├── InformationIcon.js
│ │ │ ├── Limits.js
│ │ │ ├── LoadingIndicatorDots.js
│ │ │ ├── LockIcon.js
│ │ │ ├── Logout.js
│ │ │ ├── NotificationIcon.js
│ │ │ ├── PeersIcon.js
│ │ │ ├── RadarIcon.js
│ │ │ ├── RadioDot.js
│ │ │ ├── Ratio.js
│ │ │ ├── RatioIcon.js
│ │ │ ├── Remove.js
│ │ │ ├── RemoveMini.js
│ │ │ ├── Search.js
│ │ │ ├── SeedsIcon.js
│ │ │ ├── SettingsIcon.js
│ │ │ ├── SpinnerIcon.js
│ │ │ ├── StartIcon.js
│ │ │ ├── StopIcon.js
│ │ │ ├── TrackerMessageIcon.js
│ │ │ ├── Upload.js
│ │ │ └── UploadThickIcon.js
│ │ ├── layout
│ │ │ ├── ApplicationContent.js
│ │ │ ├── ApplicationPanel.js
│ │ │ └── ApplicationView.js
│ │ ├── modals
│ │ │ ├── Modal.js
│ │ │ ├── ModalActions.js
│ │ │ ├── ModalFormSectionHeader.js
│ │ │ ├── ModalTabs.js
│ │ │ ├── Modals.js
│ │ │ ├── add-torrents-modal
│ │ │ │ ├── AddTorrentsActions.js
│ │ │ │ ├── AddTorrentsByFile.js
│ │ │ │ ├── AddTorrentsByURL.js
│ │ │ │ └── AddTorrentsModal.js
│ │ │ ├── confirm-modal
│ │ │ │ └── ConfirmModal.js
│ │ │ ├── feeds-modal
│ │ │ │ ├── DownloadRulesTab.js
│ │ │ │ ├── FeedsModal.js
│ │ │ │ └── FeedsTab.js
│ │ │ ├── move-torrents-modal
│ │ │ │ └── MoveTorrentsModal.js
│ │ │ ├── remove-torrents-modal
│ │ │ │ └── RemoveTorrentsModal.js
│ │ │ ├── set-tags-modal
│ │ │ │ └── SetTagsModal.js
│ │ │ ├── settings-modal
│ │ │ │ ├── AboutTab.js
│ │ │ │ ├── AuthTab.js
│ │ │ │ ├── BandwidthTab.js
│ │ │ │ ├── ConnectivityTab.js
│ │ │ │ ├── DiskUsageTab.js
│ │ │ │ ├── ResourcesTab.js
│ │ │ │ ├── SettingsModal.js
│ │ │ │ ├── SettingsTab.js
│ │ │ │ ├── UITab.js
│ │ │ │ └── UITabSortableDetailColumns.js
│ │ │ └── torrent-details-modal
│ │ │ │ ├── NavigationList.js
│ │ │ │ ├── TorrentDetailsModal.js
│ │ │ │ ├── TorrentFiles.js
│ │ │ │ ├── TorrentGeneralInfo.js
│ │ │ │ ├── TorrentHeading.js
│ │ │ │ ├── TorrentMediainfo.js
│ │ │ │ ├── TorrentPeers.js
│ │ │ │ └── TorrentTrackers.js
│ │ ├── sidebar
│ │ │ ├── DiskUsage.js
│ │ │ ├── FeedsButton.js
│ │ │ ├── LogoutButton.js
│ │ │ ├── NotificationsButton.js
│ │ │ ├── SearchTorrents.js
│ │ │ ├── SettingsButton.js
│ │ │ ├── Sidebar.js
│ │ │ ├── SidebarActions.js
│ │ │ ├── SidebarFilter.js
│ │ │ ├── SidebarItem.js
│ │ │ ├── SpeedLimitDropdown.js
│ │ │ ├── StatusFilters.js
│ │ │ ├── TagFilters.js
│ │ │ ├── TrackerFilters.js
│ │ │ ├── TransferData.js
│ │ │ ├── TransferRateDetails.js
│ │ │ └── TransferRateGraph.js
│ │ ├── torrent-list
│ │ │ ├── Action.js
│ │ │ ├── ActionBar.js
│ │ │ ├── SortDropdown.js
│ │ │ ├── TableHeading.js
│ │ │ ├── Torrent.js
│ │ │ ├── TorrentDetail.js
│ │ │ └── TorrentList.js
│ │ └── views
│ │ │ ├── Login.js
│ │ │ ├── Register.js
│ │ │ └── TorrentClientOverview.js
│ ├── constants
│ │ ├── ActionTypes.js
│ │ ├── Alerts.js
│ │ ├── EventTypes.js
│ │ ├── Languages.js
│ │ ├── PriorityLevels.js
│ │ └── TorrentProperties.js
│ ├── dispatcher
│ │ └── AppDispatcher.js
│ ├── i18n
│ │ ├── de.js
│ │ ├── en.js
│ │ ├── es.js
│ │ ├── fr.js
│ │ ├── ko.js
│ │ ├── languages.ts
│ │ ├── nl.js
│ │ └── zh.js
│ ├── stores
│ │ ├── AlertStore.js
│ │ ├── AuthStore.js
│ │ ├── BaseStore.js
│ │ ├── ClientStatusStore.js
│ │ ├── ConfigStore.js
│ │ ├── DiskUsageStore.js
│ │ ├── FeedMonitorStore.js
│ │ ├── NotificationStore.js
│ │ ├── SettingsStore.js
│ │ ├── TorrentFilterStore.js
│ │ ├── TorrentStore.js
│ │ ├── TransferDataStore.js
│ │ └── UIStore.js
│ └── util
│ │ ├── connectStores.tsx
│ │ ├── filterTorrents.js
│ │ ├── history.js
│ │ ├── searchTorrents.js
│ │ ├── selectTorrents.js
│ │ ├── size.js
│ │ ├── sortTorrents.js
│ │ ├── torrentStatusClasses.js
│ │ ├── torrentStatusIcons.js
│ │ └── validators.js
│ ├── public
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── browserconfig.xml
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── manifest.json
│ ├── mstile-144x144.png
│ ├── mstile-150x150.png
│ ├── mstile-310x150.png
│ ├── mstile-310x310.png
│ ├── mstile-70x70.png
│ └── safari-pinned-tab.svg
│ └── sass
│ ├── base
│ ├── _animations.scss
│ ├── _font-families.scss
│ ├── _layout.scss
│ ├── _main.scss
│ └── _typography.scss
│ ├── components
│ ├── _action-bar.scss
│ ├── _alerts.scss
│ ├── _app-wrapper.scss
│ ├── _attached-panel.scss
│ ├── _badge.scss
│ ├── _base-menu.scss
│ ├── _client-stats.scss
│ ├── _connection-status.scss
│ ├── _dependency-list.scss
│ ├── _directory-tree.scss
│ ├── _dropdown.scss
│ ├── _dropzone.scss
│ ├── _duration.scss
│ ├── _filesystem.scss
│ ├── _floating-action.scss
│ ├── _icons.scss
│ ├── _interactive-list.scss
│ ├── _loading-indicator.scss
│ ├── _mediainfo.scss
│ ├── _modals.scss
│ ├── _notifications.scss
│ ├── _peers-list.scss
│ ├── _priority-meter.scss
│ ├── _progress-bar.scss
│ ├── _scrollbars.scss
│ ├── _search.scss
│ ├── _sidebar-filter.scss
│ ├── _sidebar.scss
│ ├── _sort-dropdown.scss
│ ├── _sortable-list.scss
│ ├── _table.scss
│ ├── _tags.scss
│ ├── _textbox-repeater.scss
│ ├── _toolbar.scss
│ ├── _tooltip.scss
│ ├── _torrent-details-panel.scss
│ ├── _torrent.scss
│ ├── _torrents.scss
│ └── _transfer-data.scss
│ ├── style.scss
│ ├── style.scss.d.ts
│ ├── tools
│ ├── _colors.scss
│ ├── _reset.scss
│ └── _variables.scss
│ └── views
│ ├── _feeds.scss
│ └── _login.scss
├── config.docker.js
├── config.template.js
├── custom.d.ts
├── flood.png
├── package-lock.json
├── package.json
├── scripts
└── prettier.js
├── server
├── .eslintrc.js
├── app.js
├── bin
│ ├── enforce-prerequisites.js
│ ├── migrations
│ │ ├── fix-is-admin-flag.js
│ │ ├── per-user-rtorrent-instances.js
│ │ └── run.js
│ ├── start.js
│ └── web-server.js
├── config
│ └── passport.js
├── constants
│ ├── clientGatewayServiceEvents.js
│ ├── diskUsageServiceEvents.js
│ ├── fileListPropMap.js
│ ├── historyServiceEvents.js
│ ├── notificationServiceEvents.js
│ ├── taxonomyServiceEvents.js
│ ├── torrentListPropMap.js
│ ├── torrentServiceEvents.js
│ └── transferSummaryPropMap.js
├── middleware
│ ├── appendUserServices.js
│ ├── booleanCoerce.js
│ ├── clientActivityStream.js
│ ├── eventStream.js
│ └── requireAdmin.js
├── models
│ ├── ClientRequest.js
│ ├── Feed.js
│ ├── Filesystem.js
│ ├── HistoryEra.js
│ ├── ServerEvent.js
│ ├── TemporaryStorage.js
│ ├── Users.js
│ ├── client.js
│ └── settings.js
├── routes
│ ├── api.js
│ ├── auth.js
│ └── client.js
├── services
│ ├── BaseService.js
│ ├── clientGatewayService.js
│ ├── clientRequestManager.js
│ ├── diskUsageService.js
│ ├── feedService.js
│ ├── historyService.js
│ ├── index.js
│ ├── notificationService.js
│ ├── taxonomyService.js
│ └── torrentService.js
├── util
│ ├── ajaxUtil.js
│ ├── clientResponseUtil.js
│ ├── mediainfo.js
│ ├── methodCallUtil.js
│ ├── minifyUtil.js
│ ├── numberUtils.js
│ ├── rTorrentDeserializer.js
│ ├── rTorrentPropMap.js
│ └── scgiUtil.js
└── views
│ ├── error.pug
│ └── layout.pug
├── shared
├── constants
│ ├── clientSettingsMap.js
│ ├── diffActionTypes.js
│ ├── historySnapshotTypes.js
│ ├── serverEventTypes.js
│ ├── torrentFilePropsMap.js
│ ├── torrentPeerPropsMap.js
│ ├── torrentStatusMap.js
│ └── torrentTrackerPropsMap.js
└── util
│ ├── formatUtil.js
│ ├── objectUtil.js
│ ├── regEx.js
│ └── stringUtil.js
└── tsconfig.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/env",
4 | "@babel/typescript",
5 | "@babel/react"
6 | ],
7 | "plugins": [
8 | "@babel/plugin-proposal-class-properties",
9 | "@babel/proposal-object-rest-spread"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Ignore files not needed for building and running to keep image size low.
2 | .git/
3 | node_modules/
4 |
5 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /server/assets
3 | **/*.d.ts
4 | /docs
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['airbnb', 'plugin:import/errors', 'plugin:import/warnings', 'prettier'],
3 | parser: 'babel-eslint',
4 | plugins: ['import'],
5 | rules: {
6 | 'arrow-parens': 0,
7 | 'class-methods-use-this': 0,
8 | 'consistent-return': 0,
9 | 'implicit-arrow-linebreak': 0,
10 | 'import/no-extraneous-dependencies': 0,
11 | 'import/prefer-default-export': 0,
12 | 'max-len': [
13 | 'error',
14 | {
15 | code: 120,
16 | ignoreRegExpLiterals: true,
17 | ignoreStrings: true,
18 | ignoreTemplateLiterals: true,
19 | ignoreUrls: true,
20 | },
21 | ],
22 | 'no-console': 0,
23 | 'no-param-reassign': 0,
24 | 'no-plusplus': 0,
25 | 'no-underscore-dangle': [2, {allow: ['_id']}],
26 | 'no-unused-vars': [0, { "argsIgnorePattern": "^_" }],
27 |
28 | 'object-curly-newline': 0,
29 | 'object-curly-spacing': 0,
30 | 'prefer-destructuring': [
31 | 2,
32 | {
33 | array: false,
34 | object: true,
35 | },
36 | {
37 | enforceForRenamedProperties: false,
38 | },
39 | ],
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/02_feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "💡 Feature Request"
3 | about: "Suggest an idea for this project"
4 | ---
5 | Type: Feature Request
6 |
7 | - [ ] If you want to contribute to the project please review the [contributing guidelines](https://github.com/Flood-UI/flood/blob/master/.github/CONTRIBUTING.md).
8 |
9 | ## Summary
10 |
11 |
12 |
13 | ## Idea of implementation
14 |
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/03_security_vulnerability.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "🔒 Security Vulnerability"
3 | about: "Report a security vulnerability in flood"
4 | ---
5 | PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
6 |
7 | If you discover a security vulnerability within flood, please send an e-mail to jfurrow (me@johnfurrow.com) or noraj (cybersecurity@tutamail.com).
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/04_documentation_issue.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "📚 Documentation Issue"
3 | about: 'Report an issue or missing part in the documentation'
4 | ---
5 | Type: Documentation Issue
6 |
7 | ## Summary
8 |
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/05_question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "❓ Question"
3 | about: "Ask your questions here"
4 | ---
5 | Type: Question
6 |
7 | ## Question
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/06_discussion.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "🎙️ Discussion"
3 | about: "Start a discussion here"
4 | ---
5 | Type: Discussion
6 |
7 | ## Discussion
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/07_support.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "🆘 Support"
3 | about: "Ask for help on Discord"
4 | ---
5 | If you need support, ask on Discord https://discord.gg/Z7yR5Uf
6 |
--------------------------------------------------------------------------------
/.github/labels/bsd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/bsd.png
--------------------------------------------------------------------------------
/.github/labels/bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/bug.png
--------------------------------------------------------------------------------
/.github/labels/can't reproduce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/can't reproduce.png
--------------------------------------------------------------------------------
/.github/labels/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/code.png
--------------------------------------------------------------------------------
/.github/labels/critical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/critical.png
--------------------------------------------------------------------------------
/.github/labels/design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/design.png
--------------------------------------------------------------------------------
/.github/labels/discussion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/discussion.png
--------------------------------------------------------------------------------
/.github/labels/docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/docker.png
--------------------------------------------------------------------------------
/.github/labels/documentation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/documentation.png
--------------------------------------------------------------------------------
/.github/labels/duplicate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/duplicate.png
--------------------------------------------------------------------------------
/.github/labels/enhancement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/enhancement.png
--------------------------------------------------------------------------------
/.github/labels/feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/feature.png
--------------------------------------------------------------------------------
/.github/labels/help wanted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/help wanted.png
--------------------------------------------------------------------------------
/.github/labels/in progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/in progress.png
--------------------------------------------------------------------------------
/.github/labels/invalid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/invalid.png
--------------------------------------------------------------------------------
/.github/labels/labels.md:
--------------------------------------------------------------------------------
1 | # Labels
2 |
3 | Category | Label(s) | Color(s)
4 | --- | --- | ---
5 | Platform |      | #BFD4F2
6 | Problems |   | #EE3F46
7 | Severity |  | #B60205
8 | Type |     | #FFC274
9 | Feedback |   | #CC317C
10 | Improvements |    | #5EBEFF
11 | Help |  | #76C3A9
12 | Additions |  | #90C954
13 | Pending |      | #FBCA04
14 | Inactive |      | #D2DAE1
15 |
16 | Note: in order to take a sharp screenshot of labels with Firefox: Right click the label => Inspect element => Right click the element on the inspector => Screenshot Node
17 |
--------------------------------------------------------------------------------
/.github/labels/linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/linux.png
--------------------------------------------------------------------------------
/.github/labels/macOS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/macOS.png
--------------------------------------------------------------------------------
/.github/labels/more info needed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/more info needed.png
--------------------------------------------------------------------------------
/.github/labels/not a bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/not a bug.png
--------------------------------------------------------------------------------
/.github/labels/on hold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/on hold.png
--------------------------------------------------------------------------------
/.github/labels/optimization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/optimization.png
--------------------------------------------------------------------------------
/.github/labels/performance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/performance.png
--------------------------------------------------------------------------------
/.github/labels/question.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/question.png
--------------------------------------------------------------------------------
/.github/labels/security.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/security.png
--------------------------------------------------------------------------------
/.github/labels/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/test.png
--------------------------------------------------------------------------------
/.github/labels/waiting feedback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/waiting feedback.png
--------------------------------------------------------------------------------
/.github/labels/watchlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/watchlist.png
--------------------------------------------------------------------------------
/.github/labels/windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/windows.png
--------------------------------------------------------------------------------
/.github/labels/wontfix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/.github/labels/wontfix.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Dependency directories
15 | node_modules/
16 |
17 | # Optional npm cache directory
18 | .npm
19 |
20 | # Optional eslint cache
21 | .eslintcache
22 |
23 | # Optional REPL history
24 | .node_repl_history
25 |
26 | # Output of 'npm pack'
27 | *.tgz
28 |
29 | # Yarn Integrity file
30 | .yarn-integrity
31 |
32 | # dotenv environment variables file
33 | .env
34 |
35 | # macOS custom attributes
36 | .DS_Store
37 |
38 | # VisualStudio
39 | .vscode
40 |
41 | # Intellij
42 | .idea
43 |
44 | # Personal flood config
45 | config.js
46 |
47 | # Flood server
48 | server/db
49 | server/assets
50 | server/temp
51 |
52 | # Vim temp files
53 | *.swp
54 |
55 | # JSDoc output
56 | docs/
57 | out/
58 |
--------------------------------------------------------------------------------
/.jsdoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "tags": {
3 | "allowUnknownTags": true,
4 | "dictionaries": ["jsdoc"]
5 | },
6 | "source": {
7 | "include": ["client", "server", "shared", "package.json", "README.md"],
8 | "includePattern": ".js$",
9 | "excludePattern": "(node_modules/|docs)"
10 | },
11 | "plugins": [
12 | "plugins/markdown"
13 | ],
14 | "templates": {
15 | "cleverLinks": false,
16 | "monospaceLinks": true,
17 | "useLongnameInNav": false,
18 | "showInheritedInNav": true
19 | },
20 | "opts": {
21 | "destination": "./docs/",
22 | "encoding": "utf8",
23 | "private": true,
24 | "recurse": true,
25 | "template": "./node_modules/minami"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": false,
3 | "jsxBracketSameLine": true,
4 | "printWidth": 120,
5 | "singleQuote": true,
6 | "trailingComma": "all"
7 | }
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | language: node_js
3 | node_js:
4 | - '10'
5 | - '12'
6 | - '13'
7 | matrix:
8 | fast_finish: true
9 | allow_failures:
10 | - node_js: 10
11 | before_script:
12 | - cp config.template.js config.js
13 | script:
14 | - npm run check-source-formatting
15 | - npm run lint
16 | - npm run check-types
17 | - npm run test
18 | - npm run build
19 |
--------------------------------------------------------------------------------
/ABOUT.md:
--------------------------------------------------------------------------------
1 | # Flood
2 |
3 | [](https://travis-ci.org/Flood-UI/flood) [](https://discord.gg/Z7yR5Uf)
4 |
5 | Flood is a monitoring service for [rTorrent](https://github.com/rakshasa/rtorrent). It's a Node.js service that communicates with rTorrent instances and serves a decent web UI for administration. It's a work-in-progress.
6 |
7 | #### Feedback
8 |
9 | If you have a specific issue or bug, please file a GitHub issue. Please join the [Flood Discord server](https://discord.gg/Z7yR5Uf) to discuss feature requests and implementation details.
10 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG NODE_IMAGE=node:12.2-alpine
2 | ARG WORKDIR=/usr/src/app/
3 |
4 | FROM ${NODE_IMAGE} as nodebuild
5 | ARG WORKDIR
6 |
7 | WORKDIR $WORKDIR
8 |
9 | # Generate node_modules
10 | COPY package.json \
11 | package-lock.json \
12 | .babelrc \
13 | .eslintrc.js \
14 | .eslintignore \
15 | .prettierrc \
16 | ABOUT.md \
17 | $WORKDIR
18 | RUN apk add --no-cache --virtual=build-dependencies \
19 | python build-base && \
20 | npm install && \
21 | apk del --purge build-dependencies
22 |
23 | # Build static assets and remove devDependencies.
24 | COPY client ./client
25 | COPY server ./server
26 | COPY shared ./shared
27 | COPY scripts ./scripts
28 | COPY config.docker.js ./config.js
29 | RUN npm run build && \
30 | npm prune --production
31 |
32 | # Now get the clean image without any dependencies and copy compiled app
33 | FROM ${NODE_IMAGE} as flood
34 | ARG WORKDIR
35 |
36 | WORKDIR $WORKDIR
37 |
38 | # Install runtime dependencies.
39 | RUN apk --no-cache add \
40 | mediainfo
41 |
42 | COPY --from=nodebuild $WORKDIR $WORKDIR
43 |
44 | # Hints for consumers of the container.
45 | EXPOSE 3000
46 | VOLUME ["/data"]
47 |
48 | # Start application.
49 | CMD [ "npm", "start" ]
50 |
--------------------------------------------------------------------------------
/client/config/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: 0,
4 | node: 1,
5 | },
6 | rules: {
7 | 'no-console': 0,
8 | 'global-require': 0,
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/client/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | // This is a custom Jest transformer turning style imports into empty objects.
2 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
3 |
4 | module.exports = {
5 | process() {
6 | return 'module.exports = {};';
7 | },
8 | getCacheKey() {
9 | // The output is always the same.
10 | return 'cssTransform';
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/client/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // This is a custom Jest transformer turning file imports into filenames.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process(src, filename) {
8 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/client/config/paths.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const userConfig = require('../../config');
4 |
5 | // Make sure any symlinks in the project folder are resolved:
6 | // https://github.com/facebookincubator/create-react-app/issues/637
7 | const appDirectory = fs.realpathSync(process.cwd());
8 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
9 | const ensureSlash = (questionablePath, needsSlash) => {
10 | const hasSlash = questionablePath.endsWith('/');
11 | if (hasSlash && !needsSlash) {
12 | return questionablePath.substr(questionablePath, questionablePath.length - 1);
13 | }
14 | if (!hasSlash && needsSlash) {
15 | return `${questionablePath}/`;
16 | }
17 | return questionablePath;
18 | };
19 |
20 | module.exports = {
21 | appBuild: resolveApp('server/assets'),
22 | appPublic: resolveApp('client/src/public/'),
23 | appHtml: resolveApp('client/src/index.html'),
24 | appIndex: resolveApp('client/src/javascript/app.tsx'),
25 | appPackageJson: resolveApp('package.json'),
26 | appSrc: resolveApp('./'),
27 | clientSrc: resolveApp('client/src'),
28 | testsSetup: resolveApp('tests/setupTests.js'),
29 | appNodeModules: resolveApp('node_modules'),
30 | servedPath: ensureSlash(userConfig.baseURI || '/', true),
31 | };
32 |
--------------------------------------------------------------------------------
/client/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // Object.assign() is commonly used with React.
10 | // It will use the native implementation if it's present and isn't buggy.
11 | Object.assign = require('object-assign');
12 |
--------------------------------------------------------------------------------
/client/scripts/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: 0,
4 | node: 1,
5 | },
6 | rules: {
7 | 'no-console': 0,
8 | 'global-require': 0,
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/client/scripts/test.js:
--------------------------------------------------------------------------------
1 | console.log('There are no tests yet.');
2 | process.exit(0);
3 |
4 | // Do this as the first thing so that any code reading it knows the right env.
5 | process.env.BABEL_ENV = 'test';
6 | process.env.NODE_ENV = 'test';
7 | process.env.BASE_URI = '';
8 |
9 | // Makes the script crash on unhandled rejections instead of silently
10 | // ignoring them. In the future, promise rejections that are not handled will
11 | // terminate the Node.js process with a non-zero exit code.
12 | process.on('unhandledRejection', err => {
13 | throw err;
14 | });
15 |
16 | // Ensure environment variables are read.
17 | require('../config/env');
18 |
19 | const jest = require('jest');
20 |
21 | const argv = process.argv.slice(2);
22 |
23 | // Watch unless on CI or in coverage mode
24 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
25 | argv.push('--watch');
26 | }
27 |
28 | jest.run(argv);
29 |
--------------------------------------------------------------------------------
/client/scripts/typed-css-modules-loader.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const DtsCreator = require('typed-css-modules');
3 | const prettier = require('../../scripts/prettier');
4 |
5 | const creator = new DtsCreator();
6 |
7 | module.exports = async function moduleLoader(source, map) {
8 | if (this.cacheable) {
9 | this.cacheable();
10 | }
11 |
12 | try {
13 | const callback = this.async();
14 | const dtsContent = await creator.create(this.resourcePath, source);
15 |
16 | await dtsContent.writeFile();
17 | await prettier.formatFile(dtsContent.outputFilePath, dtsContent.outputFilePath);
18 |
19 | return callback(null, source, map);
20 | } catch (error) {
21 | console.log(chalk.red(chalk.red('CSS module type generation failed.')));
22 | console.log(error.message);
23 |
24 | if (error.stack != null) {
25 | console.log(chalk.gray(error.stack));
26 | }
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-500/Roboto-500.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-500/Roboto-500.eot
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-500/Roboto-500.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-500/Roboto-500.ttf
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-500/Roboto-500.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-500/Roboto-500.woff
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-500/Roboto-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-500/Roboto-500.woff2
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700/Roboto-700.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700/Roboto-700.eot
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700/Roboto-700.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700/Roboto-700.ttf
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700/Roboto-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700/Roboto-700.woff
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700/Roboto-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700/Roboto-700.woff2
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700italic/Roboto-700italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700italic/Roboto-700italic.eot
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700italic/Roboto-700italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700italic/Roboto-700italic.ttf
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700italic/Roboto-700italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700italic/Roboto-700italic.woff
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-700italic/Roboto-700italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-700italic/Roboto-700italic.woff2
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-italic/Roboto-italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-italic/Roboto-italic.eot
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-italic/Roboto-italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-italic/Roboto-italic.ttf
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-italic/Roboto-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-italic/Roboto-italic.woff
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-italic/Roboto-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-italic/Roboto-italic.woff2
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-regular/Roboto-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-regular/Roboto-regular.eot
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-regular/Roboto-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-regular/Roboto-regular.ttf
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-regular/Roboto-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-regular/Roboto-regular.woff
--------------------------------------------------------------------------------
/client/src/fonts/Roboto-regular/Roboto-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/fonts/Roboto-regular/Roboto-regular.woff2
--------------------------------------------------------------------------------
/client/src/images/flags/ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ad.png
--------------------------------------------------------------------------------
/client/src/images/flags/ae.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ae.png
--------------------------------------------------------------------------------
/client/src/images/flags/af.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/af.png
--------------------------------------------------------------------------------
/client/src/images/flags/ag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ag.png
--------------------------------------------------------------------------------
/client/src/images/flags/al.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/al.png
--------------------------------------------------------------------------------
/client/src/images/flags/am.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/am.png
--------------------------------------------------------------------------------
/client/src/images/flags/ao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ao.png
--------------------------------------------------------------------------------
/client/src/images/flags/ar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ar.png
--------------------------------------------------------------------------------
/client/src/images/flags/at.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/at.png
--------------------------------------------------------------------------------
/client/src/images/flags/au.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/au.png
--------------------------------------------------------------------------------
/client/src/images/flags/az.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/az.png
--------------------------------------------------------------------------------
/client/src/images/flags/ba.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ba.png
--------------------------------------------------------------------------------
/client/src/images/flags/bb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bb.png
--------------------------------------------------------------------------------
/client/src/images/flags/bd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bd.png
--------------------------------------------------------------------------------
/client/src/images/flags/be.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/be.png
--------------------------------------------------------------------------------
/client/src/images/flags/bf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bf.png
--------------------------------------------------------------------------------
/client/src/images/flags/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bg.png
--------------------------------------------------------------------------------
/client/src/images/flags/bh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bh.png
--------------------------------------------------------------------------------
/client/src/images/flags/bi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bi.png
--------------------------------------------------------------------------------
/client/src/images/flags/bj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bj.png
--------------------------------------------------------------------------------
/client/src/images/flags/bn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bn.png
--------------------------------------------------------------------------------
/client/src/images/flags/bo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bo.png
--------------------------------------------------------------------------------
/client/src/images/flags/br.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/br.png
--------------------------------------------------------------------------------
/client/src/images/flags/bs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bs.png
--------------------------------------------------------------------------------
/client/src/images/flags/bt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bt.png
--------------------------------------------------------------------------------
/client/src/images/flags/bw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bw.png
--------------------------------------------------------------------------------
/client/src/images/flags/by.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/by.png
--------------------------------------------------------------------------------
/client/src/images/flags/bz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/bz.png
--------------------------------------------------------------------------------
/client/src/images/flags/ca.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ca.png
--------------------------------------------------------------------------------
/client/src/images/flags/cd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cd.png
--------------------------------------------------------------------------------
/client/src/images/flags/cf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cf.png
--------------------------------------------------------------------------------
/client/src/images/flags/cg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cg.png
--------------------------------------------------------------------------------
/client/src/images/flags/ch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ch.png
--------------------------------------------------------------------------------
/client/src/images/flags/ci.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ci.png
--------------------------------------------------------------------------------
/client/src/images/flags/cl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cl.png
--------------------------------------------------------------------------------
/client/src/images/flags/cm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cm.png
--------------------------------------------------------------------------------
/client/src/images/flags/cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cn.png
--------------------------------------------------------------------------------
/client/src/images/flags/co.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/co.png
--------------------------------------------------------------------------------
/client/src/images/flags/cr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cr.png
--------------------------------------------------------------------------------
/client/src/images/flags/cu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cu.png
--------------------------------------------------------------------------------
/client/src/images/flags/cv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cv.png
--------------------------------------------------------------------------------
/client/src/images/flags/cw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cw.png
--------------------------------------------------------------------------------
/client/src/images/flags/cy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cy.png
--------------------------------------------------------------------------------
/client/src/images/flags/cz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/cz.png
--------------------------------------------------------------------------------
/client/src/images/flags/de.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/de.png
--------------------------------------------------------------------------------
/client/src/images/flags/dj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/dj.png
--------------------------------------------------------------------------------
/client/src/images/flags/dk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/dk.png
--------------------------------------------------------------------------------
/client/src/images/flags/dm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/dm.png
--------------------------------------------------------------------------------
/client/src/images/flags/do.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/do.png
--------------------------------------------------------------------------------
/client/src/images/flags/dz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/dz.png
--------------------------------------------------------------------------------
/client/src/images/flags/ec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ec.png
--------------------------------------------------------------------------------
/client/src/images/flags/ee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ee.png
--------------------------------------------------------------------------------
/client/src/images/flags/eg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/eg.png
--------------------------------------------------------------------------------
/client/src/images/flags/eh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/eh.png
--------------------------------------------------------------------------------
/client/src/images/flags/er.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/er.png
--------------------------------------------------------------------------------
/client/src/images/flags/es.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/es.png
--------------------------------------------------------------------------------
/client/src/images/flags/et.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/et.png
--------------------------------------------------------------------------------
/client/src/images/flags/fi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/fi.png
--------------------------------------------------------------------------------
/client/src/images/flags/fj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/fj.png
--------------------------------------------------------------------------------
/client/src/images/flags/fm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/fm.png
--------------------------------------------------------------------------------
/client/src/images/flags/fr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/fr.png
--------------------------------------------------------------------------------
/client/src/images/flags/ga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ga.png
--------------------------------------------------------------------------------
/client/src/images/flags/gb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gb.png
--------------------------------------------------------------------------------
/client/src/images/flags/gd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gd.png
--------------------------------------------------------------------------------
/client/src/images/flags/ge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ge.png
--------------------------------------------------------------------------------
/client/src/images/flags/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gh.png
--------------------------------------------------------------------------------
/client/src/images/flags/gm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gm.png
--------------------------------------------------------------------------------
/client/src/images/flags/gn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gn.png
--------------------------------------------------------------------------------
/client/src/images/flags/gq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gq.png
--------------------------------------------------------------------------------
/client/src/images/flags/gr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gr.png
--------------------------------------------------------------------------------
/client/src/images/flags/gt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gt.png
--------------------------------------------------------------------------------
/client/src/images/flags/gw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gw.png
--------------------------------------------------------------------------------
/client/src/images/flags/gy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/gy.png
--------------------------------------------------------------------------------
/client/src/images/flags/hk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/hk.png
--------------------------------------------------------------------------------
/client/src/images/flags/hn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/hn.png
--------------------------------------------------------------------------------
/client/src/images/flags/hr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/hr.png
--------------------------------------------------------------------------------
/client/src/images/flags/ht.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ht.png
--------------------------------------------------------------------------------
/client/src/images/flags/hu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/hu.png
--------------------------------------------------------------------------------
/client/src/images/flags/id.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/id.png
--------------------------------------------------------------------------------
/client/src/images/flags/ie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ie.png
--------------------------------------------------------------------------------
/client/src/images/flags/il.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/il.png
--------------------------------------------------------------------------------
/client/src/images/flags/in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/in.png
--------------------------------------------------------------------------------
/client/src/images/flags/iq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/iq.png
--------------------------------------------------------------------------------
/client/src/images/flags/ir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ir.png
--------------------------------------------------------------------------------
/client/src/images/flags/is.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/is.png
--------------------------------------------------------------------------------
/client/src/images/flags/it.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/it.png
--------------------------------------------------------------------------------
/client/src/images/flags/je.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/je.png
--------------------------------------------------------------------------------
/client/src/images/flags/jm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/jm.png
--------------------------------------------------------------------------------
/client/src/images/flags/jo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/jo.png
--------------------------------------------------------------------------------
/client/src/images/flags/jp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/jp.png
--------------------------------------------------------------------------------
/client/src/images/flags/ke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ke.png
--------------------------------------------------------------------------------
/client/src/images/flags/kg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kg.png
--------------------------------------------------------------------------------
/client/src/images/flags/kh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kh.png
--------------------------------------------------------------------------------
/client/src/images/flags/ki.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ki.png
--------------------------------------------------------------------------------
/client/src/images/flags/km.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/km.png
--------------------------------------------------------------------------------
/client/src/images/flags/kn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kn.png
--------------------------------------------------------------------------------
/client/src/images/flags/kp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kp.png
--------------------------------------------------------------------------------
/client/src/images/flags/kr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kr.png
--------------------------------------------------------------------------------
/client/src/images/flags/ks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ks.png
--------------------------------------------------------------------------------
/client/src/images/flags/kw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kw.png
--------------------------------------------------------------------------------
/client/src/images/flags/kz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/kz.png
--------------------------------------------------------------------------------
/client/src/images/flags/la.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/la.png
--------------------------------------------------------------------------------
/client/src/images/flags/lb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lb.png
--------------------------------------------------------------------------------
/client/src/images/flags/lc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lc.png
--------------------------------------------------------------------------------
/client/src/images/flags/li.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/li.png
--------------------------------------------------------------------------------
/client/src/images/flags/lk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lk.png
--------------------------------------------------------------------------------
/client/src/images/flags/lr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lr.png
--------------------------------------------------------------------------------
/client/src/images/flags/ls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ls.png
--------------------------------------------------------------------------------
/client/src/images/flags/lt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lt.png
--------------------------------------------------------------------------------
/client/src/images/flags/lu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lu.png
--------------------------------------------------------------------------------
/client/src/images/flags/lv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/lv.png
--------------------------------------------------------------------------------
/client/src/images/flags/ly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ly.png
--------------------------------------------------------------------------------
/client/src/images/flags/ma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ma.png
--------------------------------------------------------------------------------
/client/src/images/flags/mc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mc.png
--------------------------------------------------------------------------------
/client/src/images/flags/md.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/md.png
--------------------------------------------------------------------------------
/client/src/images/flags/me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/me.png
--------------------------------------------------------------------------------
/client/src/images/flags/mg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mg.png
--------------------------------------------------------------------------------
/client/src/images/flags/mh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mh.png
--------------------------------------------------------------------------------
/client/src/images/flags/mk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mk.png
--------------------------------------------------------------------------------
/client/src/images/flags/ml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ml.png
--------------------------------------------------------------------------------
/client/src/images/flags/mm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mm.png
--------------------------------------------------------------------------------
/client/src/images/flags/mn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mn.png
--------------------------------------------------------------------------------
/client/src/images/flags/mr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mr.png
--------------------------------------------------------------------------------
/client/src/images/flags/mt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mt.png
--------------------------------------------------------------------------------
/client/src/images/flags/mu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mu.png
--------------------------------------------------------------------------------
/client/src/images/flags/mv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mv.png
--------------------------------------------------------------------------------
/client/src/images/flags/mw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mw.png
--------------------------------------------------------------------------------
/client/src/images/flags/mx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mx.png
--------------------------------------------------------------------------------
/client/src/images/flags/my.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/my.png
--------------------------------------------------------------------------------
/client/src/images/flags/mz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/mz.png
--------------------------------------------------------------------------------
/client/src/images/flags/na.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/na.png
--------------------------------------------------------------------------------
/client/src/images/flags/ne.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ne.png
--------------------------------------------------------------------------------
/client/src/images/flags/ng.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ng.png
--------------------------------------------------------------------------------
/client/src/images/flags/ni.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ni.png
--------------------------------------------------------------------------------
/client/src/images/flags/nl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/nl.png
--------------------------------------------------------------------------------
/client/src/images/flags/no.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/no.png
--------------------------------------------------------------------------------
/client/src/images/flags/np.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/np.png
--------------------------------------------------------------------------------
/client/src/images/flags/nr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/nr.png
--------------------------------------------------------------------------------
/client/src/images/flags/nz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/nz.png
--------------------------------------------------------------------------------
/client/src/images/flags/om.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/om.png
--------------------------------------------------------------------------------
/client/src/images/flags/pa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pa.png
--------------------------------------------------------------------------------
/client/src/images/flags/pe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pe.png
--------------------------------------------------------------------------------
/client/src/images/flags/pg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pg.png
--------------------------------------------------------------------------------
/client/src/images/flags/ph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ph.png
--------------------------------------------------------------------------------
/client/src/images/flags/pk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pk.png
--------------------------------------------------------------------------------
/client/src/images/flags/pl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pl.png
--------------------------------------------------------------------------------
/client/src/images/flags/pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pt.png
--------------------------------------------------------------------------------
/client/src/images/flags/pw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/pw.png
--------------------------------------------------------------------------------
/client/src/images/flags/py.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/py.png
--------------------------------------------------------------------------------
/client/src/images/flags/qa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/qa.png
--------------------------------------------------------------------------------
/client/src/images/flags/ro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ro.png
--------------------------------------------------------------------------------
/client/src/images/flags/rs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/rs.png
--------------------------------------------------------------------------------
/client/src/images/flags/ru.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ru.png
--------------------------------------------------------------------------------
/client/src/images/flags/rw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/rw.png
--------------------------------------------------------------------------------
/client/src/images/flags/sa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sa.png
--------------------------------------------------------------------------------
/client/src/images/flags/sb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sb.png
--------------------------------------------------------------------------------
/client/src/images/flags/sc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sc.png
--------------------------------------------------------------------------------
/client/src/images/flags/sd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sd.png
--------------------------------------------------------------------------------
/client/src/images/flags/se.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/se.png
--------------------------------------------------------------------------------
/client/src/images/flags/sg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sg.png
--------------------------------------------------------------------------------
/client/src/images/flags/si.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/si.png
--------------------------------------------------------------------------------
/client/src/images/flags/sk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sk.png
--------------------------------------------------------------------------------
/client/src/images/flags/sl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sl.png
--------------------------------------------------------------------------------
/client/src/images/flags/sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sm.png
--------------------------------------------------------------------------------
/client/src/images/flags/sn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sn.png
--------------------------------------------------------------------------------
/client/src/images/flags/so.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/so.png
--------------------------------------------------------------------------------
/client/src/images/flags/sr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sr.png
--------------------------------------------------------------------------------
/client/src/images/flags/st.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/st.png
--------------------------------------------------------------------------------
/client/src/images/flags/sv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sv.png
--------------------------------------------------------------------------------
/client/src/images/flags/sy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sy.png
--------------------------------------------------------------------------------
/client/src/images/flags/sz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/sz.png
--------------------------------------------------------------------------------
/client/src/images/flags/td.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/td.png
--------------------------------------------------------------------------------
/client/src/images/flags/tg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tg.png
--------------------------------------------------------------------------------
/client/src/images/flags/th.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/th.png
--------------------------------------------------------------------------------
/client/src/images/flags/tj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tj.png
--------------------------------------------------------------------------------
/client/src/images/flags/tl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tl.png
--------------------------------------------------------------------------------
/client/src/images/flags/tm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tm.png
--------------------------------------------------------------------------------
/client/src/images/flags/tn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tn.png
--------------------------------------------------------------------------------
/client/src/images/flags/to.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/to.png
--------------------------------------------------------------------------------
/client/src/images/flags/tr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tr.png
--------------------------------------------------------------------------------
/client/src/images/flags/tt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tt.png
--------------------------------------------------------------------------------
/client/src/images/flags/tv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tv.png
--------------------------------------------------------------------------------
/client/src/images/flags/tw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tw.png
--------------------------------------------------------------------------------
/client/src/images/flags/tz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/tz.png
--------------------------------------------------------------------------------
/client/src/images/flags/ua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ua.png
--------------------------------------------------------------------------------
/client/src/images/flags/ug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ug.png
--------------------------------------------------------------------------------
/client/src/images/flags/us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/us.png
--------------------------------------------------------------------------------
/client/src/images/flags/uy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/uy.png
--------------------------------------------------------------------------------
/client/src/images/flags/uz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/uz.png
--------------------------------------------------------------------------------
/client/src/images/flags/va.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/va.png
--------------------------------------------------------------------------------
/client/src/images/flags/vc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/vc.png
--------------------------------------------------------------------------------
/client/src/images/flags/ve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ve.png
--------------------------------------------------------------------------------
/client/src/images/flags/vn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/vn.png
--------------------------------------------------------------------------------
/client/src/images/flags/vu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/vu.png
--------------------------------------------------------------------------------
/client/src/images/flags/ws.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ws.png
--------------------------------------------------------------------------------
/client/src/images/flags/ye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/ye.png
--------------------------------------------------------------------------------
/client/src/images/flags/za.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/za.png
--------------------------------------------------------------------------------
/client/src/images/flags/zm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/zm.png
--------------------------------------------------------------------------------
/client/src/images/flags/zw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/images/flags/zw.png
--------------------------------------------------------------------------------
/client/src/images/flood.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/client/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Flood
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/client/src/javascript/components/alerts/Alert.js:
--------------------------------------------------------------------------------
1 | import {FormattedMessage} from 'react-intl';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 | import React from 'react';
5 |
6 | import Alerts from '../../constants/Alerts';
7 | import CircleCheckmarkIcon from '../icons/CircleCheckmarkIcon';
8 | import CircleExclamationIcon from '../icons/CircleExclamationIcon';
9 |
10 | export default class Alert extends React.Component {
11 | static propTypes = {
12 | count: PropTypes.number,
13 | id: PropTypes.string,
14 | };
15 |
16 | static defaultProps = {
17 | count: 0,
18 | type: 'success',
19 | };
20 |
21 | render() {
22 | let icon = ;
23 | const alertClasses = classnames('alert', {
24 | 'is-success': this.props.type === 'success',
25 | 'is-error': this.props.type === 'error',
26 | });
27 |
28 | if (this.props.type === 'error') {
29 | icon = ;
30 | }
31 |
32 | return (
33 |
34 | {icon}
35 |
36 | {this.props.count},
42 | }}
43 | />
44 |
45 |
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/src/javascript/components/alerts/Alerts.js:
--------------------------------------------------------------------------------
1 | import {CSSTransition, TransitionGroup} from 'react-transition-group';
2 | import React from 'react';
3 |
4 | import Alert from './Alert';
5 | import AlertStore from '../../stores/AlertStore';
6 | import connectStores from '../../util/connectStores';
7 | import EventTypes from '../../constants/EventTypes';
8 |
9 | class Alerts extends React.Component {
10 | renderAlerts() {
11 | const {alerts} = this.props;
12 |
13 | if (alerts.length > 0) {
14 | return (
15 |
16 |
17 | {this.props.alerts.map(alert => (
18 |
19 | ))}
20 |
21 |
22 | );
23 | }
24 |
25 | return null;
26 | }
27 |
28 | render() {
29 | return {this.renderAlerts()};
30 | }
31 | }
32 |
33 | const ConnectedAlerts = connectStores(Alerts, () => {
34 | return [
35 | {
36 | store: AlertStore,
37 | event: EventTypes.ALERTS_CHANGE,
38 | getValue: ({store}) => {
39 | return {
40 | alerts: store.getAlerts(),
41 | };
42 | },
43 | },
44 | ];
45 | });
46 |
47 | export default ConnectedAlerts;
48 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Badge.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Badge extends React.Component {
4 | render() {
5 | return {this.props.children}
;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Icon.scss:
--------------------------------------------------------------------------------
1 | .icon {
2 | display: block;
3 | }
4 |
5 | .sizeSmall {
6 | height: 12px;
7 | width: 12px;
8 | }
9 |
10 | .sizeMedium {
11 | height: 16px;
12 | width: 16px;
13 | }
14 |
15 | .fillCurrentColor {
16 | fill: currentColor;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Icon.scss.d.ts:
--------------------------------------------------------------------------------
1 | declare const styles: {
2 | readonly icon: string;
3 | readonly sizeSmall: string;
4 | readonly sizeMedium: string;
5 | readonly fillCurrentColor: string;
6 | };
7 | export = styles;
8 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Icon.tsx:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import * as React from 'react';
3 | import * as styles from './Icon.scss';
4 |
5 | enum Fills {
6 | NONE,
7 | CURRENT_COLOR,
8 | }
9 |
10 | enum Sizes {
11 | SMALL,
12 | MEDIUM,
13 | }
14 |
15 | interface Props {
16 | className?: string;
17 | fill: Fills;
18 | glyph: string;
19 | size: Sizes;
20 | }
21 |
22 | export default class Icon extends React.PureComponent {
23 | public static defaultProps = {
24 | fill: Fills.CURRENT_COLOR,
25 | size: Sizes.MEDIUM,
26 | };
27 |
28 | public static Fills = Fills;
29 |
30 | public static Sizes = Sizes;
31 |
32 | public render(): React.ReactNode {
33 | const {className, fill, glyph, size, ...restProps} = this.props;
34 |
35 | return (
36 |
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/LoadingIndicator.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import React from 'react';
3 |
4 | export default class LoadingIndicator extends React.Component {
5 | render() {
6 | const classes = classnames('loading-indicator', {
7 | 'is-inverse': this.props.inverse,
8 | });
9 |
10 | return (
11 |
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Portal.js:
--------------------------------------------------------------------------------
1 | import {IntlProvider} from 'react-intl';
2 | import PropTypes from 'prop-types';
3 | import React from 'react';
4 | import ReactDOM from 'react-dom';
5 |
6 | import * as i18n from '../../i18n/languages';
7 | import SettingsStore from '../../stores/SettingsStore';
8 |
9 | class Portal extends React.Component {
10 | static propTypes = {
11 | children: PropTypes.node,
12 | };
13 |
14 | static defaultProps = {
15 | children: ,
16 | };
17 |
18 | componentDidMount() {
19 | this.nodeEl = document.createElement('div');
20 | document.body.appendChild(this.nodeEl);
21 | }
22 |
23 | componentWillUnmount() {
24 | ReactDOM.unmountComponentAtNode(this.nodeEl);
25 | document.body.removeChild(this.nodeEl);
26 | }
27 |
28 | render() {
29 | const locale = SettingsStore.getFloodSettings('language');
30 | if (this.nodeEl == null) return null;
31 | return ReactDOM.createPortal(
32 | // eslint-disable-next-line import/namespace
33 |
34 | {this.props.children}
35 | ,
36 | this.nodeEl,
37 | );
38 | }
39 | }
40 |
41 | export default Portal;
42 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/ProgressBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ProgressBar extends React.PureComponent {
4 | render() {
5 | const percent = Math.round(this.props.percent);
6 | const style = {};
7 |
8 | if (percent !== 100) {
9 | style.width = `${percent}%`;
10 | }
11 |
12 | return (
13 |
14 |
{this.props.icon}
15 |
18 |
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Ratio.js:
--------------------------------------------------------------------------------
1 | import {FormattedNumber} from 'react-intl';
2 | import React from 'react';
3 |
4 | export default class Ratio extends React.Component {
5 | render() {
6 | let ratio = this.props.value;
7 |
8 | ratio /= 1000;
9 | let precision = 1;
10 |
11 | if (ratio < 10) {
12 | precision = 2;
13 | } else if (ratio >= 100) {
14 | precision = 0;
15 | }
16 |
17 | ratio = ratio.toFixed(precision);
18 |
19 | return ;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/javascript/components/general/Size.js:
--------------------------------------------------------------------------------
1 | import {FormattedNumber, injectIntl} from 'react-intl';
2 | import React from 'react';
3 |
4 | import {compute, getTranslationString} from '../../util/size';
5 |
6 | class Size extends React.Component {
7 | renderNumber(computedNumber) {
8 | if (Number.isNaN(computedNumber.value)) {
9 | return '—';
10 | }
11 |
12 | return ;
13 | }
14 |
15 | render() {
16 | const {value, isSpeed, className, precision, intl} = this.props;
17 | const computed = compute(value, precision);
18 |
19 | let translatedUnit = intl.formatMessage({id: getTranslationString(computed.unit)});
20 |
21 | if (isSpeed) {
22 | translatedUnit = intl.formatMessage(
23 | {
24 | id: 'unit.speed',
25 | defaultMessage: '{baseUnit}/s',
26 | },
27 | {
28 | baseUnit: translatedUnit,
29 | },
30 | );
31 | }
32 |
33 | return (
34 |
35 | {this.renderNumber(computed)}
36 | {translatedUnit}
37 |
38 | );
39 | }
40 | }
41 |
42 | Size.defaultProps = {
43 | isSpeed: false,
44 | precision: 2,
45 | };
46 |
47 | export default injectIntl(Size);
48 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Active.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Active extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Add.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class AddMini extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/AddMini.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class AddMini extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/All.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class All extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ArrowIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class ArrowIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/BaseIcon.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default class BaseIcon extends React.Component {
5 | static propTypes = {
6 | size: PropTypes.string,
7 | viewBox: PropTypes.string,
8 | };
9 |
10 | static defaultProps = {
11 | className: '',
12 | viewBox: '0 0 60 60',
13 | };
14 |
15 | getViewBox() {
16 | let {viewBox} = this.props;
17 |
18 | if (this.props.size && this.props.size === 'mini') {
19 | viewBox = '0 0 8 8';
20 | }
21 |
22 | return viewBox;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/CalendarCreatedIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class CalendarCreatedIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/CalendarIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class CalendarIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Checkmark.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Checkmark extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ChevronLeftIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class ChevronLeftIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ChevronRightIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class ChevronRightIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/CircleCheckmarkIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class CircleCheckmarkIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/CircleExclamationIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class CircleExclamationIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/CircleIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Circle extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ClipboardIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class ClipboardIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ClockIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class ClockIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Close.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Close extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/CommentIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class CommentIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Completed.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Completed extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/DetailNotAvailableIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class DetailNotAvailableIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Disk.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Disk extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/DiskIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class DiskIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/DotsMini.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class DotsMini extends BaseIcon {
6 | render() {
7 | return (
8 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Download.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Download extends BaseIcon {
6 | render() {
7 | return (
8 |
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/DownloadSmall.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class DownloadSmall extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/DownloadThickIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class DownloadThickIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ETA.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class ETA extends BaseIcon {
6 | render() {
7 | return (
8 |
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Edit.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Edit extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/ErrorIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Error extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/FeedIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class FeedIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/File.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class File extends BaseIcon {
6 | render() {
7 | return (
8 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Files.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Files extends BaseIcon {
6 | render() {
7 | return (
8 |
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/FolderClosedOutlined.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class FolderClosedOutline extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/FolderClosedSolid.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class FolderClosedOutline extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/FolderOpenOutlined.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class FolderOpenOutlined extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/FolderOpenSolid.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class FolderOpenSolid extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/HashIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class HashIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Inactive.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Inactive extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/InfinityIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class InfinityIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/InformationIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class InformationIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/LoadingIndicatorDots.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class LoadingIndicatorDots extends BaseIcon {
6 | render() {
7 | return (
8 |
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/LockIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class LockIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Logout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Logout extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/NotificationIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class NotificationIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/PeersIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class PeersIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/RadarIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class RadarIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/RadioDot.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class RadioDot extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Ratio.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Ratio extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/RatioIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class RatioIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Remove.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class AddMini extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/RemoveMini.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class RemoveMini extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Search.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Search extends BaseIcon {
6 | render() {
7 | return (
8 |
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/SeedsIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class SeedsIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/StartIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Start extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/StopIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Stop extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/TrackerMessageIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class TrackerMessageIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/Upload.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class Upload extends BaseIcon {
6 | render() {
7 | return (
8 |
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/javascript/components/icons/UploadThickIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BaseIcon from './BaseIcon';
4 |
5 | export default class UploadThickIcon extends BaseIcon {
6 | render() {
7 | return (
8 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/javascript/components/layout/ApplicationContent.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | class ApplicationContent extends React.Component {
5 | static propTypes = {
6 | children: PropTypes.node,
7 | };
8 |
9 | render() {
10 | return {this.props.children}
;
11 | }
12 | }
13 |
14 | export default ApplicationContent;
15 |
--------------------------------------------------------------------------------
/client/src/javascript/components/layout/ApplicationPanel.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import PropTypes from 'prop-types';
3 | import React from 'react';
4 |
5 | class ApplicationContent extends React.Component {
6 | static propTypes = {
7 | children: PropTypes.node,
8 | className: PropTypes.string,
9 | modifier: PropTypes.string,
10 | };
11 |
12 | static defaultProps = {
13 | baseClassName: 'application__panel',
14 | };
15 |
16 | render() {
17 | const classes = classnames(this.props.baseClassName, {
18 | [`${this.props.baseClassName}--${this.props.modifier}`]: this.props.baseClassName,
19 | [this.props.className]: this.props.className,
20 | });
21 |
22 | return {this.props.children}
;
23 | }
24 | }
25 |
26 | export default ApplicationContent;
27 |
--------------------------------------------------------------------------------
/client/src/javascript/components/layout/ApplicationView.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import PropTypes from 'prop-types';
3 | import React from 'react';
4 |
5 | class ApplicationView extends React.Component {
6 | static propTypes = {
7 | children: PropTypes.node,
8 | modifier: PropTypes.string,
9 | };
10 |
11 | render() {
12 | const classes = classnames('application__view', {
13 | [`application__view--${this.props.modifier}`]: this.props.modifier != null,
14 | });
15 |
16 | return {this.props.children}
;
17 | }
18 | }
19 |
20 | export default ApplicationView;
21 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/ModalFormSectionHeader.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class ModalFormSectionHeader extends React.PureComponent {
4 | render() {
5 | return {this.props.children}
;
6 | }
7 | }
8 |
9 | export default ModalFormSectionHeader;
10 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/ModalTabs.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import React from 'react';
3 |
4 | export default class ModalTabs extends React.Component {
5 | handleTabClick(tab) {
6 | if (this.props.onTabChange) {
7 | this.props.onTabChange(tab);
8 | }
9 | }
10 |
11 | render() {
12 | const tabs = Object.keys(this.props.tabs).map(tabId => {
13 | const currentTab = this.props.tabs[tabId];
14 |
15 | currentTab.id = tabId;
16 |
17 | const classes = classnames('modal__tab', {
18 | 'is-active': tabId === this.props.activeTabId,
19 | });
20 |
21 | return (
22 |
23 | {currentTab.label}
24 |
25 | );
26 | });
27 | return ;
28 | }
29 | }
30 |
31 | ModalTabs.defaultProps = {
32 | tabs: [],
33 | };
34 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/add-torrents-modal/AddTorrentsModal.js:
--------------------------------------------------------------------------------
1 | import {injectIntl} from 'react-intl';
2 | import React from 'react';
3 |
4 | import AddTorrentsByFile from './AddTorrentsByFile';
5 | import AddTorrentsByURL from './AddTorrentsByURL';
6 | import Modal from '../Modal';
7 | import UIActions from '../../../actions/UIActions';
8 |
9 | class AddTorrents extends React.Component {
10 | dismissModal() {
11 | UIActions.dismissModal();
12 | }
13 |
14 | render() {
15 | const tabs = {
16 | 'by-url': {
17 | content: AddTorrentsByURL,
18 | label: this.props.intl.formatMessage({
19 | id: 'torrents.add.tab.url.title',
20 | defaultMessage: 'By URL',
21 | }),
22 | },
23 | 'by-file': {
24 | content: AddTorrentsByFile,
25 | label: this.props.intl.formatMessage({
26 | id: 'torrents.add.tab.file.title',
27 | defaultMessage: 'By File',
28 | }),
29 | },
30 | };
31 |
32 | return (
33 |
41 | );
42 | }
43 | }
44 |
45 | export default injectIntl(AddTorrents);
46 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/confirm-modal/ConfirmModal.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Modal from '../Modal';
4 |
5 | export default class ConfirmModal extends React.Component {
6 | getContent() {
7 | return {this.props.options.content}
;
8 | }
9 |
10 | render() {
11 | return (
12 |
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/feeds-modal/FeedsModal.js:
--------------------------------------------------------------------------------
1 | import {injectIntl} from 'react-intl';
2 | import React from 'react';
3 |
4 | import DownloadRulesTab from './DownloadRulesTab';
5 | import FeedMonitorStore from '../../../stores/FeedMonitorStore';
6 | import FeedsTab from './FeedsTab';
7 | import Modal from '../Modal';
8 |
9 | class FeedsModal extends React.Component {
10 | componentDidMount() {
11 | FeedMonitorStore.fetchFeedMonitors();
12 | }
13 |
14 | render() {
15 | const tabs = {
16 | feeds: {
17 | content: FeedsTab,
18 | label: this.props.intl.formatMessage({
19 | id: 'feeds.tabs.feeds',
20 | defaultMessage: 'Feeds',
21 | }),
22 | },
23 | downloadRules: {
24 | content: DownloadRulesTab,
25 | label: this.props.intl.formatMessage({
26 | id: 'feeds.tabs.download.rules',
27 | defaultMessage: 'Download Rules',
28 | }),
29 | },
30 | };
31 |
32 | return (
33 |
43 | );
44 | }
45 | }
46 |
47 | export default injectIntl(FeedsModal);
48 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/settings-modal/AboutTab.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import React from 'react';
3 | import ReactMarkdown from 'react-markdown';
4 |
5 | import AboutMarkdownPath from '../../../../../../ABOUT.md';
6 | import SettingsTab from './SettingsTab';
7 |
8 | export default class AboutTab extends SettingsTab {
9 | state = {
10 | about: null,
11 | };
12 |
13 | componentDidMount() {
14 | axios.get(AboutMarkdownPath).then(response => {
15 | this.setState({about: response.data});
16 | });
17 | }
18 |
19 | render() {
20 | return ;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/javascript/components/modals/settings-modal/SettingsTab.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class SettingsTab extends React.Component {
4 | state = {};
5 |
6 | getFieldValue(fieldName) {
7 | if (this.state[fieldName] == null) {
8 | return this.props.settings[fieldName] || '';
9 | }
10 |
11 | return this.state[fieldName];
12 | }
13 |
14 | handleClientSettingFieldChange(fieldName, event) {
15 | let {value} = event.target;
16 |
17 | if (event.target.type === 'checkbox') {
18 | value = event.target.checked ? '1' : '0';
19 | }
20 |
21 | const nextState = {[fieldName]: value};
22 |
23 | this.setState(nextState);
24 | this.props.onClientSettingsChange(nextState);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/src/javascript/components/sidebar/LogoutButton.js:
--------------------------------------------------------------------------------
1 | import {defineMessages, injectIntl} from 'react-intl';
2 | import React from 'react';
3 |
4 | import AuthActions from '../../actions/AuthActions';
5 | import Logout from '../icons/Logout';
6 | import Tooltip from '../general/Tooltip';
7 |
8 | const MESSAGES = defineMessages({
9 | logOut: {
10 | id: 'sidebar.button.log.out',
11 | defaultMessage: 'Log Out',
12 | },
13 | });
14 |
15 | class LogoutButton extends React.Component {
16 | handleLogoutClick() {
17 | AuthActions.logout().then(() => {
18 | window.location.reload();
19 | });
20 | }
21 |
22 | render() {
23 | return (
24 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default injectIntl(LogoutButton);
38 |
--------------------------------------------------------------------------------
/client/src/javascript/components/sidebar/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import ClientStats from './TransferData';
4 | import CustomScrollbars from '../general/CustomScrollbars';
5 | import FeedsButton from './FeedsButton';
6 | import LogoutButton from './LogoutButton';
7 | import NotificationsButton from './NotificationsButton';
8 | import SearchTorrents from './SearchTorrents';
9 | import SettingsButton from './SettingsButton';
10 | import SidebarActions from './SidebarActions';
11 | import SpeedLimitDropdown from './SpeedLimitDropdown';
12 | import StatusFilters from './StatusFilters';
13 | import TagFilters from './TagFilters';
14 | import TrackerFilters from './TrackerFilters';
15 | import DiskUsage from './DiskUsage';
16 |
17 | const Sidebar = () => {
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | export default Sidebar;
38 |
--------------------------------------------------------------------------------
/client/src/javascript/components/sidebar/SidebarActions.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class SidebarActions extends React.Component {
4 | render() {
5 | return {this.props.children}
;
6 | }
7 | }
8 |
9 | export default SidebarActions;
10 |
--------------------------------------------------------------------------------
/client/src/javascript/components/sidebar/SidebarFilter.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import {injectIntl} from 'react-intl';
3 | import React from 'react';
4 |
5 | import Badge from '../general/Badge';
6 |
7 | const METHODS_TO_BIND = ['handleClick'];
8 |
9 | class SidebarFilter extends React.Component {
10 | constructor() {
11 | super();
12 |
13 | METHODS_TO_BIND.forEach(method => {
14 | this[method] = this[method].bind(this);
15 | });
16 | }
17 |
18 | handleClick() {
19 | this.props.handleClick(this.props.slug);
20 | }
21 |
22 | render() {
23 | const classNames = classnames('sidebar-filter__item', {
24 | 'is-active': this.props.isActive,
25 | });
26 | let {name} = this.props;
27 |
28 | if (this.props.name === 'all') {
29 | name = this.props.intl.formatMessage({
30 | id: 'filter.all',
31 | defaultMessage: 'All',
32 | });
33 | } else if (this.props.name === 'untagged') {
34 | name = this.props.intl.formatMessage({
35 | id: 'filter.untagged',
36 | defaultMessage: 'Untagged',
37 | });
38 | }
39 |
40 | return (
41 |
42 | {this.props.icon}
43 | {name}
44 | {this.props.count}
45 |
46 | );
47 | }
48 | }
49 |
50 | export default injectIntl(SidebarFilter);
51 |
--------------------------------------------------------------------------------
/client/src/javascript/components/sidebar/SidebarItem.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import PropTypes from 'prop-types';
3 | import React from 'react';
4 |
5 | class SidebarItem extends React.Component {
6 | static propTypes = {
7 | baseClassName: PropTypes.string,
8 | children: PropTypes.node,
9 | modifier: PropTypes.string,
10 | };
11 |
12 | static defaultProps = {
13 | baseClassName: 'sidebar__item',
14 | };
15 |
16 | render() {
17 | const classes = classnames(this.props.baseClassName, {
18 | [`${this.props.baseClassName}--${this.props.modifier}`]: this.props.modifier,
19 | });
20 |
21 | return {this.props.children}
;
22 | }
23 | }
24 |
25 | export default SidebarItem;
26 |
--------------------------------------------------------------------------------
/client/src/javascript/components/torrent-list/Action.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import React from 'react';
3 |
4 | import Tooltip from '../general/Tooltip';
5 |
6 | export default class Action extends React.Component {
7 | render() {
8 | const {clickHandler, icon, label, slug} = this.props;
9 | const classes = classnames('action tooltip__wrapper', {
10 | [`action--${slug}`]: slug != null,
11 | });
12 |
13 | return (
14 |
15 | {icon}
16 | {label}
17 |
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/javascript/components/views/Login.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import ApplicationView from '../layout/ApplicationView';
4 | import AuthForm from '../auth/AuthForm';
5 |
6 | export default class LoginView extends React.Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/javascript/components/views/Register.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import ApplicationView from '../layout/ApplicationView';
4 | import AuthForm from '../auth/AuthForm';
5 |
6 | export default class LoginView extends React.Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/javascript/components/views/TorrentClientOverview.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import ActionBar from '../torrent-list/ActionBar';
4 | import Alerts from '../alerts/Alerts';
5 | import ApplicationContent from '../layout/ApplicationContent';
6 | import ApplicationPanel from '../layout/ApplicationPanel';
7 | import ApplicationView from '../layout/ApplicationView';
8 | import Modals from '../modals/Modals';
9 | import Sidebar from '../sidebar/Sidebar';
10 | import TorrentList from '../torrent-list/TorrentList';
11 |
12 | export default class TorrentCLientOverview extends React.Component {
13 | render() {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/javascript/constants/Alerts.js:
--------------------------------------------------------------------------------
1 | const ALERTS = {
2 | 'alert.torrent.add': `Successfully added {countElement} {count, plural,
3 | =1 {torrent}
4 | other {torrents}
5 | }.`,
6 | 'alert.torrent.add.failed': `Failed to add {countElement} {count, plural,
7 | =1 {torrent}
8 | other {torrents}
9 | }.`,
10 | 'alert.torrent.move': `Successfully moved {countElement} {count, plural,
11 | =1 {torrent}
12 | other {torrents}
13 | }.`,
14 | 'alert.torrent.move.failed': `Failed to move {countElement} {count, plural,
15 | =1 {torrent}
16 | other {torrents}
17 | }.`,
18 | 'alert.torrent.remove': `Successfully removed {countElement} {count, plural,
19 | =1 {torrent}
20 | other {torrents}
21 | }.`,
22 | 'alert.torrent.remove.failed': `Failed to remove {countElement} {count, plural,
23 | =1 {torrent}
24 | other {torrents}
25 | }.`,
26 | 'alert.settings.saved': 'Successfully saved settings.',
27 | };
28 |
29 | export default ALERTS;
30 |
--------------------------------------------------------------------------------
/client/src/javascript/constants/Languages.js:
--------------------------------------------------------------------------------
1 | const LANGUAGES = {
2 | en: {
3 | defaultMessage: 'English',
4 | id: 'locale.language.en',
5 | },
6 | es: {
7 | defaultMessage: 'Spanish',
8 | id: 'locale.language.es',
9 | },
10 | fr: {
11 | defaultMessage: 'French',
12 | id: 'locale.language.fr',
13 | },
14 | nl: {
15 | defaultMessage: 'Nederlands',
16 | id: 'locale.language.nl',
17 | },
18 | ko: {
19 | defaultMessage: 'Korean',
20 | id: 'locale.language.ko',
21 | },
22 | zh: {
23 | defaultMessage: 'Chinese',
24 | id: 'locale.language.zh',
25 | },
26 | };
27 |
28 | export default LANGUAGES;
29 |
--------------------------------------------------------------------------------
/client/src/javascript/constants/PriorityLevels.js:
--------------------------------------------------------------------------------
1 | const PRIORITY_LEVELS = {
2 | file: {
3 | 0: 'DONT_DOWNLOAD',
4 | 1: 'NORMAL',
5 | 2: 'HIGH',
6 | },
7 | torrent: {
8 | 0: 'DONT_DOWNLOAD',
9 | 1: 'LOW',
10 | 2: 'NORMAL',
11 | 3: 'HIGH',
12 | },
13 | };
14 |
15 | export default PRIORITY_LEVELS;
16 |
--------------------------------------------------------------------------------
/client/src/javascript/dispatcher/AppDispatcher.js:
--------------------------------------------------------------------------------
1 | import {Dispatcher} from 'flux';
2 |
3 | class FloodDispatcher extends Dispatcher {
4 | dispatchUIAction(action) {
5 | if (action.type == null) {
6 | console.warn('Undefined action.type', action);
7 | }
8 | this.dispatch({source: 'UI_ACTION', action});
9 | }
10 |
11 | dispatchServerAction(action) {
12 | if (action.type == null) {
13 | console.warn('Undefined action.type', action);
14 | }
15 | this.dispatch({source: 'SERVER_ACTION', action});
16 | }
17 | }
18 |
19 | const AppDispatcher = new FloodDispatcher();
20 |
21 | export default AppDispatcher;
22 |
--------------------------------------------------------------------------------
/client/src/javascript/i18n/de.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'sidebar.button.settings': 'Einstellungen',
3 |
4 | 'button.save.feed': 'Speichern',
5 | };
6 |
--------------------------------------------------------------------------------
/client/src/javascript/i18n/languages.ts:
--------------------------------------------------------------------------------
1 | import {addLocaleData} from 'react-intl';
2 | import deLocaleData from 'react-intl/locale-data/de';
3 | import enLocaleData from 'react-intl/locale-data/en';
4 | import esLocaleData from 'react-intl/locale-data/es';
5 | import frLocaleData from 'react-intl/locale-data/fr';
6 | import koLocaleData from 'react-intl/locale-data/ko';
7 | import nlLocaleData from 'react-intl/locale-data/nl';
8 | import zhLocaleData from 'react-intl/locale-data/zh';
9 |
10 | addLocaleData(deLocaleData);
11 | addLocaleData(enLocaleData);
12 | addLocaleData(esLocaleData);
13 | addLocaleData(frLocaleData);
14 | addLocaleData(koLocaleData);
15 | addLocaleData(nlLocaleData);
16 | addLocaleData(zhLocaleData);
17 |
18 | export {default as de} from './de';
19 | export {default as en} from './en';
20 | export {default as es} from './es';
21 | export {default as fr} from './fr';
22 | export {default as ko} from './ko';
23 | export {default as nl} from './nl';
24 | export {default as zh} from './zh';
25 |
--------------------------------------------------------------------------------
/client/src/javascript/stores/BaseStore.js:
--------------------------------------------------------------------------------
1 | import {EventEmitter} from 'events';
2 |
3 | export default class BaseStore extends EventEmitter {
4 | constructor(...eventEmitterConfig) {
5 | super(...eventEmitterConfig);
6 |
7 | this.dispatcherID = null;
8 | this.on('uncaughtException', error => {
9 | throw new Error(error);
10 | });
11 | this.requests = {};
12 | this.setMaxListeners(20);
13 | }
14 |
15 | beginRequest(id) {
16 | this.requests[id] = true;
17 | }
18 |
19 | isRequestPending(id) {
20 | if (this.requests[id] == null) {
21 | return false;
22 | }
23 |
24 | return true;
25 | }
26 |
27 | listen(event, callback) {
28 | this.on(event, callback);
29 | }
30 |
31 | resolveRequest(id) {
32 | delete this.requests[id];
33 | }
34 |
35 | unlisten(event, callback) {
36 | this.removeListener(event, callback);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/client/src/javascript/stores/ClientStatusStore.js:
--------------------------------------------------------------------------------
1 | import ActionTypes from '../constants/ActionTypes';
2 | import AppDispatcher from '../dispatcher/AppDispatcher';
3 | import BaseStore from './BaseStore';
4 | import EventTypes from '../constants/EventTypes';
5 |
6 | class ClientStatusStoreClass extends BaseStore {
7 | constructor() {
8 | super();
9 | this.errorCount = 0;
10 | this.isConnected = null;
11 | }
12 |
13 | getIsConnected() {
14 | return this.isConnected === true;
15 | }
16 |
17 | handleConnectivityStatusChange({isConnected}) {
18 | if (this.isConnected !== isConnected) {
19 | this.isConnected = isConnected;
20 | this.emit(EventTypes.CLIENT_CONNECTION_STATUS_CHANGE);
21 | }
22 | }
23 | }
24 |
25 | const ClientStatusStore = new ClientStatusStoreClass();
26 |
27 | ClientStatusStore.dispatcherID = AppDispatcher.register(payload => {
28 | const {action} = payload;
29 |
30 | switch (action.type) {
31 | case ActionTypes.CLIENT_CONNECTIVITY_STATUS_CHANGE:
32 | ClientStatusStore.handleConnectivityStatusChange(action.data);
33 | break;
34 | default:
35 | break;
36 | }
37 | });
38 |
39 | export default ClientStatusStore;
40 |
--------------------------------------------------------------------------------
/client/src/javascript/stores/ConfigStore.js:
--------------------------------------------------------------------------------
1 | import BaseStore from './BaseStore';
2 |
3 | class ConfigStoreClass extends BaseStore {
4 | getBaseURI() {
5 | return process.env.BASE_URI;
6 | }
7 |
8 | getPollInterval() {
9 | return process.env.POLL_INTERVAL || 5000;
10 | }
11 | }
12 |
13 | export default new ConfigStoreClass();
14 |
--------------------------------------------------------------------------------
/client/src/javascript/stores/DiskUsageStore.js:
--------------------------------------------------------------------------------
1 | import BaseStore from './BaseStore';
2 | import ActionTypes from '../constants/ActionTypes';
3 | import EventTypes from '../constants/EventTypes';
4 | import AppDispatcher from '../dispatcher/AppDispatcher';
5 |
6 | class DiskUsageStoreClass extends BaseStore {
7 | constructor() {
8 | super();
9 | this.disks = [];
10 | }
11 |
12 | setDiskUsage(disks) {
13 | this.disks = disks;
14 | this.emit(EventTypes.DISK_USAGE_CHANGE);
15 | }
16 |
17 | getDiskUsage() {
18 | return this.disks;
19 | }
20 | }
21 |
22 | const DiskUsageStore = new DiskUsageStoreClass();
23 |
24 | DiskUsageStore.dispatcherID = AppDispatcher.register(payload => {
25 | const {action} = payload;
26 | switch (action.type) {
27 | case ActionTypes.DISK_USAGE_CHANGE:
28 | DiskUsageStore.setDiskUsage(action.data);
29 | break;
30 | default:
31 | break;
32 | }
33 | });
34 |
35 | export default DiskUsageStore;
36 |
--------------------------------------------------------------------------------
/client/src/javascript/util/filterTorrents.js:
--------------------------------------------------------------------------------
1 | import torrentStatusMap from '@shared/constants/torrentStatusMap';
2 |
3 | export function filterTorrents(torrentList, opts) {
4 | const {type, filter} = opts;
5 |
6 | if (filter !== 'all') {
7 | if (type === 'status') {
8 | const statusFilter = torrentStatusMap[filter];
9 | return torrentList.filter(torrent => torrent.status.includes(statusFilter));
10 | }
11 | if (type === 'tracker') {
12 | return torrentList.filter(torrent => torrent.trackerURIs.includes(filter));
13 | }
14 | if (type === 'tag') {
15 | return torrentList.filter(torrent => {
16 | if (filter === 'untagged') {
17 | return torrent.tags.length === 0;
18 | }
19 |
20 | return torrent.tags.includes(filter);
21 | });
22 | }
23 | }
24 |
25 | return torrentList;
26 | }
27 |
--------------------------------------------------------------------------------
/client/src/javascript/util/history.js:
--------------------------------------------------------------------------------
1 | import {createBrowserHistory} from 'history';
2 |
3 | import stringUtil from '@shared/util/stringUtil';
4 | import ConfigStore from '../stores/ConfigStore';
5 |
6 | const history = createBrowserHistory({basename: stringUtil.withoutTrailingSlash(ConfigStore.getBaseURI())});
7 |
8 | export default history;
9 |
--------------------------------------------------------------------------------
/client/src/javascript/util/searchTorrents.js:
--------------------------------------------------------------------------------
1 | export function searchTorrents(torrents, searchString) {
2 | if (searchString !== '') {
3 | const queries = [];
4 | const searchTerms = searchString.replace(/,/g, ' ').split(' ');
5 |
6 | for (let i = 0, len = searchTerms.length; i < len; i++) {
7 | queries.push(new RegExp(searchTerms[i], 'gi'));
8 | }
9 |
10 | torrents = torrents.filter(torrent => {
11 | for (let i = 0, len = queries.length; i < len; i++) {
12 | if (!torrent.name.match(queries[i])) {
13 | return false;
14 | }
15 | }
16 | return true;
17 | });
18 | }
19 |
20 | return torrents;
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/javascript/util/size.js:
--------------------------------------------------------------------------------
1 | export function compute(bytes, precision = 2) {
2 | const kilobyte = 1024;
3 |
4 | const megabyte = kilobyte * 1024;
5 |
6 | const gigabyte = megabyte * 1024;
7 |
8 | const terabyte = gigabyte * 1024;
9 | let value = 0;
10 |
11 | let unit = '';
12 |
13 | if (bytes >= terabyte) {
14 | value = bytes / terabyte;
15 | unit = 'TB';
16 | } else if (bytes >= gigabyte) {
17 | value = bytes / gigabyte;
18 | unit = 'GB';
19 | } else if (bytes >= megabyte) {
20 | value = bytes / megabyte;
21 | unit = 'MB';
22 | } else if (bytes >= kilobyte) {
23 | value = bytes / kilobyte;
24 | unit = 'kB';
25 | } else {
26 | value = bytes;
27 | unit = 'B';
28 | }
29 |
30 | value = Number(value);
31 | if (!!value && value >= 100) {
32 | value = Math.floor(value);
33 | } else if (!!value && value > 10) {
34 | value = Number(value.toFixed(precision - 1));
35 | } else if (value) {
36 | value = Number(value.toFixed(precision));
37 | }
38 |
39 | return {
40 | value,
41 | unit,
42 | };
43 | }
44 |
45 | export function getTranslationString(unit) {
46 | const UNIT_TO_STRING_ID = {
47 | B: 'unit.size.byte',
48 | kB: 'unit.size.kilobyte',
49 | MB: 'unit.size.megabyte',
50 | GB: 'unit.size.gigabyte',
51 | TB: 'unit.size.terabyte',
52 | };
53 |
54 | return UNIT_TO_STRING_ID[unit] || 'unit.size.byte';
55 | }
56 |
--------------------------------------------------------------------------------
/client/src/javascript/util/torrentStatusClasses.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 | import torrentStatusMap from '@shared/constants/torrentStatusMap';
3 |
4 | export function torrentStatusClasses(torrent, ...classes) {
5 | return classnames(classes, {
6 | 'torrent--has-error': torrent.status.includes(torrentStatusMap.error),
7 | 'torrent--is-stopped': torrent.status.includes(torrentStatusMap.stopped),
8 | 'torrent--is-downloading': torrent.status.includes(torrentStatusMap.downloading),
9 | 'torrent--is-downloading--actively': torrent.status.includes(torrentStatusMap.activelyDownloading),
10 | 'torrent--is-uploading--actively': torrent.status.includes(torrentStatusMap.activelyUploading),
11 | 'torrent--is-seeding': torrent.status.includes(torrentStatusMap.seeding),
12 | 'torrent--is-completed': torrent.status.includes(torrentStatusMap.complete),
13 | 'torrent--is-checking': torrent.status.includes(torrentStatusMap.checking),
14 | 'torrent--is-inactive': torrent.status.includes(torrentStatusMap.inactive),
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/javascript/util/torrentStatusIcons.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import torrentStatusMap from '@shared/constants/torrentStatusMap';
3 |
4 | import ErrorIcon from '../components/icons/ErrorIcon';
5 | import SpinnerIcon from '../components/icons/SpinnerIcon';
6 | import StartIcon from '../components/icons/StartIcon';
7 | import StopIcon from '../components/icons/StopIcon';
8 |
9 | const STATUS_ICON_MAP = {
10 | error: ,
11 | hashChecking: ,
12 | stopped: ,
13 | running: ,
14 | };
15 |
16 | export function torrentStatusIcons(status) {
17 | let statusString;
18 | const statusConditions = {
19 | hashChecking: [status.includes(torrentStatusMap.checking)],
20 | error: [status.includes(torrentStatusMap.error)],
21 | stopped: [status.includes(torrentStatusMap.stopped)],
22 | running: [status.includes(torrentStatusMap.downloading), status.includes(torrentStatusMap.seeding)],
23 | };
24 |
25 | Object.keys(statusConditions).some(conditionName => {
26 | const conditions = statusConditions[conditionName];
27 |
28 | conditions.some(condition => {
29 | if (condition) {
30 | statusString = conditionName;
31 | }
32 |
33 | return condition;
34 | });
35 |
36 | return statusString != null;
37 | });
38 |
39 | return STATUS_ICON_MAP[statusString];
40 | }
41 |
--------------------------------------------------------------------------------
/client/src/javascript/util/validators.js:
--------------------------------------------------------------------------------
1 | import regEx from '@shared/util/regEx';
2 |
3 | export const isNotEmpty = value => {
4 | return value != null && value !== '';
5 | };
6 |
7 | export const isRegExValid = regExToCheck => {
8 | try {
9 | // eslint-disable-next-line no-new
10 | new RegExp(regExToCheck);
11 | } catch (err) {
12 | return false;
13 | }
14 |
15 | return true;
16 | };
17 |
18 | export const isURLValid = url => {
19 | return url != null && url !== '' && url.match(regEx.url) !== null;
20 | };
21 |
22 | export const isPositiveInteger = value => {
23 | if (value === null || value === '') return false;
24 |
25 | const number = parseInt(value, 10);
26 |
27 | return !Number.isNaN(number) && number > 0;
28 | };
29 |
--------------------------------------------------------------------------------
/client/src/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/client/src/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/client/src/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/client/src/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #0e2337
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/client/src/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/favicon-16x16.png
--------------------------------------------------------------------------------
/client/src/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/favicon-32x32.png
--------------------------------------------------------------------------------
/client/src/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/favicon.ico
--------------------------------------------------------------------------------
/client/src/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Flood",
3 | "icons": [
4 | {
5 | "src": "android-chrome-192x192.png",
6 | "sizes": "192x192",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "android-chrome-512x512.png",
11 | "sizes": "512x512",
12 | "type": "image/png"
13 | }
14 | ],
15 | "start_url": "./index.html",
16 | "theme_color": "#ffffff",
17 | "background_color": "#1d2938",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/client/src/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/mstile-144x144.png
--------------------------------------------------------------------------------
/client/src/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/mstile-150x150.png
--------------------------------------------------------------------------------
/client/src/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/mstile-310x150.png
--------------------------------------------------------------------------------
/client/src/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/mstile-310x310.png
--------------------------------------------------------------------------------
/client/src/public/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/client/src/public/mstile-70x70.png
--------------------------------------------------------------------------------
/client/src/public/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
21 |
--------------------------------------------------------------------------------
/client/src/sass/base/_animations.scss:
--------------------------------------------------------------------------------
1 | @keyframes fade-in {
2 |
3 | 0% {
4 | opacity: 0;
5 | }
6 |
7 | 100% {
8 | opacity: 1;
9 | }
10 |
11 | }
12 |
13 | @keyframes fade-out {
14 |
15 | 0% {
16 | opacity: 1;
17 | }
18 |
19 | 100% {
20 | opacity: 0;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/client/src/sass/base/_layout.scss:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | overflow: hidden;
5 | }
6 |
7 | .container {
8 | height: 100%;
9 | width: 100%;
10 | }
11 |
12 | #app,
13 | .application,
14 | .application__view {
15 | height: 100%;
16 | width: 100%;
17 | }
18 |
19 | .application {
20 |
21 | &,
22 | &__view {
23 | align-content: center;
24 | align-items: center;
25 | display: flex;
26 | flex: 1;
27 | justify-content: center;
28 | height: 100%;
29 | width: 100%;
30 | }
31 |
32 | &__content {
33 | align-items: center;
34 | display: flex;
35 | flex: 1 0 auto;
36 | flex-direction: column;
37 | height: 100%;
38 | justify-content: center;
39 | position: relative;
40 | }
41 |
42 | &__panel {
43 | display: flex;
44 | bottom: 0;
45 | left: 0;
46 | position: absolute;
47 | right: 0;
48 | top: 0;
49 |
50 | &--torrent-list {
51 | transition: transform 0.5s;
52 | z-index: 2;
53 |
54 | &.is-open {
55 | transform: translateX($torrent-details--width);
56 | }
57 | }
58 |
59 | &--torrent-details {
60 | right: 100% - $torrent-details--width;
61 | width: $torrent-details--width;
62 | z-index: 1;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/client/src/sass/base/_main.scss:
--------------------------------------------------------------------------------
1 | body {
2 | background: $background;
3 | }
4 |
5 | ul {
6 | list-style: none;
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/sass/components/_app-wrapper.scss:
--------------------------------------------------------------------------------
1 | .application {
2 | &__loading-overlay {
3 | align-items: center;
4 | background: $light-blue;
5 | display: flex;
6 | flex-direction: column;
7 | font-size: 0.8em;
8 | height: 100%;
9 | justify-content: center;
10 | left: 0;
11 | opacity: 1;
12 | position: fixed;
13 | top: 0;
14 | width: 100%;
15 | z-index: 1000;
16 |
17 | &-exit {
18 | opacity: 1;
19 | transition: opacity 1s;
20 |
21 | &-active {
22 | opacity: 0;
23 | }
24 | }
25 | }
26 |
27 | &__entry-barrier {
28 | max-width: 500px;
29 | width: 100%;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/sass/components/_attached-panel.scss:
--------------------------------------------------------------------------------
1 | $attached-panel--background: #242b36;
2 | $attached-panel--foreground: #5e728c;
3 |
4 | $attached-panel--border: #1a2028;
5 | $attached-panel--border-radius: 4px;
6 |
7 | $attached-panel--padding--vertical: 10px;
8 | $attached-panel--padding--horizontal: 15px;
9 |
10 | $attached-panel--shadow: #05080a;
11 |
12 | .attached-panel {
13 | background: $attached-panel--background;
14 | border: 1px solid $attached-panel--border;
15 | border-radius: 0 0 $attached-panel--border-radius $attached-panel--border-radius;
16 | border-top-width: 0;
17 | color: $attached-panel--foreground;
18 | position: fixed;
19 | transition: opacity 0.25s;
20 | z-index: 100;
21 |
22 | &__content {
23 | padding: $attached-panel--padding--vertical $attached-panel--padding--horizontal;
24 | }
25 |
26 | &__wrapper {
27 | position: relative;
28 | }
29 |
30 | &-enter {
31 | opacity: 0;
32 |
33 | &-active {
34 | opacity: 1;
35 | }
36 | }
37 |
38 | &-exit {
39 | opacity: 1;
40 |
41 | &-active {
42 | opacity: 0;
43 | }
44 | }
45 | }
46 |
47 | .textbox {
48 | &--has-attached-panel {
49 | &--is-open {
50 | border-bottom-left-radius: 0;
51 | border-bottom-right-radius: 0;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/client/src/sass/components/_badge.scss:
--------------------------------------------------------------------------------
1 | $sidebar-filter--count--foreground: darken($grey, 5%);
2 | $sidebar-filter--count--background: lighten($grey, 20%);
3 | $sidebar-filter--count--background--active: $blue;
4 |
5 | .badge {
6 | background: $sidebar-filter--count--background;
7 | border-radius: 100px;
8 | color: $sidebar-filter--count--foreground;
9 | display: inline-block;
10 | font-size: 0.75rem;
11 | font-weight: 700;
12 | line-height: 1;
13 | margin-left: 10px;
14 | padding: 2px 5px;
15 | transition: background 0.25s;
16 | vertical-align: middle;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/sass/components/_connection-status.scss:
--------------------------------------------------------------------------------
1 | .connection-status {
2 | display: flex;
3 | align-items: center;
4 |
5 | &__icon {
6 | fill: $green--darker;
7 | height: 15px;
8 | margin-right: 5px;
9 | width: 15px;
10 | }
11 |
12 | &__copy {
13 | color: $light-grey--lighter;
14 | font-size: 14px;
15 | }
16 | }
--------------------------------------------------------------------------------
/client/src/sass/components/_dependency-list.scss:
--------------------------------------------------------------------------------
1 | .dependency-list {
2 | margin-top: $spacing-unit;
3 | width: auto;
4 |
5 | &__dependency {
6 | color: $foreground;
7 | display: flex;
8 | opacity: 0.5;
9 | transition: opacity 0.25s;
10 | white-space: nowrap;
11 |
12 | &__icon {
13 | fill: $green;
14 | flex: 0 0 $spacing-unit * 2/5;
15 | height: $spacing-unit * 2/5;
16 | margin-right: $spacing-unit * 1/5;
17 | opacity: 0;
18 | transition: opacity 0.25s;
19 | width: $spacing-unit * 2/5;
20 |
21 | .icon {
22 | height: 10px;
23 | width: 10px;
24 | }
25 | }
26 |
27 | &--satisfied {
28 | opacity: 1;
29 |
30 | .dependency-list {
31 |
32 | &__dependency {
33 |
34 | &__icon {
35 | opacity: 1;
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/sass/components/_duration.scss:
--------------------------------------------------------------------------------
1 | .duration {
2 |
3 | &--segment {
4 | margin-right: 0.25em;
5 |
6 | &:last-child {
7 | margin-right: 0;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/sass/components/_mediainfo.scss:
--------------------------------------------------------------------------------
1 | .mediainfo {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | &__toolbar {
6 | display: flex;
7 | flex: 0 0 auto;
8 | justify-content: space-between;
9 | padding-bottom: $spacing-unit * 2/5;
10 | position: relative;
11 |
12 | .tooltip__wrapper {
13 | bottom: 0;
14 | position: absolute;
15 | right: 0;
16 | }
17 | }
18 |
19 | &__copy-button {
20 |
21 | &.tooltip {
22 |
23 | &__wrapper {
24 | position: absolute;
25 | right: 0;
26 | top: 0;
27 | }
28 | }
29 |
30 | .icon {
31 | fill: currentColor;
32 | height: 16px;
33 | width: 16px;
34 | }
35 | }
36 |
37 | &__output {
38 | flex: 1 1 auto;
39 | overflow: auto;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/sass/components/_peers-list.scss:
--------------------------------------------------------------------------------
1 | .peers-list {
2 |
3 | &__flag {
4 | display: inline-block;
5 | height: 10px;
6 | overflow: hidden;
7 | margin-right: $spacing-unit * 3/10;
8 | position: relative;
9 | width: 15px;
10 | vertical-align: baseline;
11 |
12 | &__image {
13 | height: 10px;
14 | left: 50%;
15 | position: absolute;
16 | top: 0;
17 | transform: translateX(-50%);
18 | width: auto;
19 | z-index: 2;
20 | }
21 |
22 | &__text {
23 | font-size: 0.8em;
24 | font-weight: bold;
25 | left: 50%;
26 | margin-top: 1px;
27 | position: absolute;
28 | top: 50%;
29 | transform: translate(-50%, -50%);
30 | z-index: 1;
31 | }
32 | }
33 |
34 | &__encryption {
35 |
36 | .icon {
37 | fill: $green;
38 | height: 12px;
39 | width: 12px;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/sass/components/_scrollbars.scss:
--------------------------------------------------------------------------------
1 | $scrollbar--thumb--background--inactive: rgba(#1a2f3d, 0.3);
2 | $scrollbar--thumb--background--hover: rgba(#1a2f3d, 0.6);
3 | $scrollbar--thumb--background--inverted--inactive: rgba(#e9eef2, 0.3);
4 | $scrollbar--thumb--background--inverted--hover: rgba(#e9eef2, 0.6);
5 |
6 | .scrollbars {
7 |
8 | &__thumb {
9 | background: $scrollbar--thumb--background--inactive;
10 | border-radius: 10px;
11 | cursor: pointer;
12 | opacity: 0;
13 | transition: background 0.25s, opacity 0.5s;
14 | z-index: 2;
15 |
16 | &:active {
17 | opacity: 1;
18 | }
19 |
20 | &:hover,
21 | &:active {
22 | background: $scrollbar--thumb--background--hover;
23 | }
24 |
25 | &--surrogate {
26 | display: block;
27 | height: 100%;
28 | width: 100%;
29 | }
30 |
31 | .is-inverted & {
32 | background: $scrollbar--thumb--background--inverted--inactive;
33 |
34 | &:hover,
35 | &:active {
36 | background: $scrollbar--thumb--background--inverted--hover;
37 | }
38 | }
39 | }
40 |
41 | &:hover {
42 |
43 | .scrollbars__thumb {
44 | opacity: 1;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/client/src/sass/components/_sort-dropdown.scss:
--------------------------------------------------------------------------------
1 | .sort-dropdown {
2 |
3 | &__item {
4 | align-items: center;
5 | display: flex;
6 | }
7 |
8 | &__indicator {
9 | border-left: 4px solid transparent;
10 | border-right: 4px solid transparent;
11 | border-top: 5px solid currentColor;
12 | display: inline-block;
13 | margin-left: auto;
14 | transition: transform 0.25s;
15 | vertical-align: middle;
16 |
17 | &--asc {
18 | transform: rotate(180deg);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/sass/components/_tags.scss:
--------------------------------------------------------------------------------
1 | $tag--background: rgba(#4a596d, 0.75);
2 | $tag--foreground: #1a2028;
3 |
4 | .tag {
5 | background: $tag--background;
6 | border-radius: 30px;
7 | color: $tag--foreground;
8 | display: inline-block;
9 | font-size: 0.9em;
10 | margin-right: $spacing-unit * 1/5;
11 | padding: 0 $spacing-unit * 2/5;
12 | white-space: nowrap;
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/sass/components/_textbox-repeater.scss:
--------------------------------------------------------------------------------
1 | .textbox-repeater {
2 |
3 | .icon {
4 | height: 12px;
5 | width: 12px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/sass/components/_transfer-data.scss:
--------------------------------------------------------------------------------
1 | $transfer-data--download: $green;
2 | $transfer-data--upload: $blue;
3 |
4 | .transfer-data {
5 |
6 | &--download {
7 | color: $transfer-data--download;
8 |
9 | .icon {
10 | fill: $transfer-data--download;
11 | }
12 | }
13 |
14 | &--upload {
15 | color: $transfer-data--upload;
16 |
17 | .icon {
18 | fill: $transfer-data--upload;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/sass/tools/_colors.scss:
--------------------------------------------------------------------------------
1 | $dark-blue: #1d2938;
2 | $grey: #293341;
3 | $light-grey: #3A4553;
4 | $light-grey--lighter: lighten($light-grey, 40%);
5 | $blue: #258de5;
6 | $blue--lighter: saturate(lighten($blue, 10%), 100%);
7 | $green: #39ce83;
8 | $green--darker: darken(#39ce83, 4%);
9 | $light-blue: #e9eef2;
10 | $red: #e95779;
11 | $white: #fff;
12 |
13 | $background: $dark-blue;
14 | $foreground: #53718a;
15 |
16 | $sidebar--background: $grey;
17 | $main-content--background: $light-blue;
18 |
--------------------------------------------------------------------------------
/client/src/sass/tools/_reset.scss:
--------------------------------------------------------------------------------
1 | th {
2 | font-weight: inherit;
3 | text-align: left;
4 | }
5 |
--------------------------------------------------------------------------------
/client/src/sass/tools/_variables.scss:
--------------------------------------------------------------------------------
1 | @import 'colors';
2 |
3 | $font-family: 'Roboto', sans-serif;
4 |
5 | $spacing-unit: 25px;
6 |
7 | $torrent-details--width: 85%;
8 |
9 | $textbox--background: #242b36;
10 | $textbox--foreground: #5e728c;
11 | $textbox--border: #1a2028;
12 | $textbox--fulfilled--background: $textbox--background;
13 | $form--element--border-radius: 4px;
14 | $textbox--padding--vertical: 10px;
15 | $textbox--padding--horizontal: 15px;
16 | $textbox--placeholder: #424d5e;
17 | $textbox--selection--foreground: #1a2028;
18 | $textbox--selection--background: $blue--lighter;
19 | $textbox--active--background: $textbox--background;
20 | $textbox--active--border: $blue;
21 | $textbox--active--foreground: $blue;
22 | $textbox--active--placeholder: $textbox--placeholder;
23 |
--------------------------------------------------------------------------------
/client/src/sass/views/_feeds.scss:
--------------------------------------------------------------------------------
1 | .feed-list {
2 |
3 | &__feed-label {
4 | display: block;
5 | overflow: hidden;
6 | text-overflow: ellipsis;
7 | }
8 | }
--------------------------------------------------------------------------------
/config.docker.js:
--------------------------------------------------------------------------------
1 | const CONFIG = {
2 | baseURI: process.env.FLOOD_BASE_URI || '/',
3 | dbCleanInterval: 1000 * 60 * 60,
4 | dbPath: '/data/server/db/',
5 | floodServerPort: 3000,
6 | maxHistoryStates: 30,
7 | pollInterval: 1000 * 5,
8 | secret: process.env.FLOOD_SECRET || 'flood',
9 | scgi: {
10 | host: process.env.RTORRENT_SCGI_HOST || 'localhost',
11 | port: process.env.RTORRENT_SCGI_PORT || 5000,
12 | socket: process.env.RTORRENT_SOCK === 'true' || process.env.RTORRENT_SOCK === true,
13 | socketPath: process.env.RTORRENT_SOCK_PATH || '/data/rtorrent.sock',
14 | },
15 | ssl: process.env.FLOOD_ENABLE_SSL === 'true' || process.env.FLOOD_ENABLE_SSL === true,
16 | sslKey: '/data/flood_ssl.key',
17 | sslCert: '/data/flood_ssl.cert',
18 | };
19 |
20 | module.exports = CONFIG;
21 |
--------------------------------------------------------------------------------
/custom.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | const content: any;
3 | export default content;
4 | }
5 |
--------------------------------------------------------------------------------
/flood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/flood.png
--------------------------------------------------------------------------------
/server/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: 0,
4 | node: 1,
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/server/bin/enforce-prerequisites.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const staticAssets = [path.join(__dirname, '../assets/index.html')];
5 |
6 | const configFiles = [path.join(__dirname, '../../config.js')];
7 |
8 | // Taken from react-scripts/check-required-files, but without console.logs.
9 | const doFilesExist = files => {
10 | try {
11 | files.forEach(filename => {
12 | fs.accessSync(filename, fs.F_OK);
13 | });
14 | return true;
15 | } catch (err) {
16 | return false;
17 | }
18 | };
19 |
20 | const enforcePrerequisites = () =>
21 | new Promise((resolve, reject) => {
22 | if (!doFilesExist(configFiles)) {
23 | reject(new Error(`Configuration files missing. Please check the 'Configuring' section of README.md.`));
24 | return;
25 | }
26 |
27 | if (!doFilesExist(staticAssets)) {
28 | reject(
29 | new Error(
30 | `Static assets (index.html) are missing. Please check the 'Compiling assets and starting the server' section of README.md.`,
31 | ),
32 | );
33 | return;
34 | }
35 |
36 | return resolve();
37 | });
38 |
39 | module.exports = enforcePrerequisites;
40 |
--------------------------------------------------------------------------------
/server/bin/migrations/fix-is-admin-flag.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const Users = require('../../models/Users');
3 |
4 | const log = data => {
5 | if (process.env.DEBUG) {
6 | console.log(data);
7 | }
8 | };
9 |
10 | const migrate = () => {
11 | log(chalk.green('Migrating data: resolving unset isAdmin flag'));
12 |
13 | return new Promise((migrateResolve, migrateReject) => {
14 | Users.listUsers((users, migrateError) => {
15 | if (migrateError) return migrateReject(migrateError);
16 |
17 | migrateResolve(
18 | Promise.all(
19 | users.map(user => {
20 | let userPatch = null;
21 |
22 | if (user.isAdmin == null) {
23 | userPatch = {isAdmin: true};
24 | }
25 |
26 | if (userPatch != null) {
27 | log(chalk.yellow(`Migrating user ${user.username}`));
28 |
29 | return new Promise((updateUserResolve, updateUserReject) => {
30 | Users.updateUser(user.username, userPatch, (response, updateUserError) => {
31 | if (updateUserError) {
32 | updateUserReject(updateUserError);
33 | return;
34 | }
35 |
36 | updateUserResolve(response);
37 | });
38 | });
39 | }
40 |
41 | return Promise.resolve();
42 | }),
43 | ),
44 | );
45 | });
46 | });
47 | };
48 |
49 | module.exports = migrate;
50 |
--------------------------------------------------------------------------------
/server/bin/migrations/run.js:
--------------------------------------------------------------------------------
1 | const perUserRtorrentInstances = require('./per-user-rtorrent-instances');
2 | const fixIsAdminFlag = require('./fix-is-admin-flag');
3 |
4 | const migrations = [perUserRtorrentInstances, fixIsAdminFlag];
5 |
6 | const migrate = () => Promise.all(migrations.map(migration => migration()));
7 |
8 | module.exports = migrate;
9 |
--------------------------------------------------------------------------------
/server/bin/start.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 |
3 | const enforcePrerequisites = require('./enforce-prerequisites');
4 | const migrateData = require('./migrations/run');
5 | const {startWebServer} = require('./web-server');
6 |
7 | enforcePrerequisites()
8 | .then(migrateData)
9 | .then(startWebServer)
10 | .catch(error => {
11 | console.log(chalk.red('Failed to start Flood:'));
12 | console.trace(error);
13 | process.exit(1);
14 | });
15 |
--------------------------------------------------------------------------------
/server/config/passport.js:
--------------------------------------------------------------------------------
1 | const JwtStrategy = require('passport-jwt').Strategy;
2 |
3 | const config = require('../../config');
4 | const Users = require('../models/Users');
5 |
6 | // Setup work and export for the JWT passport strategy.
7 | module.exports = passport => {
8 | const options = {
9 | jwtFromRequest: req => {
10 | let token = null;
11 |
12 | if (req && req.cookies) {
13 | token = req.cookies.jwt;
14 | }
15 |
16 | return token;
17 | },
18 | secretOrKey: config.secret,
19 | };
20 |
21 | passport.use(
22 | new JwtStrategy(options, (jwtPayload, callback) => {
23 | Users.lookupUser({username: jwtPayload.username}, (err, user) => {
24 | if (err) {
25 | return callback(err, false);
26 | }
27 |
28 | if (user) {
29 | return callback(null, user);
30 | }
31 |
32 | return callback(null, false);
33 | });
34 | }),
35 | );
36 | };
37 |
--------------------------------------------------------------------------------
/server/constants/clientGatewayServiceEvents.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../../shared/util/objectUtil');
2 |
3 | const clientGatewayServiceEvents = [
4 | 'CLIENT_CONNECTION_STATE_CHANGE',
5 | 'PROCESS_TORRENT',
6 | 'PROCESS_TORRENT_LIST_END',
7 | 'PROCESS_TORRENT_LIST_START',
8 | 'PROCESS_TRANSFER_RATE_START',
9 | 'TORRENTS_REMOVED',
10 | ];
11 |
12 | module.exports = objectUtil.createSymbolMapFromArray(clientGatewayServiceEvents);
13 |
--------------------------------------------------------------------------------
/server/constants/diskUsageServiceEvents.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../../shared/util/objectUtil');
2 |
3 | const diskUsageServiceEvents = ['DISK_USAGE_CHANGE'];
4 |
5 | module.exports = objectUtil.createSymbolMapFromArray(diskUsageServiceEvents);
6 |
--------------------------------------------------------------------------------
/server/constants/fileListPropMap.js:
--------------------------------------------------------------------------------
1 | const fileListPropMap = new Map();
2 | const defaultTransformer = value => value;
3 |
4 | fileListPropMap.set('path', {
5 | methodCall: 'f.path=',
6 | transformValue: defaultTransformer,
7 | });
8 |
9 | fileListPropMap.set('pathComponents', {
10 | methodCall: 'f.path_components=',
11 | transformValue: defaultTransformer,
12 | });
13 |
14 | fileListPropMap.set('priority', {
15 | methodCall: 'f.priority=',
16 | transformValue: defaultTransformer,
17 | });
18 |
19 | fileListPropMap.set('sizeBytes', {
20 | methodCall: 'f.size_bytes=',
21 | transformValue: Number,
22 | });
23 |
24 | fileListPropMap.set('sizeChunks', {
25 | methodCall: 'f.size_chunks=',
26 | transformValue: Number,
27 | });
28 |
29 | fileListPropMap.set('completedChunks', {
30 | methodCall: 'f.completed_chunks=',
31 | transformValue: Number,
32 | });
33 |
34 | module.exports = fileListPropMap;
35 |
--------------------------------------------------------------------------------
/server/constants/historyServiceEvents.js:
--------------------------------------------------------------------------------
1 | const historySnapshotTypes = require('../../shared/constants/historySnapshotTypes');
2 | const objectUtil = require('../../shared/util/objectUtil');
3 |
4 | const torrentServiceEvents = [
5 | 'FETCH_TRANSFER_SUMMARY_ERROR',
6 | 'FETCH_TRANSFER_SUMMARY_SUCCESS',
7 | 'TRANSFER_SUMMARY_DIFF_CHANGE',
8 | ].concat(
9 | // Create an array of event types based on the available snapshots.
10 | Object.keys(historySnapshotTypes).reduce((accumulator, snapshotType) => {
11 | accumulator.push(`${snapshotType}_SNAPSHOT_FULL_UPDATE`, `${snapshotType}_SNAPSHOT_DIFF_CHANGE`);
12 |
13 | return accumulator;
14 | }, []),
15 | );
16 |
17 | module.exports = objectUtil.createSymbolMapFromArray(torrentServiceEvents);
18 |
--------------------------------------------------------------------------------
/server/constants/notificationServiceEvents.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../../shared/util/objectUtil');
2 |
3 | const notificationServiceEvents = ['NOTIFICATION_COUNT_CHANGE'];
4 |
5 | module.exports = objectUtil.createSymbolMapFromArray(notificationServiceEvents);
6 |
--------------------------------------------------------------------------------
/server/constants/taxonomyServiceEvents.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../../shared/util/objectUtil');
2 |
3 | const taxonomyServiceEvents = ['TAXONOMY_DIFF_CHANGE'];
4 |
5 | module.exports = objectUtil.createSymbolMapFromArray(taxonomyServiceEvents);
6 |
--------------------------------------------------------------------------------
/server/constants/torrentServiceEvents.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../../shared/util/objectUtil');
2 |
3 | const torrentServiceEvents = ['FETCH_TORRENT_LIST_ERROR', 'FETCH_TORRENT_LIST_SUCCESS', 'TORRENT_LIST_DIFF_CHANGE'];
4 |
5 | module.exports = objectUtil.createSymbolMapFromArray(torrentServiceEvents);
6 |
--------------------------------------------------------------------------------
/server/constants/transferSummaryPropMap.js:
--------------------------------------------------------------------------------
1 | const transferSummaryPropMap = new Map();
2 |
3 | transferSummaryPropMap.set('upRate', {
4 | methodCall: 'throttle.global_up.rate',
5 | transformValue: Number,
6 | });
7 |
8 | transferSummaryPropMap.set('upTotal', {
9 | methodCall: 'throttle.global_up.total',
10 | transformValue: Number,
11 | });
12 |
13 | transferSummaryPropMap.set('upThrottle', {
14 | methodCall: 'throttle.global_up.max_rate',
15 | transformValue: Number,
16 | });
17 |
18 | transferSummaryPropMap.set('downRate', {
19 | methodCall: 'throttle.global_down.rate',
20 | transformValue: Number,
21 | });
22 |
23 | transferSummaryPropMap.set('downTotal', {
24 | methodCall: 'throttle.global_down.total',
25 | transformValue: Number,
26 | });
27 |
28 | transferSummaryPropMap.set('downThrottle', {
29 | methodCall: 'throttle.global_down.max_rate',
30 | transformValue: Number,
31 | });
32 |
33 | module.exports = transferSummaryPropMap;
34 |
--------------------------------------------------------------------------------
/server/middleware/appendUserServices.js:
--------------------------------------------------------------------------------
1 | const services = require('../services');
2 |
3 | module.exports = (req, res, next) => {
4 | req.services = services.getAllServices(req.user);
5 | next();
6 | };
7 |
--------------------------------------------------------------------------------
/server/middleware/booleanCoerce.js:
--------------------------------------------------------------------------------
1 | module.exports = key => (req, res, next) => {
2 | const value = req.body && req.body[key];
3 |
4 | if (value && typeof value === 'string') {
5 | req.body[key] = value === 'true';
6 | }
7 |
8 | next();
9 | };
10 |
--------------------------------------------------------------------------------
/server/middleware/eventStream.js:
--------------------------------------------------------------------------------
1 | module.exports = (req, res, next) => {
2 | req.socket.setKeepAlive(true);
3 | req.socket.setTimeout(0);
4 |
5 | res.set({
6 | 'Content-Type': 'text/event-stream',
7 | 'Cache-Control': 'no-cache',
8 | Connection: 'keep-alive',
9 | 'Access-Control-Allow-Origin': '*',
10 | 'X-Accel-Buffering': 'no',
11 | });
12 | res.status(200);
13 | res.write('retry: 500\n\n');
14 |
15 | // Keep the connection open by sending a message every so often.
16 | const keepAliveTimeout = setInterval(() => {
17 | res.write(':keep-alive\n\n');
18 | res.flush();
19 | }, 500);
20 |
21 | // cleanup on close
22 | res.on('close', () => {
23 | clearInterval(keepAliveTimeout);
24 | });
25 |
26 | next();
27 | };
28 |
--------------------------------------------------------------------------------
/server/middleware/requireAdmin.js:
--------------------------------------------------------------------------------
1 | module.exports = (req, res, next) => {
2 | if (req.user == null || !req.user.isAdmin) {
3 | return res
4 | .status(403)
5 | .json({message: 'User is not admin.'})
6 | .send();
7 | }
8 | next();
9 | };
10 |
--------------------------------------------------------------------------------
/server/models/Filesystem.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const ospath = require('ospath');
3 | const path = require('path');
4 |
5 | const getDirectoryList = (options, callback) => {
6 | const sourcePath = (options.path || '/').replace(/^~/, ospath.home());
7 |
8 | try {
9 | const directories = [];
10 | const files = [];
11 |
12 | fs.readdirSync(sourcePath).forEach(item => {
13 | const joinedPath = path.join(sourcePath, item);
14 | if (fs.existsSync(joinedPath)) {
15 | if (fs.statSync(joinedPath).isDirectory()) {
16 | directories.push(item);
17 | } else {
18 | files.push(item);
19 | }
20 | }
21 | });
22 |
23 | const hasParent = /^.{0,}:?(\/|\\){1,1}\S{1,}/.test(sourcePath);
24 |
25 | callback({
26 | directories,
27 | files,
28 | hasParent,
29 | path: sourcePath,
30 | separator: path.sep,
31 | });
32 | } catch (error) {
33 | callback(null, error);
34 | }
35 | };
36 |
37 | module.exports = {getDirectoryList};
38 |
--------------------------------------------------------------------------------
/server/models/ServerEvent.js:
--------------------------------------------------------------------------------
1 | class ServerEvent {
2 | constructor(res) {
3 | this.data = '';
4 | this.res = res;
5 |
6 | // Add 2kb padding for IE.
7 | const padding = new Array(2049);
8 | res.write(`:${padding.join(' ')}\n`);
9 | }
10 |
11 | addData(data) {
12 | const lines = JSON.stringify(data).split(/\n/);
13 |
14 | this.data = lines.reduce((accumulator, datum) => `${this.data}data:${datum}\n`, this.data);
15 | }
16 |
17 | emit() {
18 | this.res.write(`${this.data}\n`);
19 | this.res.flush();
20 | this.data = '';
21 | }
22 |
23 | setID(id) {
24 | this.res.write(`id:${id}\n`);
25 | }
26 |
27 | setType(eventType) {
28 | this.res.write(`event:${eventType}\n`);
29 | }
30 | }
31 |
32 | module.exports = ServerEvent;
33 |
--------------------------------------------------------------------------------
/server/models/TemporaryStorage.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const mkdirp = require('mkdirp');
3 | const path = require('path');
4 |
5 | class TemporaryStorage {
6 | constructor() {
7 | this.tempPath = path.join(path.dirname(require.main.filename), '..', 'temp');
8 |
9 | mkdirp(this.tempPath);
10 | }
11 |
12 | deleteFile(filename) {
13 | fs.unlink(this.getTempPath(filename));
14 | }
15 |
16 | getTempPath(filename) {
17 | return path.join(this.tempPath, filename);
18 | }
19 | }
20 |
21 | module.exports = new TemporaryStorage();
22 |
--------------------------------------------------------------------------------
/server/services/BaseService.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require('events');
2 |
3 | class BaseService extends EventEmitter {
4 | constructor(user, services, ...eventEmitterConfig) {
5 | super(...eventEmitterConfig);
6 | if (!user || !user._id) throw new Error('Missing user ID');
7 | this.user = user;
8 | this.services = services;
9 | }
10 |
11 | destroy() {
12 | delete this.services;
13 | delete this.user;
14 | }
15 |
16 | updateUser(user, services) {
17 | this.user = user;
18 | this.services = services;
19 | }
20 | }
21 |
22 | module.exports = BaseService;
23 |
--------------------------------------------------------------------------------
/server/util/ajaxUtil.js:
--------------------------------------------------------------------------------
1 | const ajaxUtil = {
2 | getResponseFn: res => (data, error) => {
3 | if (error) {
4 | if (process.env.NODE_ENV === 'development') {
5 | console.trace(error);
6 | }
7 |
8 | if (typeof error === 'string') {
9 | error = {
10 | message: error,
11 | };
12 | }
13 |
14 | res.status(500).json(error);
15 | } else {
16 | res.json(data);
17 | }
18 | },
19 | };
20 |
21 | module.exports = ajaxUtil;
22 |
--------------------------------------------------------------------------------
/server/util/mediainfo.js:
--------------------------------------------------------------------------------
1 | const childProcess = require('child_process');
2 |
3 | const services = require('../services');
4 |
5 | module.exports = {
6 | getMediainfo(user, options, callback) {
7 | const torrentService = services.getTorrentService(user);
8 | const {hash} = options;
9 |
10 | if (hash == null) {
11 | callback(null, {error: 'Hash must be defined'});
12 | return;
13 | }
14 | const selectedTorrent = torrentService.getTorrent(hash);
15 | try {
16 | childProcess.execFile(
17 | 'mediainfo',
18 | [selectedTorrent.basePath],
19 | {maxBuffer: 1024 * 2000},
20 | (error, stdout, stderr) => {
21 | if (error) {
22 | callback(null, {error});
23 | return;
24 | }
25 |
26 | if (stderr) {
27 | callback(null, {error: stderr});
28 | return;
29 | }
30 |
31 | callback({output: stdout});
32 | },
33 | );
34 | } catch (childProcessError) {
35 | callback(null, {error: childProcessError});
36 | }
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/server/util/methodCallUtil.js:
--------------------------------------------------------------------------------
1 | const methodCallUtil = {
2 | getMethodCallConfigFromPropMap(map = new Map(), requestedKeys) {
3 | let desiredKeys = Array.from(map.keys());
4 |
5 | if (requestedKeys != null) {
6 | desiredKeys = desiredKeys.filter(key => requestedKeys.includes(key));
7 | }
8 |
9 | return desiredKeys.reduce(
10 | (accumulator, key) => {
11 | const {methodCall, transformValue} = map.get(key);
12 |
13 | accumulator.methodCalls.push(methodCall);
14 | accumulator.propLabels.push(key);
15 | accumulator.valueTransformations.push(transformValue);
16 |
17 | return accumulator;
18 | },
19 | {
20 | methodCalls: [],
21 | propLabels: [],
22 | valueTransformations: [],
23 | },
24 | );
25 | },
26 | };
27 |
28 | module.exports = methodCallUtil;
29 |
--------------------------------------------------------------------------------
/server/util/minifyUtil.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flood-UI/flood/769b5412b95f4f62d2b1085f935ed3cbc4bfe344/server/util/minifyUtil.js
--------------------------------------------------------------------------------
/server/util/numberUtils.js:
--------------------------------------------------------------------------------
1 | const truncateTo = (num, precision = 0) => {
2 | const factor = 10 ** precision;
3 | return Math.floor(num * factor) / factor;
4 | };
5 |
6 | module.exports = truncateTo;
7 |
--------------------------------------------------------------------------------
/server/util/rTorrentPropMap.js:
--------------------------------------------------------------------------------
1 | const RTORRENT_PROPS_MAP = {
2 | transferData: {
3 | uploadRate: 'throttle.global_up.rate',
4 | uploadTotal: 'throttle.global_up.total',
5 | uploadThrottle: 'throttle.global_up.max_rate',
6 | downloadRate: 'throttle.global_down.rate',
7 | downloadTotal: 'throttle.global_down.total',
8 | downloadThrottle: 'throttle.global_down.max_rate',
9 | },
10 | };
11 |
12 | module.exports = RTORRENT_PROPS_MAP;
13 |
--------------------------------------------------------------------------------
/server/views/error.pug:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= message
5 | h2= error.status
6 | pre #{error.stack}
7 |
--------------------------------------------------------------------------------
/server/views/layout.pug:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title= title
5 | body
6 | block content
7 |
--------------------------------------------------------------------------------
/shared/constants/diffActionTypes.js:
--------------------------------------------------------------------------------
1 | const diffActionTypes = ['ITEM_ADDED', 'ITEM_CHANGED', 'ITEM_REMOVED'];
2 |
3 | module.exports = diffActionTypes.reduce((memo, key) => {
4 | memo[key] = key;
5 |
6 | return memo;
7 | }, {});
8 |
--------------------------------------------------------------------------------
/shared/constants/historySnapshotTypes.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../util/objectUtil');
2 |
3 | const historySnapshotTypes = {
4 | FIVE_MINUTE: 'fiveMin',
5 | THIRTY_MINUTE: 'thirtyMin',
6 | HOUR: 'hour',
7 | WEEK: 'week',
8 | MONTH: 'month',
9 | YEAR: 'year',
10 | };
11 |
12 | module.exports = objectUtil.reflect(historySnapshotTypes);
13 |
--------------------------------------------------------------------------------
/shared/constants/serverEventTypes.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../util/objectUtil');
2 |
3 | const serverEventTypes = [
4 | 'CLIENT_CONNECTIVITY_STATUS_CHANGE',
5 | 'DISK_USAGE_CHANGE',
6 | 'NOTIFICATION_COUNT_CHANGE',
7 | 'TAXONOMY_FULL_UPDATE',
8 | 'TAXONOMY_DIFF_CHANGE',
9 | 'TORRENT_LIST_ACTION_TORRENT_ADDED',
10 | 'TORRENT_LIST_ACTION_TORRENT_DELETED',
11 | 'TORRENT_LIST_ACTION_TORRENT_DETAIL_UPDATED',
12 | 'TORRENT_LIST_DIFF_CHANGE',
13 | 'TORRENT_LIST_FULL_UPDATE',
14 | 'TRANSFER_HISTORY_FULL_UPDATE',
15 | 'TRANSFER_SUMMARY_DIFF_CHANGE',
16 | 'TRANSFER_SUMMARY_FULL_UPDATE',
17 | ];
18 |
19 | module.exports = objectUtil.createStringMapFromArray(serverEventTypes);
20 |
--------------------------------------------------------------------------------
/shared/constants/torrentFilePropsMap.js:
--------------------------------------------------------------------------------
1 | const torrentFilePropsMap = {
2 | props: ['path', 'pathComponents', 'priority', 'sizeBytes', 'sizeChunks', 'completedChunks'],
3 | methods: ['f.path=', 'f.path_components=', 'f.priority=', 'f.size_bytes=', 'f.size_chunks=', 'f.completed_chunks='],
4 | };
5 |
6 | module.exports = torrentFilePropsMap;
7 |
--------------------------------------------------------------------------------
/shared/constants/torrentPeerPropsMap.js:
--------------------------------------------------------------------------------
1 | const torrentPeerPropsMap = {
2 | props: [
3 | 'address',
4 | 'completedPercent',
5 | 'clientVersion',
6 | 'downloadRate',
7 | 'downloadTotal',
8 | 'uploadRate',
9 | 'uploadTotal',
10 | 'id',
11 | 'peerRate',
12 | 'peerTotal',
13 | 'isEncrypted',
14 | 'isIncoming',
15 | ],
16 | methods: [
17 | 'p.address=',
18 | 'p.completed_percent=',
19 | 'p.client_version=',
20 | 'p.down_rate=',
21 | 'p.down_total=',
22 | 'p.up_rate=',
23 | 'p.up_total=',
24 | 'p.id=',
25 | 'p.peer_rate=',
26 | 'p.peer_total=',
27 | 'p.is_encrypted=',
28 | 'p.is_incoming=',
29 | ],
30 | };
31 |
32 | module.exports = torrentPeerPropsMap;
33 |
--------------------------------------------------------------------------------
/shared/constants/torrentStatusMap.js:
--------------------------------------------------------------------------------
1 | const objectUtil = require('../util/objectUtil');
2 |
3 | const torrentStatusMap = objectUtil.reflect({
4 | ch: 'checking',
5 | sd: 'seeding',
6 | p: 'paused',
7 | c: 'complete',
8 | d: 'downloading',
9 | ad: 'activelyDownloading',
10 | au: 'activelyUploading',
11 | s: 'stopped',
12 | e: 'error',
13 | i: 'inactive',
14 | a: 'active',
15 | });
16 |
17 | torrentStatusMap.statusShorthand = ['ch', 'sd', 'p', 'c', 'd', 'ad', 'au', 's', 'e', 'i', 'a'];
18 |
19 | module.exports = torrentStatusMap;
20 |
--------------------------------------------------------------------------------
/shared/constants/torrentTrackerPropsMap.js:
--------------------------------------------------------------------------------
1 | const torrentTrackerPropsMap = {
2 | props: ['group', 'url', 'id', 'minInterval', 'normalInterval', 'type'],
3 | methods: ['t.group=', 't.url=', 't.id=', 't.min_interval=', 't.normal_interval=', 't.type='],
4 | };
5 |
6 | module.exports = torrentTrackerPropsMap;
7 |
--------------------------------------------------------------------------------
/shared/util/regEx.js:
--------------------------------------------------------------------------------
1 | const regEx = {
2 | url: /^(?:https?|ftp):\/\/.{1,}\.{1}.{1,}/,
3 | domainName: /(?:https?|udp):\/\/(?:www\.)?([-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,18}\b)*(\/[/\d\w.-]*)*(?:[?])*(.+)*/i,
4 | cdata: //,
5 | };
6 |
7 | module.exports = regEx;
8 |
--------------------------------------------------------------------------------
/shared/util/stringUtil.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | capitalize: string => string.charAt(0).toUpperCase() + string.slice(1),
3 |
4 | pluralize: (string, count) => {
5 | if (count !== 1) {
6 | if (string.charAt(string.length - 1) === 'y') {
7 | return `${string.substring(0, string.length - 1)}ies`;
8 | }
9 | return `${string}s`;
10 | }
11 |
12 | return string;
13 | },
14 |
15 | withoutTrailingSlash: input => input.replace(/\/{1,}$/, ''),
16 | };
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "preserve",
4 | "sourceMap": true,
5 | "target": "esnext",
6 | "moduleResolution": "node",
7 | "allowJs": true,
8 | "noEmit": true,
9 | "strict": true,
10 | "isolatedModules": true,
11 | "esModuleInterop": true,
12 | "baseUrl": "./",
13 | "paths": {
14 | "@shared/*": ["shared/*"]
15 | }
16 | },
17 | "include": ["./client/**/*.ts", "./client/**/*.tsx", "./server/**/*.ts", "./server/**/*.tsx", "./custom.d.ts"],
18 | "exclude": ["node_modules", "**/*.spec.ts"]
19 | }
20 |
--------------------------------------------------------------------------------