1
0
mirror of https://github.com/mgerb/go-discord-bot synced 2026-01-09 08:32:48 +00:00

add upload history to stats UI

This commit is contained in:
2018-10-20 13:53:02 -05:00
parent b004d4f29a
commit 81ecacd3d4
15 changed files with 149 additions and 7 deletions

View File

@@ -1,9 +1,9 @@
import './scss/index.scss';
import { Provider } from 'mobx-react';
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { Clips, Downloader, NotFound, Oauth, Soundboard, Stats, VideoArchive } from './pages';
import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, VideoArchive } from './pages';
import './scss/index.scss';
import { rootStoreInstance } from './stores';
import { Wrapper } from './wrapper';
@@ -19,6 +19,7 @@ const App: any = (): any => {
<Route path="/oauth" component={Oauth} />
<Route path="/stats" component={Stats} />
<Route path="/video-archive" component={VideoArchive} />
<Route path="/admin" component={Admin} />
<Route component={NotFound} />
</Switch>
</Wrapper>

View File

@@ -2,4 +2,5 @@ export * from './embedded-youtube/embedded-youtube';
export * from './header/header';
export * from './navbar/navbar';
export * from './sound-list/sound-list';
export * from './upload-history/upload-history';
export * from './uploader/uploader';

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { NavLink } from 'react-router-dom';
import { IClaims } from '../../model';
import { IClaims, Permissions } from '../../model';
import { OauthService, StorageService } from '../../services';
import './navbar.scss';
@@ -78,6 +78,10 @@ export class Navbar extends React.Component<Props, State> {
{this.renderNavLink('Youtube Downloader', '/downloader')}
{this.renderNavLink('Clips', '/clips')}
{this.renderNavLink('Stats', '/stats')}
{claims &&
claims.permissions &&
claims.permissions === Permissions.Admin &&
this.renderNavLink('Admin', '/admin')}
{this.renderLoginButton()}
{claims && claims.email && <div className="navbar__email">{claims.email}</div>}

View File

@@ -0,0 +1,46 @@
import * as _ from 'lodash';
import { DateTime } from 'luxon';
import React from 'react';
import { ISound } from '../../model';
interface IProps {
sounds: ISound[];
}
export const UploadHistory = ({ sounds }: IProps) => {
const sortedSounds = _.orderBy(sounds, 'created_at', 'desc');
return (
<div className="card">
<div className="card__header">Upload History</div>
<table className="table">
<thead>
<tr>
<th>Date</th>
<th>Sound</th>
<th className="hide-tiny">Ext</th>
<th>Username</th>
<th className="hide-tiny">Email</th>
</tr>
</thead>
<tbody>
{sortedSounds.map((s: ISound, i) => {
const formattedDate = DateTime.fromISO(s.created_at).toLocaleString();
return (
<tr key={i}>
<td title={formattedDate}>{formattedDate}</td>
<td title={s.name}>{s.name}</td>
<td className="hide-tiny" title={s.extension}>
{s.extension}
</td>
<td title={s.user.username}>{s.user.username}</td>
<td className="hide-tiny" title={s.user.email}>
{s.user.email}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
};

View File

@@ -1,3 +1,5 @@
export * from './claims';
export * from './permissions';
export * from './sound';
export * from './user';
export * from './video-archive';

12
client/app/model/sound.ts Normal file
View File

@@ -0,0 +1,12 @@
import { IUser } from './user';
export interface ISound {
created_at: string;
deleted_at?: string;
extension: string;
id: number;
name: string;
updated_at: string;
user: IUser;
user_id: string;
}

17
client/app/model/user.ts Normal file
View File

@@ -0,0 +1,17 @@
import { Permissions } from './permissions';
export interface IUser {
avatar: string;
bot: boolean;
created_at: string;
deleted_at?: string;
discriminator: string;
email: string;
id: string;
mfa_enabled: boolean;
permissions: Permissions;
token: string;
updated_at: string;
username: string;
verified: boolean;
}

View File

@@ -0,0 +1,11 @@
import React from 'react';
interface IProps {}
interface IState {}
export class Admin extends React.Component<IProps, IState> {
render() {
return <div className="content">TODO:</div>;
}
}

View File

@@ -0,0 +1 @@
export * from './admin';

View File

@@ -1,3 +1,4 @@
export * from './admin';
export * from './clips/clips';
export * from './downloader/downloader';
export * from './not-found/not-found';

View File

@@ -1,30 +1,45 @@
import { chain, map } from 'lodash';
import { inject, observer } from 'mobx-react';
import React, { Component } from 'react';
import { HorizontalBar } from 'react-chartjs-2';
import { chain, map } from 'lodash';
import { axios } from '../../services';
import { UploadHistory } from '../../components';
import { ISound } from '../../model';
import { axios, SoundService } from '../../services';
import { AppStore } from '../../stores';
import './stats.scss';
interface IProps {
appStore: AppStore;
}
interface IState {
data: {
username: string;
count: number;
}[];
sounds: ISound[];
}
/**
* a page to show discord chat statistics
* currently keeps track of number messages that contain external links
*/
export class Stats extends Component<any, IState> {
@inject('appStore')
@observer
export class Stats extends Component<IProps, IState> {
constructor(props: any) {
super(props);
this.state = {
data: [],
sounds: [],
};
}
componentDidMount() {
this.getdata();
SoundService.getSounds().then(sounds => {
this.setState({ sounds });
});
}
async getdata() {
@@ -59,12 +74,15 @@ export class Stats extends Component<any, IState> {
},
};
const { claims } = this.props.appStore;
return (
<div className="content">
<div className="card" style={{ maxWidth: '1000px' }}>
<div className="card">
<div className="card__header">Posts containing links</div>
<HorizontalBar data={data} />
</div>
{claims && <UploadHistory sounds={this.state.sounds} />}
</div>
);
}

View File

@@ -12,3 +12,4 @@
@import './input.scss';
@import './grid.scss';
@import './nprogress.scss';
@import './table.scss';

View File

@@ -71,3 +71,9 @@ body {
white-space: nowrap;
text-overflow: ellipsis;
}
.hide-tiny {
@include tinyScreen {
display: none;
}
}

View File

@@ -0,0 +1,14 @@
.table {
width: 100%;
thead {
text-align: left;
}
td,
th {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}

View File

@@ -1,10 +1,17 @@
import { SoundType } from '../components/sound-list/sound-list';
import { ISound } from '../model';
import { axios } from './axios.service';
const playSound = (sound: SoundType): Promise<any> => {
return axios.post('/api/sound/play', { name: sound.name });
};
const getSounds = async (): Promise<ISound[]> => {
const res = await axios.get('/api/sound');
return res.data.data;
};
export const SoundService = {
getSounds,
playSound,
};