From 8c911650e5909464113e1ad9eb468c9f6c3cb555 Mon Sep 17 00:00:00 2001 From: Shaily Date: Feb 05 2018 14:33:19 +0000 Subject: [PATCH 1/32] Issues: Initial commit --- diff --git a/hubs/default_config.py b/hubs/default_config.py index 546342a..3d2b33d 100644 --- a/hubs/default_config.py +++ b/hubs/default_config.py @@ -73,5 +73,6 @@ WIDGETS = [ 'hubs.widgets.pagureissues:PagureIssues', 'hubs.widgets.repositories:Repositories', 'hubs.widgets.sticky:Sticky', + 'hubs.widgets.issues:Issues', 'hubs.widgets.workflow.updates2stable:Updates2Stable', ] diff --git a/hubs/widgets/issues/__init__.py b/hubs/widgets/issues/__init__.py new file mode 100644 index 0000000..616df54 --- /dev/null +++ b/hubs/widgets/issues/__init__.py @@ -0,0 +1,102 @@ +from __future__ import unicode_literals + +from hubs.widgets import validators +from hubs.widgets.base import Widget +from hubs.widgets.caching import CachedFunction +from hubs.widgets.view import RootWidgetView + +import requests + + +class Issues(Widget): + + name = "issues" + label = "Issues" + position = "left" + parameters = [ + dict( + name="github_username", + label="Github Username", + default="None", + validator=validators.Text, + help="Github username to show issues of", + ), + dict( + name="pagure_username", + label="Pagure Username", + default="None", + validator=validators.Text, + help="Pagure username to show issues of", + ), + dict( + name="bugzilla_username", + label="Bugzilla Username", + default="None", + validator=validators.Text, + help="Bugzilla username to show issues of", + ) + ] + + +class BaseView(RootWidgetView): + + def get_context(self, instance, *args, **kwargs): + bugzilla_bugs = GetBugzillaBugs(instance) + github_issues = GetGithubIssues(instance) + pagure_issues = GetPagureIssues(instance) + return dict( + bugzilla_bugs=bugzilla_bugs(), + github_issues=github_issues(), + pagure_issues=pagure_issues() + ) + + +class GetBugzillaBugs(CachedFunction): + + def execute(self): + username = self.instance.config["bugzilla_username"] + endpoint = "https://bugzilla.redhat.com/jsonrpc.cgi?method=Bug.search¶ms=[{{\"creator\":\"{}\"}}]" + response = requests.get(endpoint.format(username)).json() + issues = response['result']['bugs'] + issues = issues[:min(5, len(issues))] + return issues + + def should_invalidate(self, message): + return False + + def _should_cache(self, value): + return False + + +class GetPagureIssues(CachedFunction): + + def execute(self): + username = self.instance.config["pagure_username"] + endpoint = "https://pagure.io/api/0/user/{}/issues" + response = requests.get(endpoint.format(username)).json() + issues = response['issues_created'] + issues = issues[:min(5, len(issues))] + return issues + + def should_invalidate(self, message): + return False + + def _should_cache(self, value): + return False + + +class GetGithubIssues(CachedFunction): + + def execute(self): + username = self.instance.config["github_username"] + endpoint = "https://api.github.com/search/issues?q=is:issue+author:{}&sort:updated" + response = requests.get(endpoint.format(username)).json() + issues = response['items'] + issues = issues[:min(5, len(issues))] + return issues + + def should_invalidate(self, message): + return False + + def _should_cache(self, value): + return False diff --git a/hubs/widgets/issues/templates/root.html b/hubs/widgets/issues/templates/root.html new file mode 100644 index 0000000..88e9b15 --- /dev/null +++ b/hubs/widgets/issues/templates/root.html @@ -0,0 +1,110 @@ +
Bugzilla
+ + +
Github
+ + +
Pagure
+ + +{#
Bugzilla
#} +{##} +{##} +{#
Github
#} +{##} +{##} +{#
Pagure
#} +{##} From 09bd1007ce147a2af8b076302f534cc9ad36221d Mon Sep 17 00:00:00 2001 From: Shaily Date: Feb 05 2018 14:33:19 +0000 Subject: [PATCH 2/32] Issues: Fetch VCS details from hub config --- diff --git a/hubs/models/hubconfig.py b/hubs/models/hubconfig.py index d103681..a4a8db6 100644 --- a/hubs/models/hubconfig.py +++ b/hubs/models/hubconfig.py @@ -105,8 +105,9 @@ class HubConfigProxy(MutableMapping): "visibility", "chat_domain", "chat_channel", "mailing_list", "calendar", "meetings_text", "rules_url", "timezone_offset", "chat_nickname", "email", "creation_date", "country", + "pagure_username", "github_username", "bugzilla_email", "mailing_list_url", - ) + tuple(p["name"] for p in DEV_PLATFORMS) + ) + tuple(p["name"] for p in DEV_PLATFORMS) CONVERTERS = { "archived": BooleanConverter(), "left_width": Converter(int), @@ -125,6 +126,8 @@ class HubConfigProxy(MutableMapping): } LISTS = ("pagure", "github") VALIDATORS = { + "github_username": validators.GithubOrganization, + "pagure_username": validators.PagureUser, "github": validators.GithubOrgAndRepo, "pagure": validators.PagureRepo, "chat_domain": validators.ChatDomain, diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelDetails.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelDetails.js new file mode 100644 index 0000000..ec639b5 --- /dev/null +++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelDetails.js @@ -0,0 +1,85 @@ +import React from 'react'; +import { + defineMessages, + FormattedMessage, + } from 'react-intl'; + + +const messages = defineMessages({ + title: { + id: "hubs.core.config.details.title", + defaultMessage: "Details", + }, + intro: { + id: "hubs.core.config.details.intro", + defaultMessage: "Change additional hub configuration here.", + }, + pagure_username: { + id: "hubs.core.config.details.pagure_username", + defaultMessage: "Pagure Username", + }, + pagure_username_help: { + id: "hubs.core.config.details.pagure_username_help", + defaultMessage: "Your pagure username", + }, + github_username: { + id: "hubs.core.config.details.github_username", + defaultMessage: "Github Username", + }, + github_username_help: { + id: "hubs.core.config.details.github_username_help", + defaultMessage: "Your github username", + }, + bugzilla_email: { + id: "hubs.core.config.details.bugzilla_email", + defaultMessage: "Bugzilla E-mail", + }, + bugzilla_email_help: { + id: "hubs.core.config.details.bugzilla_email_help", + defaultMessage: "Your bugzilla e-mail address", + }, +}); + + +export default class DetailsPanel extends React.Component { + + constructor(props) { + super(props); + this.handleChange = this.handleChange.bind(this); + } + + handleChange(e) { + const name = e.target.name, value = e.target.value; + this.props.handleChange(name, value); + } + + render() { + return ( +
{e.preventDefault();}}> + + + {["pagure_username", "github_username", "bugzilla_email"].map(function(x, i) { + return ( +
+ + +

+ +

+
+ ) + }, this)} + + + ); + } +} diff --git a/hubs/utils/validators.py b/hubs/utils/validators.py index 4d5ec86..8da8e1c 100644 --- a/hubs/utils/validators.py +++ b/hubs/utils/validators.py @@ -107,6 +107,14 @@ def FMNContext(value): raise ValueError('Invalid FMN context') +def PagureUser(value): + """Fails if the Pagure username does not exist.""" + response = requests.get("https://pagure.io/user/%s" % value, timeout=5) + if response.ok: + return value + raise ValueError('Invalid Pagure username: {}'.format(value)) + + def PagureRepo(value): """Fails if the Pagure repository name does not exist.""" try: diff --git a/hubs/widgets/issues/__init__.py b/hubs/widgets/issues/__init__.py index 616df54..c4bfd8f 100644 --- a/hubs/widgets/issues/__init__.py +++ b/hubs/widgets/issues/__init__.py @@ -13,29 +13,7 @@ class Issues(Widget): name = "issues" label = "Issues" position = "left" - parameters = [ - dict( - name="github_username", - label="Github Username", - default="None", - validator=validators.Text, - help="Github username to show issues of", - ), - dict( - name="pagure_username", - label="Pagure Username", - default="None", - validator=validators.Text, - help="Pagure username to show issues of", - ), - dict( - name="bugzilla_username", - label="Bugzilla Username", - default="None", - validator=validators.Text, - help="Bugzilla username to show issues of", - ) - ] + parameters = [] class BaseView(RootWidgetView): @@ -54,9 +32,9 @@ class BaseView(RootWidgetView): class GetBugzillaBugs(CachedFunction): def execute(self): - username = self.instance.config["bugzilla_username"] + email = self.instance.hub.config["bugzilla_email"] endpoint = "https://bugzilla.redhat.com/jsonrpc.cgi?method=Bug.search¶ms=[{{\"creator\":\"{}\"}}]" - response = requests.get(endpoint.format(username)).json() + response = requests.get(endpoint.format(email)).json() issues = response['result']['bugs'] issues = issues[:min(5, len(issues))] return issues @@ -64,6 +42,10 @@ class GetBugzillaBugs(CachedFunction): def should_invalidate(self, message): return False + def should_invalidate_on_hub_config_change(self, old_config): + return True + + # For testing purposes def _should_cache(self, value): return False @@ -71,7 +53,7 @@ class GetBugzillaBugs(CachedFunction): class GetPagureIssues(CachedFunction): def execute(self): - username = self.instance.config["pagure_username"] + username = self.instance.hub.config["pagure_username"] endpoint = "https://pagure.io/api/0/user/{}/issues" response = requests.get(endpoint.format(username)).json() issues = response['issues_created'] @@ -81,6 +63,10 @@ class GetPagureIssues(CachedFunction): def should_invalidate(self, message): return False + def should_invalidate_on_hub_config_change(self, old_config): + return True + + # For testing purposes def _should_cache(self, value): return False @@ -88,7 +74,7 @@ class GetPagureIssues(CachedFunction): class GetGithubIssues(CachedFunction): def execute(self): - username = self.instance.config["github_username"] + username = self.instance.hub.config["github_username"] endpoint = "https://api.github.com/search/issues?q=is:issue+author:{}&sort:updated" response = requests.get(endpoint.format(username)).json() issues = response['items'] @@ -98,5 +84,9 @@ class GetGithubIssues(CachedFunction): def should_invalidate(self, message): return False + def should_invalidate_on_hub_config_change(self, old_config): + return True + + # For testing purposes def _should_cache(self, value): return False From aaef012875b3d784264549bbf6827fec0c6515bc Mon Sep 17 00:00:00 2001 From: Shaily Date: Feb 05 2018 14:33:19 +0000 Subject: [PATCH 3/32] Issues: Use react widget --- diff --git a/hubs/static/client/app/widgets/issues/Config.js b/hubs/static/client/app/widgets/issues/Config.js new file mode 100644 index 0000000..5c5e4fc --- /dev/null +++ b/hubs/static/client/app/widgets/issues/Config.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { + defineMessages, + injectIntl, + FormattedMessage +} from 'react-intl'; + + +const messages = defineMessages({ + select_author: { + id: "hubs.widgets.halp.config.select.author", + defaultMessage: "Tickets I Filed", + }, + select_assignee: { + id: "hubs.widgets.halp.config.select.assignee", + defaultMessage: "Tickets Waiting on Me", + }, +}); + + +class Config extends React.Component { + + constructor(props) { + super(props); + this.handleModeChanged = this.handleModeChanged.bind(this); + } + + handleModeChanged(e) { + this.props.setConfig("mode", e.target.value); + } + + render() { + return ( +
+ + +
+ ); + } +} + + +export default injectIntl(Config); diff --git a/hubs/static/client/app/widgets/issues/Widget.js b/hubs/static/client/app/widgets/issues/Widget.js new file mode 100644 index 0000000..1c9a8d3 --- /dev/null +++ b/hubs/static/client/app/widgets/issues/Widget.js @@ -0,0 +1,133 @@ +import React from 'react'; +import { + widgetDidUpdate, + widgetWillUpdate +} from "../../core/actions/widget"; +import WidgetChrome from '../../components/WidgetChrome'; +import PropTypes from "prop-types"; +import Spinner from "../../components/Spinner"; + + +export default class IssuesWidget extends React.PureComponent { + + constructor(props) { + super(props); + this.state = { + issues: [], + counts: {}, + isLoading: false + } + } + + componentDidMount() { + if (!this.props.editMode) { + this.loadFromServer(); + } + } + + componentWillUnmount() { + this.serverRequest.abort(); + } + + + componentDidUpdate(prevProps, prevState) { + if (this.props.needsUpdate && !this.props.editMode && !this.state.isLoading) { + this.loadFromServer(); + } + } + + loadFromServer() { + this.props.dispatch(widgetWillUpdate(this.props.widget.idx)); + this.setState({isLoading: true}); + this.serverRequest = $.ajax({ + url: this.props.widget.urls.data, + method: 'GET', + cache: false, + success: (res) => { + this.setState({ + issues: res.data.issues, + counts: res.data.counts, + isLoading: false + }, + () => ( + this.props.dispatch(widgetDidUpdate(this.props.widget.idx)) + ) + ); + }, + error: (xhr, status, err) => { + console.error(this.props.widget.urls.data, status, err.toString()); + this.setState({isLoading: false}); + } + }); + } + + render() { + return ( + +
    + { this.state.isLoading && } + { + this.state.issues.map((issue) => { + return ( +
  • +
    + +
    +
    + { issue.project } + +
    +
    +
    +
    +
    + { issue.title } +
    +
    +
  • + ) + }) + } +
+
+
+
+ View More +
+
+
+
+ + Bugzilla ({ this.state.counts.bugzilla }) +
+
+ + Github ({ this.state.counts.github }) +
+
+ + Pagure ({ this.state.counts.pagure }) +
+
+ +
+
+
+
+ ) + } +} + +IssuesWidget.propTypes = { + widget: PropTypes.object.isRequired, + editMode: PropTypes.bool, + needsUpdate: PropTypes.bool, +}; diff --git a/hubs/widgets/issues/__init__.py b/hubs/widgets/issues/__init__.py index c4bfd8f..343cef7 100644 --- a/hubs/widgets/issues/__init__.py +++ b/hubs/widgets/issues/__init__.py @@ -1,92 +1,55 @@ from __future__ import unicode_literals -from hubs.widgets import validators -from hubs.widgets.base import Widget -from hubs.widgets.caching import CachedFunction -from hubs.widgets.view import RootWidgetView +import arrow +import flask -import requests +from hubs.widgets.base import Widget +from hubs.widgets.view import WidgetView +from .functions import * class Issues(Widget): name = "issues" label = "Issues" - position = "left" - parameters = [] - - -class BaseView(RootWidgetView): - - def get_context(self, instance, *args, **kwargs): - bugzilla_bugs = GetBugzillaBugs(instance) - github_issues = GetGithubIssues(instance) - pagure_issues = GetPagureIssues(instance) - return dict( - bugzilla_bugs=bugzilla_bugs(), - github_issues=github_issues(), - pagure_issues=pagure_issues() + position = "both" + parameters = [ + dict( + name="mode", + default=1, ) + ] + is_react = True + + def get_props(self, instance, *args, **kwargs): + props = super(Issues, self).get_props(instance, *args, **kwargs) + if instance is not None: + hub_name = instance.hub.name + props.update(dict( + title="Issues - " + + ("Tickets I Filed" if int(instance.config["mode"]) == 1 else "Tickets Waiting on Me"), + urls=dict( + data=flask.url_for( + "issues_data", hub=hub_name, idx=instance.idx), + ) + )) + return props + + +class DataView(WidgetView): + """Get issues in JSON format.""" + + name = "data" + url_rules = ["data"] + json = True + def get_context(self, instance, *args, **kwargs): + [bugzilla, bzcnt] = GetBugzillaBugs(instance)() + [pagure, pcnt] = GetPagureIssues(instance)() + [github, ghcnt] = GetGithubIssues(instance)() -class GetBugzillaBugs(CachedFunction): - - def execute(self): - email = self.instance.hub.config["bugzilla_email"] - endpoint = "https://bugzilla.redhat.com/jsonrpc.cgi?method=Bug.search¶ms=[{{\"creator\":\"{}\"}}]" - response = requests.get(endpoint.format(email)).json() - issues = response['result']['bugs'] - issues = issues[:min(5, len(issues))] - return issues - - def should_invalidate(self, message): - return False - - def should_invalidate_on_hub_config_change(self, old_config): - return True - - # For testing purposes - def _should_cache(self, value): - return False - - -class GetPagureIssues(CachedFunction): - - def execute(self): - username = self.instance.hub.config["pagure_username"] - endpoint = "https://pagure.io/api/0/user/{}/issues" - response = requests.get(endpoint.format(username)).json() - issues = response['issues_created'] - issues = issues[:min(5, len(issues))] - return issues - - def should_invalidate(self, message): - return False - - def should_invalidate_on_hub_config_change(self, old_config): - return True - - # For testing purposes - def _should_cache(self, value): - return False - - -class GetGithubIssues(CachedFunction): - - def execute(self): - username = self.instance.hub.config["github_username"] - endpoint = "https://api.github.com/search/issues?q=is:issue+author:{}&sort:updated" - response = requests.get(endpoint.format(username)).json() - issues = response['items'] - issues = issues[:min(5, len(issues))] - return issues - - def should_invalidate(self, message): - return False - - def should_invalidate_on_hub_config_change(self, old_config): - return True + all_issues = bugzilla + pagure + github + all_issues.sort(key=lambda x: arrow.get(x["updated_at"]), reverse=True) - # For testing purposes - def _should_cache(self, value): - return False + data = {"issues": all_issues, "counts": {"bugzilla": bzcnt, "pagure": pcnt, "github": ghcnt}} + return dict(status="OK", data=data) diff --git a/hubs/widgets/issues/functions.py b/hubs/widgets/issues/functions.py new file mode 100644 index 0000000..68b177d --- /dev/null +++ b/hubs/widgets/issues/functions.py @@ -0,0 +1,95 @@ +import requests + +from hubs.widgets.caching import CachedFunction + + +class GetBugzillaBugs(CachedFunction): + + def execute(self): + email = self.instance.hub.config["bugzilla_email"] + endpoint = "https://bugzilla.redhat.com/jsonrpc.cgi?method=Bug.search¶ms=[{{\"{}\":\"{}\"}}]" + mode = "creator" if int(self.instance.config["mode"]) == 1 else "assigned_to" + response = requests.get(endpoint.format(mode, email)).json() + issues = response['result']['bugs'] + issues = issues[:min(5, len(issues))] + urltmpl = 'https://bugzilla.redhat.com/show_bug.cgi?id={}' + res = [] + for issue in issues: + res.append(dict( + number=issue['id'], + title=issue['summary'], + project=issue['product'], + url=urltmpl.format(issue['id']), + updated_at=issue['last_change_time'], + service='bugzilla', + icon='https://bugzilla.redhat.com/favicon.ico' + )) + total_count = len(response['result']['bugs']) + return [res, total_count] + + def should_invalidate(self, message): + return False + + def should_invalidate_on_hub_config_change(self, old_config): + return True + + +class GetPagureIssues(CachedFunction): + + def execute(self): + username = self.instance.hub.config["pagure_username"] + endpoint = "https://pagure.io/api/0/user/{}/issues?author={}" + author = "true" if int(self.instance.config["mode"]) == 1 else "false" + response = requests.get(endpoint.format(username, author)).json() + issues = response['issues_created'] if author == "true" else response['issues_assigned'] + issues = issues[:min(5, len(issues))] + urltmpl = 'https://pagure.io/{}/issue/{}' + res = [] + for issue in issues: + res.append(dict( + number=issue['id'], + title=issue['title'], + project=issue['project']['name'], + url=urltmpl.format(issue['project']['url_path'], issue['id']), + updated_at=issue['last_updated'], + service='pagure', + icon='https://pagure.io/static/favicon.ico' + )) + total_count = len(response['issues_created'] if author == "true" else response['issues_assigned']) + return [res, total_count] + + def should_invalidate(self, message): + return False + + def should_invalidate_on_hub_config_change(self, old_config): + return True + + +class GetGithubIssues(CachedFunction): + + def execute(self): + username = self.instance.hub.config["github_username"] + endpoint = "https://api.github.com/search/issues?q=type:issue+{}:{}+state:open&sort:updated" + mode = "author" if int(self.instance.config["mode"]) == 1 else "assignee" + response = requests.get(endpoint.format(mode, username)).json() + issues = response['items'] + issues = issues[:min(5, len(issues))] + res = [] + for issue in issues: + res.append(dict( + number=issue['number'], + title=issue['title'], + project=issue['repository_url'].split('/')[-1], + url=issue['html_url'], + updated_at=issue['updated_at'], + service='github', + icon='https://github.com/favicon.ico' + )) + total_count = response['total_count'] + return [res, total_count] + + def should_invalidate(self, message): + return False + + def should_invalidate_on_hub_config_change(self, old_config): + return True diff --git a/hubs/widgets/issues/templates/root.html b/hubs/widgets/issues/templates/root.html deleted file mode 100644 index 88e9b15..0000000 --- a/hubs/widgets/issues/templates/root.html +++ /dev/null @@ -1,110 +0,0 @@ -
Bugzilla
-
    - {% for bug in bugzilla_bugs %} -
  • - -
    -
    - - {{ bug.summary }} - -
    - - Reported by: {{ bug.creator }} - -- - {% if bug.assigned_to != "Nobody's working on this, feel free to take it" %} - Assigned to: {{ bug.assigned_to }} - {% else %} - Unassigned - {% endif %} - -
    -
  • - {% endfor %} -
- -
Github
-
    - {% for issue in github_issues %} -
  • - -
    -
    - - {{ issue.title }} - -
    - - Reported by: {{ issue.user.login }} - -- - {% if issue.assignee %} - Assigned to: {{ issue.assignee.login }} - {% else %} - Unassigned - {% endif %} - -
    -
  • - {% endfor %} -
- -
Pagure
-
    - {% for issue in pagure_issues %} -
  • - -
    -
    - - {{ issue.title }} - -
    - - Reported by: {{ issue.user.name }} - -- - {% if issue.assignee %} - Assigned to: {{ issue.assignee.name }} - {% else %} - Unassigned - {% endif %} - -
    -
  • - {% endfor %} -
- -{#
Bugzilla
#} -{#
    #} -{# {% for bug in bugzilla_bugs %}#} -{#
  • {{ bug.summary }}
  • #} -{# {% endfor %}#} -{#
#} -{##} -{#
Github
#} -{#
    #} -{# {% for issue in github_issues %}#} -{#
  • {{ issue.title }}
  • #} -{# {% endfor %}#} -{#
#} -{##} -{#
Pagure
#} -{#
    #} -{# {% for issue in pagure_issues %}#} -{#
  • {{ issue.title }}
  • #} -{# {% endfor %}#} -{#
#} From 6d32fe9dd8c1b1657b005ca3a337ff538e3fccf1 Mon Sep 17 00:00:00 2001 From: Shaily Date: Feb 05 2018 14:33:19 +0000 Subject: [PATCH 4/32] Issues: Rename details to VCS --- diff --git a/hubs/static/client/app/components/HubConfig/HubConfigDialog.js b/hubs/static/client/app/components/HubConfig/HubConfigDialog.js index 64d3f4c..88fe2d9 100644 --- a/hubs/static/client/app/components/HubConfig/HubConfigDialog.js +++ b/hubs/static/client/app/components/HubConfig/HubConfigDialog.js @@ -5,6 +5,7 @@ import { } from 'react-intl'; import PropTypes from 'prop-types'; import GeneralPanel from './HubConfigPanelGeneral'; +import VCSPanel from './HubConfigPanelVCS'; import UserPanel from './HubConfigPanelUser'; import CommunityPanel from './HubConfigPanelCommunity'; import MailingListPanel from './HubConfigPanelMailingList'; @@ -26,6 +27,10 @@ const messages = defineMessages({ id: "hubs.core.config.general", defaultMessage: "General", }, + vcs: { + id: "hubs.core.config.vcs", + defaultMessage: "Version Control", + }, owners: { id: "hubs.core.config.owners", defaultMessage: "Owners", @@ -186,6 +191,16 @@ export default class HubConfigDialog extends React.Component { /> ); } + else { + tabs.push( + } + handleChange={this.props.onConfigChange} + /> + ) + } return ( {e.preventDefault();}}> - - - {["pagure_username", "github_username", "bugzilla_email"].map(function(x, i) { - return ( -
- - -

- -

-
- ) - }, this)} - - - ); - } -} diff --git a/hubs/static/client/app/components/HubConfig/HubConfigPanelVCS.js b/hubs/static/client/app/components/HubConfig/HubConfigPanelVCS.js new file mode 100644 index 0000000..6df26cf --- /dev/null +++ b/hubs/static/client/app/components/HubConfig/HubConfigPanelVCS.js @@ -0,0 +1,85 @@ +import React from 'react'; +import { + defineMessages, + FormattedMessage, + } from 'react-intl'; + + +const messages = defineMessages({ + title: { + id: "hubs.core.config.vcs.title", + defaultMessage: "Version Control", + }, + intro: { + id: "hubs.core.config.vcs.intro", + defaultMessage: "Change VCS related details here.", + }, + pagure_username: { + id: "hubs.core.config.vcs.pagure_username", + defaultMessage: "Pagure Username", + }, + pagure_username_help: { + id: "hubs.core.config.vcs.pagure_username_help", + defaultMessage: "Your pagure username", + }, + github_username: { + id: "hubs.core.config.vcs.github_username", + defaultMessage: "Github Username", + }, + github_username_help: { + id: "hubs.core.config.vcs.github_username_help", + defaultMessage: "Your github username", + }, + bugzilla_email: { + id: "hubs.core.config.vcs.bugzilla_email", + defaultMessage: "Bugzilla E-mail", + }, + bugzilla_email_help: { + id: "hubs.core.config.vcs.bugzilla_email_help", + defaultMessage: "Your bugzilla e-mail address", + }, +}); + + +export default class VCSPanel extends React.Component { + + constructor(props) { + super(props); + this.handleChange = this.handleChange.bind(this); + } + + handleChange(e) { + const name = e.target.name, value = e.target.value; + this.props.handleChange(name, value); + } + + render() { + return ( +
{e.preventDefault();}}> + + + {["pagure_username", "github_username", "bugzilla_email"].map(function(x, i) { + return ( +
+ + +

+ +

+
+ ) + }, this)} + + + ); + } +} diff --git a/hubs/static/client/app/widgets/issues/Widget.js b/hubs/static/client/app/widgets/issues/Widget.js index 1c9a8d3..1a98c7b 100644 --- a/hubs/static/client/app/widgets/issues/Widget.js +++ b/hubs/static/client/app/widgets/issues/Widget.js @@ -99,8 +99,11 @@ export default class IssuesWidget extends React.PureComponent {
-
- View More +
+ View More +