From ea217200f1c42e4d4b142abc9abd55ca49535c49 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Wed, 19 Jul 2023 19:11:06 -0400 Subject: lots of changes, just need server endpoint before pull --- src/client/Network.ts | 3 +- src/client/util/reportManager/ReportManager.scss | 10 +- src/client/util/reportManager/ReportManager.tsx | 382 +++++---------------- .../util/reportManager/ReportManagerComponents.tsx | 137 +++++++- .../util/reportManager/reportManagerUtils.ts | 181 +++++++++- src/client/views/PropertiesButtons.tsx | 90 ++--- 6 files changed, 445 insertions(+), 358 deletions(-) (limited to 'src') diff --git a/src/client/Network.ts b/src/client/Network.ts index 70b51d036..39bf69e32 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -38,6 +38,7 @@ export namespace Networking { * with the mapping of guid to files as parameters. * * @param fileguidpairs the files and corresponding guids to be uploaded to the server + * @param browndash whether the endpoint should be invoked on the browndash server * @returns the response as a json from the server */ export async function UploadFilesToServer(fileguidpairs: FileGuidPair | FileGuidPair[], browndash?: boolean): Promise[]> { @@ -68,7 +69,7 @@ export namespace Networking { body: formData, }; - const endpoint = browndash ? 'http://10.38.71.246:1050/uploadFormData' : '/uploadFormData'; + const endpoint = browndash ? '[insert endpoint allowing local => browndash]' : '/uploadFormData'; const response = await fetch(endpoint, parameters); return response.json(); } diff --git a/src/client/util/reportManager/ReportManager.scss b/src/client/util/reportManager/ReportManager.scss index 4e80cbeeb..cd6a1d934 100644 --- a/src/client/util/reportManager/ReportManager.scss +++ b/src/client/util/reportManager/ReportManager.scss @@ -7,6 +7,12 @@ justify-content: space-between; align-items: center; + .header-btns { + display: flex; + align-items: center; + gap: 0.5rem; + } + h2 { margin: 0; padding: 0; @@ -53,12 +59,14 @@ } .report-textarea { + border: none; + outline: none; width: 100%; height: 80px; padding: 8px; resize: vertical; background: transparent; - // resize: none; + transition: border 0.3s ease; } .report-selects { diff --git a/src/client/util/reportManager/ReportManager.tsx b/src/client/util/reportManager/ReportManager.tsx index be46ba0a8..f20c2baaa 100644 --- a/src/client/util/reportManager/ReportManager.tsx +++ b/src/client/util/reportManager/ReportManager.tsx @@ -12,21 +12,17 @@ import { HiOutlineArrowLeft } from 'react-icons/hi'; import { Issue } from './reportManagerSchema'; import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; -import { Networking } from '../../Network'; import { MainViewModal } from '../../views/MainViewModal'; import { Octokit } from '@octokit/core'; -import { Button, IconButton, OrientationType, Type } from 'browndash-components'; -import { BugType, FileData, Priority, ViewState, darkColors, isLightText, lightColors } from './reportManagerUtils'; -import { IssueCard, IssueView, Tag } from './ReportManagerComponents'; +import { Button, Dropdown, DropdownType, IconButton, Type } from 'browndash-components'; +import { BugType, FileData, Priority, ReportForm, ViewState, bugDropdownItems, darkColors, emptyReportForm, formatTitle, getAllIssues, isDarkMode, lightColors, passesTagFilter, priorityDropdownItems, uploadFilesToServer } from './reportManagerUtils'; +import { Filter, FormInput, FormTextArea, IssueCard, IssueView, Tag } from './ReportManagerComponents'; import { StrCast } from '../../../fields/Types'; +import { MdRefresh } from 'react-icons/md'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; -// StrCast(Doc.UserDoc().userColor); -// StrCast(Doc.UserDoc().userBackgroundColor); -// StrCast(Doc.UserDoc().userVariantColor); - /** * Class for reporting and viewing Github issues within the app. */ @@ -85,44 +81,28 @@ export class ReportManager extends React.Component<{}> { }); // Form state - - @observable private bugTitle = ''; - @action setBugTitle = action((title: string) => { - this.bugTitle = title; - }); - @observable private bugDescription = ''; - @action setBugDescription = action((description: string) => { - this.bugDescription = description; + @observable private formData: ReportForm = emptyReportForm; + @action setFormData = action((newData: ReportForm) => { + this.formData = newData; }); - @observable private bugType = ''; - @action setBugType = action((type: string) => { - this.bugType = type; - }); - @observable private bugPriority = ''; - @action setBugPriority = action((priortiy: string) => { - this.bugPriority = priortiy; - }); - - @observable private mediaFiles: FileData[] = []; - @action private setMediaFiles = (files: FileData[]) => { - this.mediaFiles = files; - }; public close = action(() => (this.isOpen = false)); public open = action(async () => { this.isOpen = true; if (this.shownIssues.length === 0) { - this.setFetchingIssues(true); - try { - // load in the issues if not already loaded - const issues = (await this.getAllIssues()) as Issue[]; - // filtering to include only open issues and exclude pull requests, maybe add a separate tab for pr's? - this.setShownIssues(issues.filter(issue => issue.state === 'open' && !issue.pull_request)); - } catch (err) { - console.log(err); - } - this.setFetchingIssues(false); + this.updateIssues(); + } + }); + + @action updateIssues = action(async () => { + this.setFetchingIssues(true); + try { + const issues = (await getAllIssues(this.octokit)) as Issue[]; + this.setShownIssues(issues.filter(issue => issue.state === 'open' && !issue.pull_request)); + } catch (err) { + console.log(err); } + this.setFetchingIssues(false); }); constructor(props: {}) { @@ -135,169 +115,54 @@ export class ReportManager extends React.Component<{}> { }); } - /** - * Fethches issues from Github. - * @returns array of all issues - */ - public async getAllIssues(): Promise { - const res = await this.octokit.request('GET /repos/{owner}/{repo}/issues', { - owner: 'brown-dash', - repo: 'Dash-Web', - per_page: 80, - }); - - // 200 status means success - if (res.status === 200) { - return res.data; - } else { - throw new Error('Error getting issues'); - } - } - /** * Sends a request to Github to report a new issue with the form data. * @returns nothing */ public async reportIssue(): Promise { - if (this.bugTitle === '' || this.bugDescription === '' || this.bugType === '' || this.bugPriority === '') { + if (this.formData.title === '' || this.formData.description === '') { alert('Please fill out all required fields to report an issue.'); return; } + let formattedLinks: string[] = []; this.setSubmitting(true); - - const links = await this.uploadFilesToServer(); - console.log(links); - if (!links) { - // error uploading files to the server - return; + if (this.formData.mediaFiles.length > 0) { + const links = await uploadFilesToServer(this.formData.mediaFiles); + console.log(links); + if (!links) { + return; + } + formattedLinks = links; } - const formattedLinks = (links ?? []).map(this.fileLinktoServerLink); - // 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} ${formattedLinks.length > 0 && `\n\nFiles:\n${formattedLinks.join('\n')}`}`, - // labels: ['from-dash-app', this.bugType, this.bugPriority], - // }); + const req = await this.octokit.request('POST /repos/{owner}/{repo}/issues', { + owner: 'brown-dash', + repo: 'Dash-Web', + title: formatTitle(this.formData.title, Doc.CurrentUserEmail), + body: `${this.formData.description} ${formattedLinks.length > 0 ? `\n\nFiles:\n${formattedLinks.join('\n')}` : ''}`, + labels: ['from-dash-app', this.formData.type, this.formData.priority], + }); - // // 201 status means success - // if (req.status !== 201) { - // alert('Error creating issue on github.'); - // return; - // } + // 201 status means success + if (req.status !== 201) { + alert('Error creating issue on github.'); + return; + } // Reset fields - this.setBugTitle(''); - this.setBugDescription(''); - this.setMediaFiles([]); - this.setBugType(''); - this.setBugPriority(''); + this.setFormData(emptyReportForm); this.setSubmitting(false); - this.setFetchingIssues(true); - try { - // load in the issues if not already loaded - const issues = (await this.getAllIssues()) as Issue[]; - // filtering to include only open issues and exclude pull requests, maybe add a separate tab for pr's? - this.setShownIssues(issues.filter(issue => issue.state === 'open' && !issue.pull_request)); - } catch (err) { - console.log(err); - } - this.setFetchingIssues(false); + await this.updateIssues(); alert('Successfully submitted issue.'); } - /** - * Formats issue title. - * - * @param title title of issue - * @param userEmail email of issue submitter - * @returns formatted title - */ - private formatTitle = (title: string, userEmail: string): string => `${title} - ${userEmail.replace('@brown.edu', '')}`; - - // turns an upload link -> server link - // ex: - // C: /Users/dash/Documents/GitHub/Dash-Web/src/server/public/files/images/upload_8008dbc4b6424fbff14da7345bb32eb2.png - // -> https://browndash.com/files/images/upload_8008dbc4b6424fbff14da7345bb32eb2_l.png - private fileLinktoServerLink = (fileLink: string) => { - const serverUrl = 'https://browndash.com/'; - - const regex = 'public'; - const publicIndex = fileLink.indexOf(regex) + regex.length; - - const finalUrl = `${serverUrl}${fileLink.substring(publicIndex + 1).replace('.', '_l.')}`; - return finalUrl; - }; - - /** - * Gets the server file path. - * - * @param link response from file upload - * @returns server file path - */ - private getServerPath = (link: any): string => { - return link.result.accessPaths.agnostic.server as string; - }; - - /** - * Uploads media files to the server. - * @returns the server paths or undefined on error - */ - private uploadFilesToServer = async (): Promise => { - try { - // need to always upload to browndash - const links = await Networking.UploadFilesToServer( - this.mediaFiles.map(file => ({ file: file.file })), - true - ); - return (links ?? []).map(this.getServerPath); - } catch (err) { - if (err instanceof Error) { - alert(err.message); - } else { - alert(err); - } - } - }; - /** * Handles file upload. * * @param files uploaded files */ private onDrop = (files: File[]) => { - this.setMediaFiles([...this.mediaFiles, ...files.map(file => ({ _id: v4(), file }))]); - }; - - /** - * Returns when the issue passes the current filters. - * - * @param issue issue to check - * @returns boolean indicating whether the issue passes the current filters - */ - private passesTagFilter = (issue: Issue) => { - let passesPriority = true; - let passesBug = true; - if (this.priorityFilter) { - passesPriority = issue.labels.some(label => { - if (typeof label === 'string') { - return label === this.priorityFilter; - } else { - return label.name === this.priorityFilter; - } - }); - } - if (this.bugFilter) { - passesBug = issue.labels.some(label => { - if (typeof label === 'string') { - return label === this.bugFilter; - } else { - return label.name === this.bugFilter; - } - }); - } - return passesPriority && passesBug; + this.setFormData({ ...this.formData, mediaFiles: [...this.formData.mediaFiles, ...files.map(file => ({ _id: v4(), file }))] }); }; /** @@ -317,7 +182,7 @@ export class ReportManager extends React.Component<{}> { {`Preview
- } onClick={() => this.setMediaFiles(this.mediaFiles.filter(f => f._id !== fileData._id))} /> + } onClick={() => this.setFormData({ ...this.formData, mediaFiles: this.formData.mediaFiles.filter(f => f._id !== fileData._id) })} />
); @@ -331,7 +196,7 @@ export class ReportManager extends React.Component<{}> {
- } onClick={() => this.setMediaFiles(this.mediaFiles.filter(f => f._id !== fileData._id))} /> + } onClick={() => this.setFormData({ ...this.formData, mediaFiles: this.formData.mediaFiles.filter(f => f._id !== fileData._id) })} />
); @@ -340,7 +205,7 @@ export class ReportManager extends React.Component<{}> {
); @@ -352,94 +217,31 @@ export class ReportManager extends React.Component<{}> { * @returns the component that dispays all issues */ private viewIssuesComponent = () => { - const darkMode = isLightText(StrCast(Doc.UserDoc().userBackgroundColor)); + const darkMode = isDarkMode(StrCast(Doc.UserDoc().userBackgroundColor)); const colors = darkMode ? darkColors : lightColors; - const isTagDarkMode = isLightText(StrCast(Doc.UserDoc().userVariantColor)); - const activeTagTextColor = isTagDarkMode ? darkColors.text : lightColors.text; return (

Open Issues

-
- { - this.setQuery(e.target.value); - }} - required - /> -
-
- { - this.setPriorityFilter(null); - }} - fontSize="12px" - backgroundColor={this.priorityFilter === null ? StrCast(Doc.UserDoc().userVariantColor) : 'transparent'} - color={this.priorityFilter === null ? activeTagTextColor : colors.textGrey} - border - borderColor={this.priorityFilter === null ? StrCast(Doc.UserDoc().userVariantColor) : colors.border} - /> - {Object.values(Priority).map(p => { - return ( - { - this.setPriorityFilter(p); - }} - fontSize="12px" - backgroundColor={this.priorityFilter === p ? StrCast(Doc.UserDoc().userVariantColor) : 'transparent'} - color={this.priorityFilter === p ? activeTagTextColor : colors.textGrey} - border - borderColor={this.priorityFilter === p ? StrCast(Doc.UserDoc().userVariantColor) : colors.border} - /> - ); - })} -
-
- + } onClick={this.updateIssues} /> +
+ +
+ this.setPriorityFilter(p)} /> + this.setBugFilter(b)} /> +
{this.fetchingIssues ? (
@@ -448,7 +250,7 @@ export class ReportManager extends React.Component<{}> { ) : ( this.shownIssues .filter(issue => issue.title.toLowerCase().includes(this.query)) - .filter(issue => this.passesTagFilter(issue)) + .filter(issue => passesTagFilter(issue, this.priorityFilter, this.bugFilter)) .map(issue => ( { * @returns the form component for submitting issues */ private reportIssueComponent = () => { - const darkMode = isLightText(StrCast(Doc.UserDoc().userBackgroundColor)); + const darkMode = isDarkMode(StrCast(Doc.UserDoc().userBackgroundColor)); const colors = darkMode ? darkColors : lightColors; return ( @@ -502,38 +304,37 @@ export class ReportManager extends React.Component<{}> {
- this.setBugTitle(e.target.value)} required /> + this.setFormData({ ...this.formData, title: val })} />
-