123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import {Component, Fragment} from 'react';
- import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
- import {ModalRenderProps, openModal} from 'sentry/actionCreators/modal';
- import {Client} from 'sentry/api';
- import IssueSyncListElement from 'sentry/components/issueSyncListElement';
- import NavTabs from 'sentry/components/navTabs';
- import {t, tct} from 'sentry/locale';
- import plugins from 'sentry/plugins';
- import {Group, Organization, Plugin, Project} from 'sentry/types';
- import withApi from 'sentry/utils/withApi';
- import withOrganization from 'sentry/utils/withOrganization';
- type PluginIssue = {
- issue_id: string;
- label: string;
- url: string;
- };
- type TitledPlugin = Plugin & {
- // issue serializer adds more fields
- // TODO: should be able to use name instead of title
- title: string;
- };
- type Props = {
- api: Client;
- group: Group;
- organization: Organization;
- plugin: TitledPlugin;
- project: Project;
- };
- type State = {
- issue: PluginIssue | null;
- pluginLoading: boolean;
- };
- class PluginActions extends Component<Props, State> {
- state: State = {
- issue: null,
- pluginLoading: false,
- };
- componentDidMount() {
- this.loadPlugin(this.props.plugin);
- }
- componentDidUpdate(prevProps: Props) {
- if (this.props.plugin.id !== prevProps.plugin.id) {
- this.loadPlugin(this.props.plugin);
- }
- }
- deleteIssue = () => {
- const plugin = {
- ...this.props.plugin,
- issue: null,
- };
- // override plugin.issue so that 'create/link' Modal
- // doesn't think the plugin still has an issue linked
- const endpoint = `/issues/${this.props.group.id}/plugins/${plugin.slug}/unlink/`;
- this.props.api.request(endpoint, {
- success: () => {
- this.loadPlugin(plugin);
- addSuccessMessage(t('Successfully unlinked issue.'));
- },
- error: () => {
- addErrorMessage(t('Unable to unlink issue'));
- },
- });
- };
- loadPlugin = (data: any) => {
- this.setState(
- {
- pluginLoading: true,
- },
- () => {
- plugins.load(data, () => {
- const issue = data.issue || null;
- this.setState({pluginLoading: false, issue});
- });
- }
- );
- };
- handleModalClose = (data?: any) =>
- this.setState({
- issue:
- data?.id && data?.link
- ? {issue_id: data.id, url: data.link, label: data.label}
- : null,
- });
- openModal = () => {
- const {issue} = this.state;
- const {project, group, organization} = this.props;
- const plugin = {...this.props.plugin, issue};
- openModal(
- deps => (
- <PluginActionsModal
- {...deps}
- project={project}
- group={group}
- organization={organization}
- plugin={plugin}
- onSuccess={this.handleModalClose}
- />
- ),
- {onClose: this.handleModalClose}
- );
- };
- render() {
- const {issue} = this.state;
- const plugin = {...this.props.plugin, issue};
- return (
- <IssueSyncListElement
- onOpen={this.openModal}
- externalIssueDisplayName={issue ? issue.label : null}
- externalIssueId={issue ? issue.issue_id : null}
- externalIssueLink={issue ? issue.url : null}
- onClose={this.deleteIssue}
- integrationType={plugin.id}
- />
- );
- }
- }
- type ModalProps = ModalRenderProps & {
- group: Group;
- onSuccess: (data: any) => void;
- organization: Organization;
- plugin: TitledPlugin & {issue: PluginIssue | null};
- project: Project;
- };
- type ModalState = {
- actionType: 'create' | 'link' | null;
- };
- class PluginActionsModal extends Component<ModalProps, ModalState> {
- state: ModalState = {
- actionType: 'create',
- };
- render() {
- const {Header, Body, group, project, organization, plugin, onSuccess} = this.props;
- const {actionType} = this.state;
- return (
- <Fragment>
- <Header closeButton>
- {tct('[name] Issue', {name: plugin.name || plugin.title})}
- </Header>
- <NavTabs underlined>
- <li className={actionType === 'create' ? 'active' : ''}>
- <a onClick={() => this.setState({actionType: 'create'})}>{t('Create')}</a>
- </li>
- <li className={actionType === 'link' ? 'active' : ''}>
- <a onClick={() => this.setState({actionType: 'link'})}>{t('Link')}</a>
- </li>
- </NavTabs>
- {actionType && (
- // need the key here so React will re-render
- // with new action prop
- <Body key={actionType}>
- {plugins.get(plugin).renderGroupActions({
- plugin,
- group,
- project,
- organization,
- actionType,
- onSuccess,
- })}
- </Body>
- )}
- </Fragment>
- );
- }
- }
- export {PluginActions};
- export default withApi(withOrganization(PluginActions));
|