diff --git a/frontend/app/components/Session_/Issues/ActiveIssueClose.js b/frontend/app/components/Session_/Issues/ActiveIssueClose.js
deleted file mode 100644
index c51bd326e..000000000
--- a/frontend/app/components/Session_/Issues/ActiveIssueClose.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import { connect } from 'react-redux';
-import { Button } from 'UI';
-import { resetActiveIsue } from 'Duck/issues';
-
-const ActiveIssueClose = ({ resetActiveIsue }) => {
- return (
-
-
-
- );
-};
-
-export default connect(null, {
- resetActiveIsue
-})(ActiveIssueClose);
diff --git a/frontend/app/components/Session_/Issues/ActivityList.js b/frontend/app/components/Session_/Issues/ActivityList.js
deleted file mode 100644
index 361477d54..000000000
--- a/frontend/app/components/Session_/Issues/ActivityList.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-
-class ActivityList extends React.Component {
- render() {
- return (
-
- Hello
-
- );
- }
-}
-
-export default ActivityList;
diff --git a/frontend/app/components/Session_/Issues/AuthoAvatar.js b/frontend/app/components/Session_/Issues/AuthoAvatar.js
deleted file mode 100644
index 59ce52864..000000000
--- a/frontend/app/components/Session_/Issues/AuthoAvatar.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import cn from 'classnames';
-
-const AuthorAvatar = ({ className, imgUrl, width = 32, height = 32 }) => {
- return (
-
-

-
- );
-};
-
-export default AuthorAvatar;
diff --git a/frontend/app/components/Session_/Issues/ContentRender.js b/frontend/app/components/Session_/Issues/ContentRender.js
deleted file mode 100644
index c09b0b517..000000000
--- a/frontend/app/components/Session_/Issues/ContentRender.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import React from 'react';
-
-import { CodeBlock } from 'UI';
-
-import stl from './contentRender.module.css';
-
-const elType = {
- PARAGRAPH: 'paragraph',
- TEXT: 'text',
- QUOTE: 'blockquote',
- CODE_BLOCK: 'codeBlock',
- MENTION: 'mention',
- RULE: 'rule',
- HARD_BREAK: 'hardBreak',
-};
-
-const renderElement = (el, provider) => {
- if (provider === 'github') return el;
-
- switch (el.type) {
- case elType.PARAGRAPH:
- return (
-
-
-
- );
- case elType.QUOTE:
- return (
-
-
-
- );
- case elType.CODE_BLOCK:
- return (
-
- );
- // return
- case elType.MENTION:
- return {`@${el.attrs.text}`};
- case elType.RULE:
- return
;
- case elType.HARD_BREAK:
- return
;
- case elType.RULE:
- return
;
- case elType.TEXT:
- return el.text;
- }
- return ;
-};
-
-const codeRender = (content) => content.map((el) => el.text);
-
-const ContentRender = (props) => {
- const { message, provider } = props;
- return (
-
- {provider === 'github'
- ? message
- : message &&
- message.content &&
- message.content.map((el) => (
- {renderElement(el, provider)}
- ))}
-
- );
-};
-
-export default ContentRender;
diff --git a/frontend/app/components/Session_/Issues/IssueComment.js b/frontend/app/components/Session_/Issues/IssueComment.js
deleted file mode 100644
index a3071ff82..000000000
--- a/frontend/app/components/Session_/Issues/IssueComment.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import { checkRecentTime } from 'App/date';
-import AuthorAvatar from './AuthoAvatar';
-import ContentRender from './ContentRender';
-
-const IssueComment = ({ activity, provider }) => {
- return (
-
-
-
-
- { activity.user && activity.user.name }
- { activity.createdAt && checkRecentTime(activity.createdAt) }
-
-
{ }
-
-
- );
-};
-
-export default IssueComment;
diff --git a/frontend/app/components/Session_/Issues/IssueCommentForm.js b/frontend/app/components/Session_/Issues/IssueCommentForm.js
deleted file mode 100644
index ac688205b..000000000
--- a/frontend/app/components/Session_/Issues/IssueCommentForm.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from 'react';
-import { connect } from 'react-redux';
-import { Input, Button, Form } from 'UI';
-import { addMessage } from 'Duck/assignments';
-
-class IssueCommentForm extends React.PureComponent {
- state = { comment: '' }
-
- write = (e) => {
- e.stopPropagation();
- const { target: { name, value } } = e
- this.setState({ comment: value });
- }
-
- addComment = () => {
- const { comment } = this.state;
- const { sessionId, issueId, addMessage, loading } = this.props;
- if (loading) return;
-
- addMessage(sessionId, issueId, { message: comment, type: 'message' }).then(() => {
- this.setState({comment: ''});
- })
- }
-
- render() {
- const { comment } = this.state;
- const { loading } = this.props;
-
- return (
-
- );
- }
-};
-
-export default connect(state => ({
- loading: state.getIn(['assignments', 'addMessage', 'loading'])
-}), { addMessage })(IssueCommentForm)
diff --git a/frontend/app/components/Session_/Issues/IssueDescription.js b/frontend/app/components/Session_/Issues/IssueDescription.js
deleted file mode 100644
index 9087df233..000000000
--- a/frontend/app/components/Session_/Issues/IssueDescription.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import ContentRender from './ContentRender';
-
-const IssueDescription = ({ className, description, provider }) => {
- return (
-
-
Description
-
-
- );
-};
-
-export default IssueDescription;
diff --git a/frontend/app/components/Session_/Issues/IssueDetails.js b/frontend/app/components/Session_/Issues/IssueDetails.js
deleted file mode 100644
index f2f8f5d0c..000000000
--- a/frontend/app/components/Session_/Issues/IssueDetails.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import { connect } from 'react-redux';
-import React from 'react';
-import cn from 'classnames';
-import { Loader } from 'UI';
-import IssueHeader from './IssueHeader';
-import IssueCommentForm from './IssueCommentForm';
-import IssueComment from './IssueComment';
-import stl from './issueDetails.module.css';
-import IssueDescription from './IssueDescription';
-
-class IssueDetails extends React.PureComponent {
- state = { searchQuery: ''}
-
- write = (e, { name, value }) => this.setState({ [ name ]: value });
-
- render() {
- const { sessionId, issue, loading, users, issueTypeIcons, issuesIntegration } = this.props;
- const activities = issue.activities;
- const provider = issuesIntegration.provider;
- const assignee = users.filter(({id}) => issue.assignee === id).first();
-
- return (
-
-
-
-
-
-
-
- { activities.size > 0 &&
Comments
}
- { activities.map(activity => (
-
- ))}
-
-
-
-
-
- );
- }
-}
-
-export default connect(state => ({
- users: state.getIn(['assignments', 'users']),
- loading: state.getIn(['assignments', 'fetchAssignment', 'loading']),
- issueTypeIcons: state.getIn(['assignments', 'issueTypeIcons']),
- issuesIntegration: state.getIn([ 'issues', 'list'])[0] || {},
-}))(IssueDetails);
diff --git a/frontend/app/components/Session_/Issues/IssueForm.js b/frontend/app/components/Session_/Issues/IssueForm.js
index 248fd478c..d9ec41e39 100644
--- a/frontend/app/components/Session_/Issues/IssueForm.js
+++ b/frontend/app/components/Session_/Issues/IssueForm.js
@@ -1,182 +1,178 @@
+import { observer } from 'mobx-react-lite';
import React from 'react';
-import { connect } from 'react-redux';
-import { Form, Input, Button, CircularLoader, Loader } from 'UI';
-import { addActivity, init, edit, fetchAssignments, fetchMeta } from 'Duck/assignments';
+
+import { useStore } from 'App/mstore';
+import { Button, CircularLoader, Form, Input, Loader } from 'UI';
+
import Select from 'Shared/Select';
const SelectedValue = ({ icon, text }) => {
return (
- {/*

*/}
{icon}
{text}
);
};
-class IssueForm extends React.PureComponent {
- componentDidMount() {
- const { projects, issueTypes } = this.props;
- this.props.init({
+function IssueForm(props) {
+ const { closeHandler } = props;
+ const { issueReportingStore } = useStore();
+ const creating = issueReportingStore.createLoading;
+ const projects = issueReportingStore.projects;
+ const projectsLoading = issueReportingStore.projectsLoading;
+ const users = issueReportingStore.users;
+ const instance = issueReportingStore.instance;
+ const metaLoading = issueReportingStore.metaLoading;
+ const issueTypes = issueReportingStore.issueTypes;
+ const addActivity = issueReportingStore.saveIssue;
+ const init = issueReportingStore.init;
+ const edit = issueReportingStore.editInstance;
+ const fetchMeta = issueReportingStore.fetchMeta;
+
+ console.log(users, instance, projects, issueTypes)
+ React.useEffect(() => {
+ init({
projectId: projects[0] ? projects[0].id : '',
issueType: issueTypes[0] ? issueTypes[0].id : '',
});
- }
+ }, []);
- componentWillReceiveProps(newProps) {
- const { instance } = this.props;
- if (newProps.instance.projectId && newProps.instance.projectId != instance.projectId) {
- this.props.fetchMeta(newProps.instance.projectId).then(() => {
- this.props.edit({ issueType: '', assignee: '', projectId: newProps.instance.projectId });
+ React.useEffect(() => {
+ if (instance?.projectId) {
+ fetchMeta(instance?.projectId).then(() => {
+ edit({
+ issueType: '',
+ assignee: '',
+ projectId: instance?.projectId,
+ });
});
}
- }
+ }, [instance?.projectId]);
- onSubmit = () => {
- const { sessionId, addActivity } = this.props;
- const { instance } = this.props;
-
- addActivity(sessionId, instance.toJS()).then(() => {
- const { errors } = this.props;
+ const onSubmit = () => {
+ const { sessionId } = props;
+ addActivity(sessionId, instance).then(() => {
+ const { errors } = props;
if (!errors || errors.length === 0) {
- this.props.init({ projectId: instance.projectId });
- this.props.fetchAssignments(sessionId);
- this.props.closeHandler();
+ init({ projectId: instance?.projectId });
+ closeHandler();
}
});
};
- write = (e) => {
+ const write = (e) => {
const {
target: { name, value },
} = e;
- this.props.edit({ [name]: value });
+ edit({ [name]: value });
};
- writeOption = ({ name, value }) => this.props.edit({ [name]: value.value });
- render() {
- const {
- creating,
- projects,
- users,
- issueTypes,
- instance,
- closeHandler,
- metaLoading,
- projectsLoading,
- } = this.props;
- const projectOptions = projects.map(({ name, id }) => ({ label: name, value: id })).toArray();
- const userOptions = users.map(({ name, id }) => ({ label: name, value: id })).toArray();
+ const writeOption = ({ name, value }) => edit({ [name]: value.value });
+ const projectOptions = projects.map(({ name, id }) => ({
+ label: name,
+ value: id,
+ }));
+ const userOptions = users.map(({ name, id }) => ({ label: name, value: id }));
- const issueTypeOptions = issueTypes.map(({ name, id, iconUrl, color }) => {
- return { label: name, value: id, iconUrl, color };
- });
+ const issueTypeOptions = issueTypes.map(({ name, id, iconUrl, color }) => {
+ return { label: name, value: id, iconUrl, color };
+ });
- const selectedIssueType = issueTypes.filter((issue) => issue.id == instance.issueType)[0];
+ const selectedIssueType = issueTypes.filter(
+ (issue) => issue.id == instance?.issueType
+ )[0];
- return (
-
-
-
-
-
-
-
-
- ) : (
- ''
- )
- }
- />
-
+ return (
+
+
+
+
+
+
+
+
+ ) : (
+ ''
+ )
+ }
+ />
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
- );
- }
+
+
+
+
+ );
}
-export default connect(
- (state) => ({
- creating: state.getIn(['assignments', 'addActivity', 'loading']),
- projects: state.getIn(['assignments', 'projects']),
- projectsLoading: state.getIn(['assignments', 'fetchProjects', 'loading']),
- users: state.getIn(['assignments', 'users']),
- instance: state.getIn(['assignments', 'instance']),
- metaLoading: state.getIn(['assignments', 'fetchMeta', 'loading']),
- issueTypes: state.getIn(['assignments', 'issueTypes']),
- errors: state.getIn(['assignments', 'addActivity', 'errors']),
- }),
- { addActivity, init, edit, fetchAssignments, fetchMeta }
-)(IssueForm);
+export default observer(IssueForm);
diff --git a/frontend/app/components/Session_/Issues/IssueHeader.js b/frontend/app/components/Session_/Issues/IssueHeader.js
deleted file mode 100644
index 6d666382b..000000000
--- a/frontend/app/components/Session_/Issues/IssueHeader.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import { Icon } from 'UI';
-
-const GotoSessionLink = props => (
-
- {'Go to session'}
-
-
-)
-
-const IssueHeader = ({issue, typeIcon, assignee}) => {
- return (
-
- {/*
*/}
- {/*
*/}
-
- { typeIcon }
- {/*

*/}
-
{ issue.id }
- {/*
{ '@ 00:13 Secs'}
*/}
- { assignee &&
-
- {'Assigned to'}
- { assignee.name }
-
- }
-
-
{issue.title}
-
- );
-};
-
-export default IssueHeader;
diff --git a/frontend/app/components/Session_/Issues/IssueListItem.js b/frontend/app/components/Session_/Issues/IssueListItem.js
deleted file mode 100644
index c0e561a33..000000000
--- a/frontend/app/components/Session_/Issues/IssueListItem.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import cn from 'classnames';
-import { Tooltip } from 'UI';
-import stl from './issueListItem.module.css';
-
-const IssueListItem = ({ issue, onClick, icon, user, active }) => {
- return (
- onClick(issue)}
- className={cn(
- stl.wrapper,
- active ? 'active-bg' : '',
- 'flex flex-col justify-between cursor-pointer text-base text-gray-800'
- )}
- >
-
-
- {icon}
- {issue.id}
-
-
- {user && (
-
-
-
- )}
-
-
-
{issue.title}
-
- );
-};
-
-export default IssueListItem;
diff --git a/frontend/app/components/Session_/Issues/Issues.js b/frontend/app/components/Session_/Issues/Issues.js
index db5671454..29eb3bd78 100644
--- a/frontend/app/components/Session_/Issues/Issues.js
+++ b/frontend/app/components/Session_/Issues/Issues.js
@@ -1,81 +1,56 @@
+import { Button, Tooltip } from 'antd';
+import { observer } from 'mobx-react-lite';
import React from 'react';
+import { useStore } from 'App/mstore';
+import { Icon, Popover } from 'UI';
import { connect } from 'react-redux';
-import { Popover, Icon } from 'UI';
import IssuesModal from './IssuesModal';
-import { fetchProjects, fetchMeta } from 'Duck/assignments';
-import { Tooltip, Button } from 'antd';
-@connect(
- (state) => ({
- issues: state.getIn(['assignments', 'list']),
- metaLoading: state.getIn(['assignments', 'fetchMeta', 'loading']),
- projects: state.getIn(['assignments', 'projects']),
- projectsFetched: state.getIn(['assignments', 'projectsFetched']),
- activeIssue: state.getIn(['assignments', 'activeIssue']),
- fetchIssueLoading: state.getIn(['assignments', 'fetchAssignment', 'loading']),
- fetchIssuesLoading: state.getIn(['assignments', 'fetchAssignments', 'loading']),
- projectsLoading: state.getIn(['assignments', 'fetchProjects', 'loading']),
- issuesIntegration: state.getIn(['issues', 'list']) || {},
- issuesFetched: state.getIn(['issues', 'issuesFetched']),
- }),
- { fetchMeta, fetchProjects }
-)
-class Issues extends React.Component {
- state = { showModal: false };
+function Issues(props) {
+ const { issueReportingStore } = useStore();
- constructor(props) {
- super(props);
- this.state = { showModal: false };
- }
-
- closeModal = () => {
- this.setState({ showModal: false });
- };
-
- showIssuesList = (e) => {
- e.preventDefault();
- e.stopPropagation();
- this.setState({ showModal: true });
- };
-
- handleOpen = () => {
- this.setState({ showModal: true });
- if (!this.props.projectsFetched) {
- // cache projects fetch
- this.props.fetchProjects().then(
- function () {
- const { projects } = this.props;
- if (projects && projects.first()) {
- this.props.fetchMeta(projects.first().id);
- }
- }.bind(this)
- );
+ const handleOpen = () => {
+ issueReportingStore.init();
+ if (!issueReportingStore.projectsFetched) {
+ issueReportingStore.fetchProjects().then((projects) => {
+ if (projects && projects[0]) {
+ void issueReportingStore.fetchMeta(projects[0].id);
+ }
+ });
}
};
- render() {
- const { sessionId, issuesIntegration } = this.props;
- const provider = issuesIntegration.first()?.provider || '';
+ const { sessionId, issuesIntegration } = props;
+ const provider = issuesIntegration[0]?.provider || '';
- return (
- (
-
-
-
- )}
- >
+ console.log(provider, sessionId, issuesIntegration)
+ return (
+ (
-
-
-
+
-
- );
- }
+ )}
+ >
+
+
+
+
+
+
+ );
}
-export default Issues;
+export default connect((state) => ({
+ issuesIntegration: state.getIn(['issues', 'list']) || {},
+ issuesFetched: state.getIn(['issues', 'issuesFetched']),
+}))(observer(Issues));
diff --git a/frontend/app/components/Session_/Issues/IssuesModal.js b/frontend/app/components/Session_/Issues/IssuesModal.js
index c1a0d0724..5bd4be5eb 100644
--- a/frontend/app/components/Session_/Issues/IssuesModal.js
+++ b/frontend/app/components/Session_/Issues/IssuesModal.js
@@ -7,12 +7,10 @@ import store from 'App/store';
const IssuesModal = ({
sessionId,
closeHandler,
- provider
}) => {
return (
- {/* */}
Create Issue
diff --git a/frontend/app/components/Session_/Issues/contentRender.module.css b/frontend/app/components/Session_/Issues/contentRender.module.css
deleted file mode 100644
index d18d50630..000000000
--- a/frontend/app/components/Session_/Issues/contentRender.module.css
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-.codeMirror > div {
- border: 1px solid #eee;
- height: auto;
-}
-
-.para {
- padding: 3px 0;
-}
-.mention {
- font-weight: 500;
- margin-right: 5px;
-}
-
-.quote {
- padding: 5px;
- padding-left: 10px;
- border-left: solid 2px $gray-light;
- color: $gray-dark;
- margin: 5px 0;
- margin-left: 10px;
-}
-
-.code {
- background-color: lightgray;
- padding: 2px 5px;
-}
-
-.rule {
- margin: 6px 0;
-}
\ No newline at end of file
diff --git a/frontend/app/components/Session_/Issues/index.js b/frontend/app/components/Session_/Issues/index.js
index 161b5b097..36cf3fdd9 100644
--- a/frontend/app/components/Session_/Issues/index.js
+++ b/frontend/app/components/Session_/Issues/index.js
@@ -1,2 +1 @@
-export { defualt as Issues } from './Issues';
-export { defualt as IssueModal } from './IssuesModal';
\ No newline at end of file
+export { defualt as Issues } from './Issues';
\ No newline at end of file
diff --git a/frontend/app/components/Session_/Issues/issueDetails.module.css b/frontend/app/components/Session_/Issues/issueDetails.module.css
deleted file mode 100644
index 40d132a04..000000000
--- a/frontend/app/components/Session_/Issues/issueDetails.module.css
+++ /dev/null
@@ -1,8 +0,0 @@
-.activitiesList {
- max-height: calc(100vh - 186px);
- overflow-y: auto;
-
- &::-webkit-scrollbar {
- width: 4px;
- }
-}
\ No newline at end of file
diff --git a/frontend/app/components/Session_/Issues/issueHeader.module.css b/frontend/app/components/Session_/Issues/issueHeader.module.css
deleted file mode 100644
index e69de29bb..000000000
diff --git a/frontend/app/components/Session_/Issues/issueListItem.module.css b/frontend/app/components/Session_/Issues/issueListItem.module.css
deleted file mode 100644
index 73ed34c6f..000000000
--- a/frontend/app/components/Session_/Issues/issueListItem.module.css
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-.title {
- max-width: 90%;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.wrapper {
- transition: all 0.4s;
- padding: 8px 14px;
- /* margin: 0 -14px; */
- height: 70px;
- background-color: white;
- border-bottom: solid thin $gray-light;
- &:hover {
- background-color: $active-blue;
- transition: all 0.2s;
- }
-}
\ No newline at end of file
diff --git a/frontend/app/components/Session_/Issues/issuesModal.stories.js b/frontend/app/components/Session_/Issues/issuesModal.stories.js
deleted file mode 100644
index 60769df9f..000000000
--- a/frontend/app/components/Session_/Issues/issuesModal.stories.js
+++ /dev/null
@@ -1,300 +0,0 @@
-import { storiesOf } from '@storybook/react';
-import { List } from 'immutable';
-import IssuesModal from './IssuesModal';
-import IssueHeader from './IssueHeader';
-import IssueComment from './IssueComment';
-import IssueCommentForm from './IssueCommentForm';
-import IssueDetails from './IssueDetails';
-import IssueForm from './IssueForm';
-import IssueListItem from './IssueListItem';
-import IssueDescription from './IssueDescription';
-
-const description = {
- "version": 1,
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "test para"
- }
- ]
- },
- {
- "type": "blockquote",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "test quote"
- }
- ]
- }
- ]
- },
- {
- "type": "rule"
- },
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "another para"
- }
- ]
- },
- {
- "type": "paragraph",
- "content": []
- },
- {
- "type": "paragraph",
- "content": []
- },
- {
- "type": "codeBlock",
- "attrs": {},
- "content": [
- {
- "type": "text",
- "text": "var d = \"test code\"\nvar e = \"test new line\""
- }
- ]
- },
- {
- "type": "paragraph",
- "content": []
- }
- ]
-}
-const issueTypeIcons = {
- '1': 'https://openreplay.atlassian.net/secure/viewavatar?size=medium&avatarId=10310&avatarType=issuetype',
-}
-const issueTypes = [
- {
- id: 1,
- iconUrl: 'https://openreplay.atlassian.net/secure/viewavatar?size=medium&avatarId=10310&avatarType=issuetype',
- name: 'Improvement'
- },
- {
- id: 2,
- iconUrl: 'https://openreplay.atlassian.net/secure/viewavatar?size=medium&avatarId=10310&avatarType=issuetype',
- name: 'Bug'
- }
-]
-const user = {
- id: 1,
- name: 'test',
- avatarUrls: {
- "16x16": "https://secure.gravatar.com/avatar/900294aa68b33490b16615b57e9709fc?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FMO-3.png&size=16&s=16",
- "24x24": "https://secure.gravatar.com/avatar/900294aa68b33490b16615b57e9709fc?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FMO-3.png&size=24&s=24"
- }
-}
-const activities = [
- {
- id: 1,
- message: {
- "version": 1,
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "First Para"
- }
- ]
- },
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "Second para"
- }
- ]
- },
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "Third para",
- "marks": [
- {
- "type": "strong"
- }
- ]
- }
- ]
- },
- {
- "type": "blockquote",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "Quote"
- }
- ]
- }
- ]
- },
- {
- "type": "paragraph",
- "content": []
- },
- {
- "type": "codeBlock",
- "attrs": {},
- "content": [
- {
- "type": "text",
- "text": "alert('test')\nvar dd = \"Another line\""
- }
- ]
- },
- {
- "type": "rule"
- },
- {
- "type": "paragraph",
- "content": [
- {
- "type": "mention",
- "attrs": {
- "id": "5d8398868a50e80c2feed3f6",
- "text": "Someone"
- }
- },
- {
- "type": "text",
- "text": " "
- }
- ]
- },
- {
- "type": "paragraph",
- "content": []
- },
- {
- "type": "codeBlock",
- "attrs": {
- "language": "javascript"
- },
- "content": [
- {
- "type": "text",
- "text": "var d = \"test\""
- }
- ]
- },
- {
- "type": "paragraph",
- "content": []
- }
- ]
- },
- author: 1,
- user: user
- },
- {
- id: 1,
- message: {
- "version": 1,
- "type": "doc",
- "content": [
- {
- "type": "paragraph",
- "content": [
- {
- "type": "text",
- "text": "happy debugging"
- }
- ]
- }
- ]
- },
- author: 1,
- user: user
- }
-]
-const issues = [
- {
- title: 'Crash Report - runtime error: index out of range',
- description: description,
- commentsCount: 4,
- activities: List(activities),
- assignee: user.id,
- issueType: 1,
- id: 'APP-222'
- },
- {
- title: 'this is the second one',
- description: description,
- commentsCount: 10,
- activities: activities,
- assignee: user.id,
- issueType: 1,
- id: 'APP-333'
- },
- {
- title: 'this is the third one',
- description: description,
- commentsCount: 0,
- activities: activities,
- assignee: user.id,
- issueType: 1,
- id: 'APP-444'
- }
-];
-
-const onIssueClick = (issue) => {
- console.log(issue);
-}
-
-storiesOf('Issues', module)
- .add('IssuesModal', () => (
-
- ))
- .add('IssueHeader', () => (
-
- ))
- .add('IssueComment', () => (
-
-
-
- ))
- .add('IssueDescription', () => (
-
-
-
- ))
- .add('IssueCommentForm', () => (
-
- ))
- .add('IssueDetails', () => (
-
- ))
- .add('IssueListItem', () => (
-
- ))
- .add('IssueForm', () => (
-
-
-
- ))
-
diff --git a/frontend/app/duck/assignments.js b/frontend/app/duck/assignments.js
deleted file mode 100644
index 427937e05..000000000
--- a/frontend/app/duck/assignments.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import { List, Map, Set } from 'immutable';
-import Assignment from 'Types/session/assignment';
-import Activity from 'Types/session/activity';
-import withRequestState, { RequestTypes } from './requestStateCreator';
-import { createListUpdater } from './funcTools/tools';
-import { editType, initType } from './funcTools/crud/types';
-import { createInit, createEdit } from './funcTools/crud';
-
-const idKey = 'id';
-const name = 'assignment';
-const listUpdater = createListUpdater(idKey);
-
-const FETCH_PROJECTS = new RequestTypes('asignment/FETCH_PROJECTS');
-const FETCH_META = new RequestTypes('asignment/FETCH_META');
-const FETCH_ASSIGNMENTS = new RequestTypes('asignment/FETCH_ASSIGNMENTS');
-const FETCH_ASSIGNMENT = new RequestTypes('asignment/FETCH_ASSIGNMENT');
-const ADD_ACTIVITY = new RequestTypes('asignment/ADD_ACTIVITY');
-const ADD_MESSAGE = new RequestTypes('asignment/ADD_MESSAGE');
-const EDIT = editType(name);
-const INIT = initType(name);
-
-const initialState = Map({
- list: List(),
- instance: new Assignment(),
- activeIssue: new Assignment(),
- issueTypes: List(),
- issueTypeIcons: Set(),
- users: List(),
- projects: List(),
- projectsFetched: false
-});
-
-const reducer = (state = initialState, action = {}) => {
- const users = state.get('users');
- let issueTypes = []
- switch (action.type) {
- case INIT:
- action.instance.issueType = issueTypes.length > 0 ? issueTypes[0].id : '';
- return state.set('instance', new Assignment(action.instance));
- case EDIT:
- const inst = state.get('instance')
- return state.set('instance', new Assignment({ ...inst, ...action.instance }));
- case FETCH_PROJECTS.SUCCESS:
- return state.set('projects', List(action.data)).set('projectsFetched', true);
- case FETCH_ASSIGNMENTS.SUCCESS:
- return state.set('list', List(action.data).map(as => new Assignment(as)));
- case FETCH_ASSIGNMENT.SUCCESS:
- return state.set('activeIssue', new Assignment({ ...action.data, users}));
- case FETCH_META.SUCCESS:
- issueTypes = action.data.issueTypes
- const issueTypeIcons = {}
- issueTypes.forEach(iss => {
- issueTypeIcons[iss.id] = iss.iconUrl
- })
- return state.set('issueTypes', issueTypes)
- .set('users', List(action.data.users))
- .set('issueTypeIcons', issueTypeIcons)
- case ADD_ACTIVITY.SUCCESS:
- const instance = new Assignment(action.data);
- return listUpdater(state, instance);
- case ADD_MESSAGE.SUCCESS:
- const user = users.filter(user => user.id === action.data.author).first();
- const activity = new Activity({ type: 'message', user, ...action.data,});
- return state.update([ 'activeIssue' ], issue => issue.activities.push(activity));
- default:
- return state;
- }
-};
-
-export default withRequestState({
- fetchProjects: FETCH_PROJECTS,
- fetchMeta: FETCH_META,
- fetchAssignments: FETCH_ASSIGNMENTS,
- addActivity: ADD_ACTIVITY,
- fetchAssignment: FETCH_ASSIGNMENT,
- addMessage: ADD_MESSAGE
-}, reducer);
-
-export const init = createInit(name);
-export const edit = createEdit(name);
-
-export function fetchProjects() {
- return {
- types: FETCH_PROJECTS.toArray(),
- call: client => client.get(`/integrations/issues/list_projects`)
- };
-}
-
-export function fetchMeta(projectId) {
- return {
- types: FETCH_META.toArray(),
- call: client => client.get(`/integrations/issues/${projectId}`)
- }
-}
-
-export function fetchAssignments(sessionId) {
- return {
- types: FETCH_ASSIGNMENTS.toArray(),
- call: client => client.get(`/sessions/${ sessionId }/assign`)
- }
-}
-
-export function addActivity(sessionId, params) {
- const data = { ...params, assignee: params.assignee, issueType: params.issueType }
- return {
- types: ADD_ACTIVITY.toArray(),
- call: client => client.post(`/sessions/${ sessionId }/assign/projects/${params.projectId}`, data),
- }
-}
-
-export function addMessage(sessionId, assignmentId, params) {
- return {
- types: ADD_MESSAGE.toArray(),
- call: client => client.post(`/sessions/${ sessionId }/assign/${ assignmentId }/comment`, params),
- }
-}
diff --git a/frontend/app/duck/index.ts b/frontend/app/duck/index.ts
index 1e19955d3..b4a497de3 100644
--- a/frontend/app/duck/index.ts
+++ b/frontend/app/duck/index.ts
@@ -3,7 +3,6 @@ import { combineReducers } from 'redux-immutable';
import user from './user';
import sessions from './sessions';
-import assignments from './assignments';
import filters from './filters';
import funnelFilters from './funnelFilters';
import sources from './sources';
@@ -19,7 +18,6 @@ import liveSearch from './liveSearch';
const rootReducer = combineReducers({
user,
sessions,
- assignments,
filters,
funnelFilters,
site,
diff --git a/frontend/app/duck/issues.js b/frontend/app/duck/issues.js
index ce68d31e4..1eb80c9c6 100644
--- a/frontend/app/duck/issues.js
+++ b/frontend/app/duck/issues.js
@@ -1,4 +1,4 @@
-import Assignment from 'Types/session/assignment';
+import ReportedIssue from 'Types/session/assignment';
import Activity from 'Types/session/activity';
import { List, Map, Set } from 'immutable';
import withRequestState, { RequestTypes } from 'Duck/requestStateCreator';
@@ -22,8 +22,8 @@ const RESET_ACTIVE_ISSUE = 'assignment/RESET_ACTIVE_ISSUE';
const initialState = Map({
list: List(),
- instance: new Assignment(),
- activeIssue: new Assignment(),
+ instance: new ReportedIssue(),
+ activeIssue: new ReportedIssue(),
issueTypes: List(),
issueTypeIcons: Set(),
users: List(),
@@ -38,9 +38,9 @@ const reducer = (state = initialState, action = {}) => {
case FETCH_PROJECTS.SUCCESS:
return state.set('projects', List(action.data));
case FETCH_ASSIGNMENTS.SUCCESS:
- return state.set('list', action.data.map(as => new Assignment(as)));
+ return state.set('list', action.data.map(as => new ReportedIssue(as)));
case ADD_ACTIVITY.SUCCESS:
- const instance = new Assignment(action.data);
+ const instance = new ReportedIssue(action.data);
return listUpdater(state, instance);
case FETCH_META.SUCCESS:
issueTypes = action.data.issueTypes;
@@ -52,16 +52,16 @@ const reducer = (state = initialState, action = {}) => {
.set('users', List(action.data.users))
.set('issueTypeIcons', issueTypeIcons)
case FETCH_ISSUE.SUCCESS:
- return state.set('activeIssue', new Assignment({ ...action.data, users}));
+ return state.set('activeIssue', new ReportedIssue({ ...action.data, users}));
case RESET_ACTIVE_ISSUE:
- return state.set('activeIssue', new Assignment());
+ return state.set('activeIssue', new ReportedIssue());
case ADD_MESSAGE.SUCCESS:
const user = users.filter(user => user.id === action.data.author).first();
const activity = new Activity({ type: 'message', user, ...action.data,});
return state.updateIn([ 'activeIssue', 'activities' ], list => list.push(activity));
case INIT:
action.instance.issueType = issueTypes.length > 0 ? issueTypes[0].id : '';
- return state.set('instance', new Assignment(action.instance));
+ return state.set('instance', new ReportedIssue(action.instance));
case EDIT:
return state.mergeIn([ 'instance' ], action.instance);
default:
@@ -80,13 +80,6 @@ export default withRequestState({
export const init = createInit(name);
export const edit = createEdit(name);
-export function fetchAssignments(sessionId) {
- return {
- types: FETCH_ASSIGNMENTS.toArray(),
- call: client => client.get(`/sessions/${ sessionId }/assign`)
- }
-}
-
export function resetActiveIsue() {
return {
type: RESET_ACTIVE_ISSUE
diff --git a/frontend/app/mstore/index.tsx b/frontend/app/mstore/index.tsx
index bed726abd..2d536aefd 100644
--- a/frontend/app/mstore/index.tsx
+++ b/frontend/app/mstore/index.tsx
@@ -25,6 +25,7 @@ import SpotStore from "./spotStore";
import LoginStore from "./loginStore";
import FilterStore from "./filterStore";
import UiPlayerStore from './uiPlayerStore';
+import IssueReportingStore from './issueReportingStore';
export class RootStore {
dashboardStore: DashboardStore;
@@ -51,6 +52,7 @@ export class RootStore {
loginStore: LoginStore;
filterStore: FilterStore;
uiPlayerStore: UiPlayerStore;
+ issueReportingStore: IssueReportingStore;
constructor() {
this.dashboardStore = new DashboardStore();
@@ -77,6 +79,7 @@ export class RootStore {
this.loginStore = new LoginStore();
this.filterStore = new FilterStore();
this.uiPlayerStore = new UiPlayerStore();
+ this.issueReportingStore = new IssueReportingStore();
}
initClient() {
diff --git a/frontend/app/mstore/issueReportingStore.ts b/frontend/app/mstore/issueReportingStore.ts
new file mode 100644
index 000000000..ba8aee1db
--- /dev/null
+++ b/frontend/app/mstore/issueReportingStore.ts
@@ -0,0 +1,90 @@
+import { makeAutoObservable } from 'mobx';
+import ReportedIssue from "../types/session/assignment";
+import { issueReportsService } from "App/services";
+
+export default class issueReportingStore {
+ instance: ReportedIssue
+ issueTypes: any[] = []
+ issueTypeIcons: {}
+ users: any[] = []
+ projects: any[] = []
+ projectsFetched = false
+ projectsLoading = false
+ metaLoading = false
+ createLoading = false
+
+ constructor() {
+ makeAutoObservable(this);
+ }
+
+ init = (instance: any) => {
+ this.instance = new ReportedIssue(instance);
+ if (this.issueTypes.length > 0) {
+ this.instance.issueType = this.issueTypes[0].id;
+ }
+ }
+
+ editInstance = (data: any) => {
+ const inst = this.instance
+ this.instance = new ReportedIssue({ ...inst, ...data })
+ }
+
+ setProjects = (projects: any[]) => {
+ this.projectsFetched = true;
+ this.projects = projects;
+ }
+
+ setMeta = (data: any) => {
+ const issueTypes = data.issueTypes || [];
+ const itIcons = {}
+ issueTypes.forEach((it: any) => {
+ itIcons[it.id] = it.iconUrl
+ })
+
+ this.issueTypes = issueTypes;
+ this.issueTypeIcons = itIcons;
+ this.users = data.users || [];
+ }
+
+ fetchProjects = async () => {
+ if (this.projectsLoading) return;
+ this.projectsLoading = true;
+ try {
+ const { data } = await issueReportsService.fetchProjects();
+ this.setProjects(data);
+ this.projectsFetched = true;
+ return data;
+ } catch (e) {
+ console.error(e)
+ } finally {
+ this.projectsLoading = false;
+ }
+ }
+
+ fetchMeta = async (projectId: number) => {
+ if (this.metaLoading) return;
+ this.metaLoading = true;
+ try {
+ const { data } = await issueReportsService.fetchMeta(projectId);
+ this.setMeta(data);
+ } catch (e) {
+ console.error(e)
+ } finally {
+ this.metaLoading = false;
+ }
+ }
+
+ saveIssue = async (sessionId: string, params: any) => {
+ if (this.createLoading) return;
+ this.createLoading = true;
+ try {
+ const data = { ...params, assignee: params.assignee, issueType: params.issueType }
+ const { data: issue } = await issueReportsService.saveIssue(sessionId, data);
+ this.init(issue)
+ } catch (e) {
+ console.error(e)
+ } finally {
+ this.createLoading = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/app/services/IssueReportsService.ts b/frontend/app/services/IssueReportsService.ts
new file mode 100644
index 000000000..4d6ef23f0
--- /dev/null
+++ b/frontend/app/services/IssueReportsService.ts
@@ -0,0 +1,21 @@
+import BaseService from 'App/services/BaseService';
+
+export default class IssueReportsService extends BaseService {
+ fetchProjects = async () => {
+ const r = await this.client.get(`/integrations/issues/list_projects`)
+
+ return await r.json();
+ }
+
+ fetchMeta = async (projectId: number) => {
+ const r = await this.client.get(`/integrations/issues/${projectId}`)
+
+ return await r.json();
+ }
+
+ saveIssue = async (sessionId: string, data: any) => {
+ const r = await this.client.post(`/sessions/${ sessionId }/assign/projects/${data.projectId}`, data)
+
+ return await r.json();
+ }
+}
\ No newline at end of file
diff --git a/frontend/app/services/index.ts b/frontend/app/services/index.ts
index 56a343b5d..4a6e743d1 100644
--- a/frontend/app/services/index.ts
+++ b/frontend/app/services/index.ts
@@ -20,6 +20,7 @@ import WebhookService from './WebhookService';
import SpotService from './spotService';
import LoginService from "./loginService";
import FilterService from "./FilterService";
+import IssueReportsService from "./IssueReportsService";
export const dashboardService = new DashboardService();
export const metricService = new MetricService();
@@ -42,6 +43,7 @@ export const aiService = new AiService();
export const spotService = new SpotService();
export const loginService = new LoginService();
export const filterService = new FilterService();
+export const issueReportsService = new IssueReportsService();
export const services = [
dashboardService,
@@ -65,4 +67,5 @@ export const services = [
spotService,
loginService,
filterService,
+ issueReportsService,
];
diff --git a/frontend/app/types/session/assignment.ts b/frontend/app/types/session/assignment.ts
index a16361ee8..1ae13825f 100644
--- a/frontend/app/types/session/assignment.ts
+++ b/frontend/app/types/session/assignment.ts
@@ -2,11 +2,10 @@ import Activity, { IActivity } from './activity';
import { DateTime } from 'luxon';
import { notEmptyString } from 'App/validate';
-interface IAssignment {
+interface IReportedIssue {
id: string;
title: string;
timestamp: number;
- creatorId: string;
sessionId: string;
projectId: string;
siteId: string;
@@ -22,23 +21,21 @@ interface IAssignment {
users: { id: string }[]
}
-export default class Assignment {
- id: IAssignment["id"];
- title: IAssignment["title"] = '';
- timestamp: IAssignment["timestamp"];
- creatorId: IAssignment["creatorId"];
- sessionId: IAssignment["sessionId"];
- projectId: IAssignment["projectId"] = '';
- siteId: IAssignment["siteId"];
- activities: IAssignment["activities"];
- closed: IAssignment["closed"];
- assignee: IAssignment["assignee"] = '';
- commentsCount: IAssignment["commentsCount"];
- issueType: IAssignment["issueType"] = '';
- description: IAssignment["description"] = '';
- iconUrl: IAssignment["iconUrl"] = '';
+export default class ReportedIssue {
+ id: IReportedIssue["id"];
+ title: IReportedIssue["title"] = '';
+ timestamp: IReportedIssue["timestamp"];
+ sessionId: IReportedIssue["sessionId"];
+ projectId: IReportedIssue["projectId"] = '';
+ siteId: IReportedIssue["siteId"];
+ activities: IReportedIssue["activities"];
+ closed: IReportedIssue["closed"];
+ assignee: IReportedIssue["assignee"] = '';
+ issueType: IReportedIssue["issueType"] = '';
+ description: IReportedIssue["description"] = '';
+ iconUrl: IReportedIssue["iconUrl"] = '';
- constructor(assignment?: IAssignment) {
+ constructor(assignment?: IReportedIssue) {
if (assignment) {
Object.assign(this, {
...assignment,