Browse Source

fix(routes): Fix some Account Settings 404s (#9039)

* Use ExternalLink for "When should I delete issues"
* Fix "/account/authorizations" and some "security" and "notifications" sub routes

After taking a look at:
https://sentry.io/sentry/javascript/issues/496412334/tags/ - I noticed a few URLs
that were 404ing, this should fix them.

Also I thought it'd be better to open the help article when you are bulk deleting
an issue, otherwise you lose your UI state in sentry which seems a bit annoying.
Billy Vong 6 years ago
parent
commit
6a2684e6b3

+ 2 - 0
src/sentry/static/sentry/app/data/forms/apiApplication.jsx

@@ -1,4 +1,5 @@
 import {extractMultilineFields} from 'app/utils';
+import getDynamicText from 'app/utils/getDynamicText';
 
 const forms = [
   {
@@ -13,6 +14,7 @@ const forms = [
         // additional data/props that is related to rendering of form field rather than data
         label: 'Name',
         help: 'e.g. My Application',
+        setValue: value => getDynamicText({value, fixed: 'PERCY_APPLICATION_NAME'}),
       },
       {
         name: 'homepageUrl',

+ 8 - 3
src/sentry/static/sentry/app/views/settings/account/apiApplicationDetails.jsx

@@ -2,6 +2,7 @@ import {Box} from 'grid-emotion';
 import PropTypes from 'prop-types';
 import React from 'react';
 
+import {Panel, PanelBody, PanelHeader} from 'app/components/panels';
 import {addErrorMessage} from 'app/actionCreators/indicator';
 import {t} from 'app/locale';
 import AsyncView from 'app/views/asyncView';
@@ -9,10 +10,10 @@ import ConfigStore from 'app/stores/configStore';
 import Form from 'app/views/settings/components/forms/form';
 import FormField from 'app/views/settings/components/forms/formField';
 import JsonForm from 'app/views/settings/components/forms/jsonForm';
-import {Panel, PanelBody, PanelHeader} from 'app/components/panels';
 import SettingsPageHeader from 'app/views/settings/components/settingsPageHeader';
 import TextCopyInput from 'app/views/settings/components/forms/textCopyInput';
 import apiApplication from 'app/data/forms/apiApplication';
+import getDynamicText from 'app/utils/getDynamicText';
 
 class ApiApplicationDetails extends AsyncView {
   static contextTypes = {
@@ -62,7 +63,9 @@ class ApiApplicationDetails extends AsyncView {
                   {({value}) => {
                     return (
                       <div>
-                        <TextCopyInput>{value}</TextCopyInput>
+                        <TextCopyInput>
+                          {getDynamicText({value, fixed: 'PERCY_CLIENT_ID'})}
+                        </TextCopyInput>
                       </div>
                     );
                   }}
@@ -77,7 +80,9 @@ class ApiApplicationDetails extends AsyncView {
                 >
                   {({value}) => {
                     return value ? (
-                      <TextCopyInput>{value}</TextCopyInput>
+                      <TextCopyInput>
+                        {getDynamicText({value, fixed: 'PERCY_CLIENT_SECRET'})}
+                      </TextCopyInput>
                     ) : (
                       <em>hidden</em>
                     );

+ 8 - 3
src/sentry/static/sentry/app/views/settings/account/apiApplications.jsx

@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import createReactClass from 'create-react-class';
 
+import {Panel, PanelBody, PanelHeader, PanelItem} from 'app/components/panels';
 import {
   addErrorMessage,
   addLoadingMessage,
@@ -16,8 +17,8 @@ import AsyncView from 'app/views/asyncView';
 import Button from 'app/components/buttons/button';
 import EmptyMessage from 'app/views/settings/components/emptyMessage';
 import IndicatorStore from 'app/stores/indicatorStore';
-import {Panel, PanelBody, PanelHeader, PanelItem} from 'app/components/panels';
 import SettingsPageHeader from 'app/views/settings/components/settingsPageHeader';
+import getDynamicText from 'app/utils/getDynamicText';
 
 const ROUTE_PREFIX = '/settings/account/api/';
 
@@ -79,9 +80,13 @@ const ApiApplicationRow = createReactClass({
       <PanelItem justify="space-between" px={2} py={2}>
         <Box flex="1">
           <h4 style={{marginBottom: 5}}>
-            <Link to={`${ROUTE_PREFIX}applications/${app.id}/`}>{app.name}</Link>
+            <Link to={`${ROUTE_PREFIX}applications/${app.id}/`}>
+              {getDynamicText({value: app.name, fixed: 'PERCY_APPLICATION_NAME'})}
+            </Link>
           </h4>
-          <small style={{color: '#999'}}>{app.clientID}</small>
+          <small style={{color: '#999'}}>
+            {getDynamicText({value: app.clientID, fixed: 'PERCY_CLIENT_ID'})}
+          </small>
         </Box>
 
         <Flex align="center">

+ 9 - 3
src/sentry/static/sentry/app/views/settings/account/apiTokenRow.jsx

@@ -3,11 +3,12 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import styled from 'react-emotion';
 
+import {PanelItem} from 'app/components/panels';
 import {t} from 'app/locale';
 import Button from 'app/components/buttons/button';
 import DateTime from 'app/components/dateTime';
-import {PanelItem} from 'app/components/panels';
 import TextCopyInput from 'app/views/settings/components/forms/textCopyInput';
+import getDynamicText from 'app/utils/getDynamicText';
 
 const StyledPanelItem = styled(PanelItem)`
   flex-direction: column;
@@ -78,7 +79,7 @@ class ApiTokenRow extends React.Component {
                       </Flex>
                     )}
                   >
-                    {token.token}
+                    {getDynamicText({value: token.token, fixed: 'PERCY_AUTH_TOKEN'})}
                   </TextCopyInput>
                 </small>
               </div>
@@ -103,7 +104,12 @@ class ApiTokenRow extends React.Component {
           <Box>
             <Heading>{t('Created')}</Heading>
             <Time>
-              <DateTime date={token.dateCreated} />
+              <DateTime
+                date={getDynamicText({
+                  value: token.dateCreated,
+                  fixed: new Date(1508208080000), //National Pasta Day
+                })}
+              />
             </Time>
           </Box>
         </Details>

+ 10 - 11
src/sentry/static/sentry/app/views/stream/actions.jsx

@@ -1,25 +1,24 @@
+import {Flex, Box} from 'grid-emotion';
+import {capitalize} from 'lodash';
 import PropTypes from 'prop-types';
 import React from 'react';
-import createReactClass from 'create-react-class';
 import Reflux from 'reflux';
-import {capitalize} from 'lodash';
+import createReactClass from 'create-react-class';
 import styled from 'react-emotion';
-import {Flex, Box} from 'grid-emotion';
-import {Link} from 'react-router';
 
+import {t, tct, tn} from 'app/locale';
+import ActionLink from 'app/components/actions/actionLink';
 import ApiMixin from 'app/mixins/apiMixin';
+import Checkbox from 'app/components/checkbox';
 import DropdownLink from 'app/components/dropdownLink';
+import ExternalLink from 'app/components/externalLink';
+import IgnoreActions from 'app/components/actions/ignore';
 import IndicatorStore from 'app/stores/indicatorStore';
 import MenuItem from 'app/components/menuItem';
+import ResolveActions from 'app/components/actions/resolve';
 import SelectedGroupStore from 'app/stores/selectedGroupStore';
 import SentryTypes from 'app/proptypes';
-import {t, tct, tn} from 'app/locale';
-
-import Checkbox from 'app/components/checkbox';
 import ToolbarHeader from 'app/components/toolbarHeader';
-import ResolveActions from 'app/components/actions/resolve';
-import IgnoreActions from 'app/components/actions/ignore';
-import ActionLink from 'app/components/actions/actionLink';
 import Tooltip from 'app/components/tooltip';
 
 const BULK_LIMIT = 1000;
@@ -61,7 +60,7 @@ const getConfirm = (numIssues, allInQuerySelected, query, queryCount) => {
             'Bulk deletion is only recommended for junk data. To clear your stream, consider resolving or ignoring. [link:When should I delete events?]',
             {
               link: (
-                <Link to="https://help.sentry.io/hc/en-us/articles/360003443113-When-should-I-delete-events-" />
+                <ExternalLink href="https://help.sentry.io/hc/en-us/articles/360003443113-When-should-I-delete-events" />
               ),
             }
           )

+ 1 - 1
src/sentry/templates/sentry/bases/account.html

@@ -39,7 +39,7 @@
         <li{% if page == 'appearance' %} class="active"{% endif %}><a href="{% url 'sentry-account-settings-appearance' %}">{% trans "Appearance" %}</a></li>
         <li{% if page == 'notifications' %} class="active"{% endif %}><a href="{% url 'sentry-account-settings-notifications' %}">{% trans "Notifications" %}</a></li>
         <li{% if page == 'emails' %} class="active"{% endif %}><a href="{% url 'sentry-account-settings-emails' %}">{% trans "Emails" %}</a></li>
-        <li{% if page == 'security' %} class="active"{% endif %}><a href="{% url 'sentry-account-security' %}">{% trans "Security" %}</a></li>
+        <li{% if page == 'security' %} class="active"{% endif %}><a href="{% url 'sentry-account-settings-security' %}">{% trans "Security" %}</a></li>
         {% if has_newsletters %}
           <li{% if page == 'subscriptions' %} class="active"{% endif %}><a href="{% url 'sentry-account-settings-subscriptions' %}">{% trans "Subscriptions" %}</a></li>
         {% endif %}

+ 12 - 8
src/sentry/web/urls.py

@@ -198,6 +198,9 @@ urlpatterns += patterns(
         accounts.start_confirm_email,
         name='sentry-account-confirm-email-send'
     ),
+    url(r'^account/authorizations/$',
+        RedirectView.as_view(pattern_name="sentry-account-settings-authorizations", permanent=False),
+    ),
     url(
         r'^account/confirm-email/(?P<user_id>[\d]+)/(?P<hash>[0-9a-zA-Z]+)/$',
         accounts.confirm_email,
@@ -253,11 +256,7 @@ urlpatterns += patterns(
         name='sentry-account-link-identity'
     ),
     url(
-        r'^account/settings/notifications/$',
-        RedirectView.as_view(pattern_name="sentry-account-settings-notifications", permanent=False),
-    ),
-    url(
-        r'^account/settings/security/$',
+        r'^account/settings/security/',
         RedirectView.as_view(pattern_name="sentry-account-settings-security", permanent=False),
     ),
     url(r'^account/settings/emails/$',
@@ -276,6 +275,10 @@ urlpatterns += patterns(
         r'^account/settings/notifications/unsubscribe/(?P<project_id>\d+)/$',
         accounts.email_unsubscribe_project
     ),
+    url(
+        r'^account/settings/notifications/',
+        RedirectView.as_view(pattern_name="sentry-account-settings-notifications", permanent=False),
+    ),
     url(
         r'^account/notifications/unsubscribe/(?P<project_id>\d+)/$',
         accounts.email_unsubscribe_project,
@@ -349,12 +352,13 @@ urlpatterns += patterns(
     # acting on behalf of an organization should use react_page_view
     url(r'^settings/account/$', generic_react_page_view, name="sentry-account-settings"),
     url(r'^settings/account/$', generic_react_page_view, name="sentry-account-settings-appearance"),
-    url(r'^settings/account/security/$', generic_react_page_view, name='sentry-account-settings-security'),
+    url(r'^settings/account/authorizations/$', generic_react_page_view, name="sentry-account-settings-authorizations"),
+    url(r'^settings/account/security/', generic_react_page_view, name='sentry-account-settings-security'),
     url(r'^settings/account/avatar/$', generic_react_page_view, name='sentry-account-settings-avatar'),
     url(r'^settings/account/identities/$', generic_react_page_view, name='sentry-account-settings-identities'),
     url(r'^settings/account/subscriptions/$', generic_react_page_view, name='sentry-account-settings-subscriptions'),
-    url(r'^settings/account/notifications/$', generic_react_page_view, name='sentry-account-settings-notifications'),
-    url(r'^settings/account/email/$', generic_react_page_view, name='sentry-account-settings-emails'),
+    url(r'^settings/account/notifications/', generic_react_page_view, name='sentry-account-settings-notifications'),
+    url(r'^settings/account/emails/$', generic_react_page_view, name='sentry-account-settings-emails'),
     url(r'^settings/account/api/$', generic_react_page_view, name='sentry-api'),
     url(r'^settings/account/api/applications/$', generic_react_page_view, name='sentry-api-applications'),
     url(r'^settings/account/api/[^0]+/$', generic_react_page_view, name='sentry-api-details'),

+ 0 - 16
tests/acceptance/test_account_appearance_settings.py

@@ -1,16 +0,0 @@
-from __future__ import absolute_import
-
-from sentry.testutils import AcceptanceTestCase
-
-
-class AccountAppearanceSettingsTest(AcceptanceTestCase):
-    def setUp(self):
-        super(AccountAppearanceSettingsTest, self).setUp()
-        self.user = self.create_user('foo@example.com')
-        self.login_as(self.user)
-        self.path = '/account/settings/appearance/'
-
-    def test_simple(self):
-        self.browser.get(self.path)
-        self.browser.wait_until_not('.loading-indicator')
-        self.browser.snapshot('account appearance settings')

+ 0 - 41
tests/acceptance/test_account_notification_settings.py

@@ -1,41 +0,0 @@
-from __future__ import absolute_import
-
-from sentry.testutils import AcceptanceTestCase
-
-
-class AccountNotificationSettingsTest(AcceptanceTestCase):
-    def setUp(self):
-        super(AccountNotificationSettingsTest, self).setUp()
-        self.user = self.create_user('foo@example.com')
-        self.org = self.create_organization(
-            name='Rowdy Tiger',
-            owner=None,
-        )
-        self.team = self.create_team(organization=self.org, name='Mariachi Band')
-        self.project = self.create_project(
-            organization=self.org,
-            teams=[self.team],
-            name='Bengal',
-        )
-        self.create_member(
-            user=self.user,
-            organization=self.org,
-            role='owner',
-            teams=[self.team],
-        )
-        self.login_as(self.user)
-        self.path = '/account/settings/notifications/'
-
-    def test_simple(self):
-        self.browser.get(self.path)
-        self.browser.wait_until_not('.loading-indicator')
-        self.browser.snapshot('account notification settings')
-
-    def test_new_simple(self):
-        self.browser.get('/settings/account/notifications/')
-        self.browser.wait_until_not('.loading-indicator')
-        self.browser.snapshot('account notification - settings (new)')
-
-        self.browser.click_when_visible('#Alerts a')
-        self.browser.wait_until_not('.loading-indicator')
-        self.browser.snapshot('account notification - fine tune "Alerts" (new)')

+ 99 - 3
tests/acceptance/test_account_settings.py

@@ -1,5 +1,7 @@
 from __future__ import absolute_import
 
+import pytest
+
 from sentry.testutils import AcceptanceTestCase
 
 
@@ -7,10 +9,104 @@ class AccountSettingsTest(AcceptanceTestCase):
     def setUp(self):
         super(AccountSettingsTest, self).setUp()
         self.user = self.create_user('foo@example.com')
+        self.org = self.create_organization(
+            name='Rowdy Tiger Rowdy Tiger Rowdy Tiger',
+            owner=None,
+        )
+        self.team = self.create_team(organization=self.org, name='Mariachi Band Mariachi Band Mariachi Band')
+        self.project = self.create_project(
+            organization=self.org,
+            teams=[self.team],
+            name='Bengal Bengal Bengal Bengal',
+        )
+        self.create_member(
+            user=self.user,
+            organization=self.org,
+            role='owner',
+            teams=[self.team],
+        )
         self.login_as(self.user)
-        self.path = '/account/settings/'
 
-    def test_simple(self):
-        self.browser.get(self.path)
+    # TODO(billy): Enable this and remove the slower tests below
+    @pytest.mark.skip(reason="This will be faster but does not check if old django routes are redirecting")
+    def test_account_settings(self):
+        path = '/account/settings/'
+        self.browser.get(path)
         self.browser.wait_until_not('.loading-indicator')
         self.browser.snapshot('account settings')
+
+        self.browser.click('[href="/settings/account/security/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account security settings')
+
+        self.browser.click('[href="/settings/account/notifications/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account notification settings')
+
+        self.browser.click_when_visible('#Alerts a')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account notification - fine tune "Alerts"')
+
+        self.browser.click('[href="/settings/account/emails/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account emails settings')
+
+        self.browser.click('[href="/settings/account/subscriptions/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account subscriptions settings')
+
+        self.browser.click('[href="/settings/account/authorizations/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account authorizations settings')
+
+        self.browser.click('[href="/settings/account/identities/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account identities settings')
+
+        self.browser.click('[href="/settings/account/close-account/"]')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account settings - close account')
+
+    def test_account_appearance_settings(self):
+        self.browser.get('/account/settings/appearance/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account appearance settings')
+
+    def test_account_security_settings(self):
+        self.browser.get('/account/settings/security/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account security settings')
+
+    def test_account_notifications(self):
+        self.browser.get('/account/settings/notifications/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account notification settings')
+
+        self.browser.click_when_visible('#Alerts a')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account notification - fine tune "Alerts"')
+
+    def test_account_emails_settings(self):
+        self.browser.get('/account/settings/emails/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account emails settings')
+
+    def test_account_subscriptions_settings(self):
+        self.browser.get('/account/settings/subscriptions/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account subscriptions settings')
+
+    def test_account_authorizations_settings(self):
+        self.browser.get('/account/authorizations/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account authorizations settings')
+
+    def test_account_identities_settings(self):
+        self.browser.get('/account/settings/identities/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account identities settings')
+
+    def test_close_account(self):
+        self.browser.get('/account/remove/')
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.snapshot('account settings - close account')

Some files were not shown because too many files changed in this diff