|
@@ -7,6 +7,7 @@ import {Button} from 'sentry/components/button';
|
|
|
import {EventUserFeedback} from 'sentry/components/events/userFeedback';
|
|
|
import CompactIssue from 'sentry/components/issues/compactIssue';
|
|
|
import * as Layout from 'sentry/components/layouts/thirds';
|
|
|
+import LoadingError from 'sentry/components/loadingError';
|
|
|
import LoadingIndicator from 'sentry/components/loadingIndicator';
|
|
|
import NoProjectMessage from 'sentry/components/noProjectMessage';
|
|
|
import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
|
|
@@ -18,50 +19,47 @@ import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionT
|
|
|
import Pagination from 'sentry/components/pagination';
|
|
|
import Panel from 'sentry/components/panels/panel';
|
|
|
import {SegmentedControl} from 'sentry/components/segmentedControl';
|
|
|
+import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
|
|
|
import {Tooltip} from 'sentry/components/tooltip';
|
|
|
import {t} from 'sentry/locale';
|
|
|
import {space} from 'sentry/styles/space';
|
|
|
-import type {Organization, UserReport} from 'sentry/types';
|
|
|
+import type {UserReport} from 'sentry/types';
|
|
|
+import {useApiQuery} from 'sentry/utils/queryClient';
|
|
|
+import useOrganization from 'sentry/utils/useOrganization';
|
|
|
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
|
|
|
-import withOrganization from 'sentry/utils/withOrganization';
|
|
|
-import type {AsyncViewState} from 'sentry/views/deprecatedAsyncView';
|
|
|
-import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
|
|
|
|
|
|
import {UserFeedbackEmpty} from './userFeedbackEmpty';
|
|
|
import {getQuery} from './utils';
|
|
|
|
|
|
-interface State extends AsyncViewState {
|
|
|
- reportList: UserReport[];
|
|
|
-}
|
|
|
+interface Props extends RouteComponentProps<{}, {}> {}
|
|
|
|
|
|
-interface Props extends RouteComponentProps<{}, {}> {
|
|
|
- organization: Organization;
|
|
|
-}
|
|
|
+function OrganizationUserFeedback({location: {search, pathname, query}, router}: Props) {
|
|
|
+ const organization = useOrganization();
|
|
|
+ const {status} = getQuery(search);
|
|
|
|
|
|
-class OrganizationUserFeedback extends DeprecatedAsyncView<Props, State> {
|
|
|
- getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
|
|
|
- const {
|
|
|
- organization,
|
|
|
- location: {search},
|
|
|
- } = this.props;
|
|
|
-
|
|
|
- return [
|
|
|
- [
|
|
|
- 'reportList',
|
|
|
- `/organizations/${organization.slug}/user-feedback/`,
|
|
|
- {
|
|
|
- query: getQuery(search),
|
|
|
- },
|
|
|
- ],
|
|
|
- ];
|
|
|
- }
|
|
|
+ const unresolvedQuery = omit(query, 'status');
|
|
|
+ const allIssuesQuery = {...query, status: ''};
|
|
|
+ const hasNewFeedback = organization.features.includes('user-feedback-ui');
|
|
|
|
|
|
- getTitle() {
|
|
|
- return `${t('User Feedback')} - ${this.props.organization.slug}`;
|
|
|
- }
|
|
|
+ const {
|
|
|
+ data: reportList,
|
|
|
+ isLoading,
|
|
|
+ isError,
|
|
|
+ getResponseHeader,
|
|
|
+ } = useApiQuery<UserReport[]>(
|
|
|
+ [
|
|
|
+ `/organizations/${organization.slug}/user-feedback/`,
|
|
|
+ {
|
|
|
+ query: getQuery(search),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ {staleTime: 0}
|
|
|
+ );
|
|
|
+
|
|
|
+ const reportListsPageLinks = getResponseHeader?.('Link');
|
|
|
|
|
|
- get projectIds() {
|
|
|
- const {project} = this.props.location.query;
|
|
|
+ function getProjectIds() {
|
|
|
+ const {project} = query;
|
|
|
|
|
|
return Array.isArray(project)
|
|
|
? project
|
|
@@ -70,12 +68,23 @@ class OrganizationUserFeedback extends DeprecatedAsyncView<Props, State> {
|
|
|
: [];
|
|
|
}
|
|
|
|
|
|
- renderResults() {
|
|
|
- const {organization} = this.props;
|
|
|
-
|
|
|
+ function StreamBody() {
|
|
|
+ if (isError) {
|
|
|
+ return <LoadingError />;
|
|
|
+ }
|
|
|
+ if (isLoading) {
|
|
|
+ return (
|
|
|
+ <Panel>
|
|
|
+ <LoadingIndicator />
|
|
|
+ </Panel>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (!reportList?.length) {
|
|
|
+ return <UserFeedbackEmpty projectIds={getProjectIds()} />;
|
|
|
+ }
|
|
|
return (
|
|
|
<Panel className="issue-list" data-test-id="user-feedback-list">
|
|
|
- {this.state.reportList.map(item => {
|
|
|
+ {reportList.map(item => {
|
|
|
const issue = item.issue;
|
|
|
return (
|
|
|
<CompactIssue key={item.id} id={issue.id} data={issue} eventId={item.eventID}>
|
|
@@ -91,44 +100,8 @@ class OrganizationUserFeedback extends DeprecatedAsyncView<Props, State> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- renderEmpty() {
|
|
|
- return <UserFeedbackEmpty projectIds={this.projectIds} />;
|
|
|
- }
|
|
|
-
|
|
|
- renderLoading() {
|
|
|
- return this.renderBody();
|
|
|
- }
|
|
|
-
|
|
|
- renderStreamBody() {
|
|
|
- const {loading, reportList} = this.state;
|
|
|
-
|
|
|
- if (loading) {
|
|
|
- return (
|
|
|
- <Panel>
|
|
|
- <LoadingIndicator />
|
|
|
- </Panel>
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- if (!reportList.length) {
|
|
|
- return this.renderEmpty();
|
|
|
- }
|
|
|
-
|
|
|
- return this.renderResults();
|
|
|
- }
|
|
|
-
|
|
|
- renderBody() {
|
|
|
- const {organization, router} = this.props;
|
|
|
- const {location} = this.props;
|
|
|
- const {pathname, search, query} = location;
|
|
|
- const {status} = getQuery(search);
|
|
|
- const {reportListPageLinks} = this.state;
|
|
|
-
|
|
|
- const unresolvedQuery = omit(query, 'status');
|
|
|
- const allIssuesQuery = {...query, status: ''};
|
|
|
- const hasNewFeedback = organization.features.includes('user-feedback-ui');
|
|
|
-
|
|
|
- return (
|
|
|
+ return (
|
|
|
+ <SentryDocumentTitle title={`${t('User Feedback')} - ${organization.slug}`}>
|
|
|
<PageFiltersContainer>
|
|
|
<NoProjectMessage organization={organization}>
|
|
|
<Layout.Header>
|
|
@@ -158,7 +131,7 @@ class OrganizationUserFeedback extends DeprecatedAsyncView<Props, State> {
|
|
|
`/organizations/${organization.slug}/feedback/`
|
|
|
),
|
|
|
query: {
|
|
|
- ...location.query,
|
|
|
+ ...query,
|
|
|
query: undefined,
|
|
|
cursor: undefined,
|
|
|
},
|
|
@@ -194,17 +167,17 @@ class OrganizationUserFeedback extends DeprecatedAsyncView<Props, State> {
|
|
|
<SegmentedControl.Item key="">{t('All Issues')}</SegmentedControl.Item>
|
|
|
</SegmentedControl>
|
|
|
</Filters>
|
|
|
- {this.renderStreamBody()}
|
|
|
- <Pagination pageLinks={reportListPageLinks} />
|
|
|
+ <StreamBody />
|
|
|
+ <Pagination pageLinks={reportListsPageLinks} />
|
|
|
</Layout.Main>
|
|
|
</Layout.Body>
|
|
|
</NoProjectMessage>
|
|
|
</PageFiltersContainer>
|
|
|
- );
|
|
|
- }
|
|
|
+ </SentryDocumentTitle>
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
-export default withOrganization(withProfiler(OrganizationUserFeedback));
|
|
|
+export default withProfiler(OrganizationUserFeedback);
|
|
|
|
|
|
const Filters = styled('div')`
|
|
|
display: grid;
|