diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/ReportManager.tsx | 168 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/topbar/TopBar.tsx | 6 |
3 files changed, 176 insertions, 0 deletions
diff --git a/src/client/util/ReportManager.tsx b/src/client/util/ReportManager.tsx new file mode 100644 index 000000000..be58da29a --- /dev/null +++ b/src/client/util/ReportManager.tsx @@ -0,0 +1,168 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { ColorState, SketchPicker } from 'react-color'; +import { Doc } from '../../fields/Doc'; +import { Id } from '../../fields/FieldSymbols'; +import { BoolCast, Cast, StrCast } from '../../fields/Types'; +import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils'; +import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; +import { DocServer } from '../DocServer'; +import { Networking } from '../Network'; +import { MainViewModal } from '../views/MainViewModal'; +import { FontIconBox } from '../views/nodes/button/FontIconBox'; +import { DragManager } from './DragManager'; +import { GroupManager } from './GroupManager'; +import './SettingsManager.scss'; +import { undoBatch } from './UndoManager'; +import { Octokit } from "@octokit/core"; +import { CheckBox } from '../views/search/CheckBox'; +const higflyout = require('@hig/flyout'); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; + +@observer +export class ReportManager extends React.Component<{}> { + public static Instance: ReportManager; + @observable private isOpen = false; + + private octokit: Octokit; + + @observable public issues: any[] = []; + @action setIssues = action((issues: any[]) => { this.issues = issues; }); + + @observable public shownIssues = this.issues.filter(issue => issue.state === 'open'); + + public updateIssueSearch = action((query: string = '') => { + if (query === '') { + this.shownIssues = this.issues.filter(issue => issue.state === 'open'); + return; + } + this.shownIssues = this.issues.filter(issue => issue.title.toLowerCase().includes(query.toLowerCase())); + }); + + constructor(props: {}) { + super(props); + ReportManager.Instance = this; + + this.octokit = new Octokit({ + auth: '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' + }); + } + + public close = action(() => (this.isOpen = false)); + public open = action(() => { + if (this.issues.length === 0) { + // load in the issues if not already loaded + this.getAllIssues() + .then(issues => { + this.setIssues(issues); + this.updateIssueSearch(); + }) + .catch(err => console.log(err)); + } + (this.isOpen = true) + }); + + private bugTitle = ''; + private bugDescription = ''; + + // private toGithub = false; + // will always be set to true - no alterntive option yet + private toGithub = true; + + private formatTitle = (title: string, userEmail: string) => `${title} - ${userEmail.replace('@brown.edu', '')}`; + + public async getAllIssues() : Promise<any[]> { + const res = await this.octokit.request('GET /repos/{owner}/{repo}/issues', { + owner: 'brown-dash', + repo: 'Dash-Web', + }); + + // 200 status means success + if (res.status === 200) { + return res.data; + } else { + throw new Error('Error getting issues'); + } + } + + public async reportIssue() { + if (this.toGithub) { + const req = await this.octokit.request('POST /repos/{owner}/{repo}/issues', { + owner: 'brown-dash', + repo: 'Dash-Web', + title: this.formatTitle(this.bugTitle, Doc.CurrentUserEmail), + body: this.bugDescription, + labels: [ + 'from-dash-app', + ] + }); + + // 201 status means success + if (req.status !== 201) { + alert('Error creating issue on github.'); + // on error, don't close the modal + return; + } + } + else { + // if not going to github issues, not sure what to do yet... + } + + // if we're down here, then we're good to go. + this.bugTitle = ''; + this.bugDescription = ''; + this.toGithub = false; + this.close(); + } + + private get reportInterface() { + + return ( + <div className="settings-interface"> + <div className="settings-panel"> + <input type="text" placeholder='issue name' onChange={(e => this.updateIssueSearch(e.target.value))}></input> + <h3>Previous Issues</h3> + {this.issues.length === 0 ? <div>loading</div> : this.shownIssues.map(issue => <div key={issue.number}>{issue.title}</div>)} + + <div className="settings-user"> + <button onClick={() => this.getAllIssues().then(issues => this.issues = issues)}>Poll Issues</button> + </div> + </div> + <div className="close-button" onClick={this.close}> + <FontAwesomeIcon icon={'times'} color="black" size={'lg'} /> + </div> + + <div className="settings-content"> + <h3 style={{ 'textDecoration': 'underline'}}>Report an Issue</h3> + <label>Please leave a title for the bug.</label><br /> + <input type="text" placeholder='title' onChange={(e) => this.bugTitle = e.target.value} /> + <br /> + <label>Please leave a description for the bug and how it can be recreated.</label> + <textarea placeholder='description' onChange={(e) => this.bugDescription = e.target.value}/> + <br /><br /> + {/* <label>Send to github issues? </label> + <input type="checkbox" onChange={(e) => this.toGithub = e.target.checked} /> + <br /> */} + <button onClick={() => this.reportIssue()}>Submit</button> + </div> + + + </div> + ); + } + + render() { + return ( + <MainViewModal + contents={this.reportInterface} + isDisplayed={this.isOpen} + interactive={true} + closeOnExternalClick={this.close} + dialogueBoxStyle={{ width: '500px', height: '500px', background: Cast(Doc.SharingDoc().userColor, 'string', null) }} + /> + ); + } +} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index e96f65548..a8c8fedaa 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -20,6 +20,7 @@ import { DocumentManager } from '../util/DocumentManager'; import { GroupManager } from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; import { Hypothesis } from '../util/HypothesisUtils'; +import { ReportManager } from '../util/ReportManager'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { SelectionManager } from '../util/SelectionManager'; import { ColorScheme, SettingsManager } from '../util/SettingsManager'; @@ -974,6 +975,7 @@ export class MainView extends React.Component { <DictationOverlay /> <SharingManager /> <SettingsManager /> + <ReportManager /> <CaptureManager /> <GroupManager /> <GoogleAuthenticationManager /> diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 3fc0a237e..cbcfed06f 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -1,5 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; +import { MdBugReport } from 'react-icons/md'; import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -18,6 +19,7 @@ import { DashboardView } from '../DashboardView'; import { Borders, Colors } from '../global/globalEnums'; import { MainView } from '../MainView'; import './TopBar.scss'; +import { ReportManager } from '../../util/ReportManager'; /** * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user @@ -31,6 +33,7 @@ export class TopBar extends React.Component { DashboardView.closeActiveDashboard(); // bcz: if we do this, we need some other way to keep track, for user convenience, of the last dashboard in use }); }; + render() { const activeDashboard = Doc.ActiveDashboard; return ( @@ -92,6 +95,9 @@ export class TopBar extends React.Component { {GetEffectiveAcl(Doc.GetProto(Doc.ActiveDashboard)) === AclAdmin ? 'Share' : 'view original'} </div> ) : null} + <div className="topbar-button-icon" onClick={() => ReportManager.Instance.open()}> + <MdBugReport /> + </div> <div className="topbar-button-icon" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')}> <FontAwesomeIcon icon="question-circle" /> </div> |