Merge pull request #9211 from edx/ammar/tnl-1909-support-joining-a-team
support joining a team
This commit is contained in:
@@ -312,3 +312,25 @@ class TeamPage(CoursePage, PaginatedUIMixin):
|
||||
def team_invite_url(self):
|
||||
"""Returns the url of invite link box"""
|
||||
return self.q(css='.page-content-secondary .invite-link-input').attrs('value')[0]
|
||||
|
||||
def click_join_team_button(self):
|
||||
""" Click on Join Team button"""
|
||||
self.q(css='.join-team .action-primary').first.click()
|
||||
self.wait_for_ajax()
|
||||
|
||||
@property
|
||||
def join_team_message(self):
|
||||
""" Returns join team message """
|
||||
self.wait_for_ajax()
|
||||
return self.q(css='.join-team .join-team-message').text[0]
|
||||
|
||||
@property
|
||||
def join_team_button_present(self):
|
||||
""" Returns True if Join Team button is present else False """
|
||||
self.wait_for_ajax()
|
||||
return self.q(css='.join-team .action-primary').present
|
||||
|
||||
@property
|
||||
def join_team_message_present(self):
|
||||
""" Returns True if Join Team message is present else False """
|
||||
return self.q(css='.join-team .join-team-message').present
|
||||
|
||||
@@ -997,3 +997,61 @@ class TeamPageTest(TeamsTabBase):
|
||||
invite_text='Send this link to friends so that they can join too.'
|
||||
)
|
||||
self.assertEqual(self.team_page.team_invite_url, '{0}?invite=true'.format(self.team_page.url))
|
||||
|
||||
def test_join_team(self):
|
||||
"""
|
||||
Scenario: User can join a Team if not a member already..
|
||||
|
||||
Given I am enrolled in a course with a team configuration, a topic,
|
||||
and a team belonging to that topic
|
||||
And I visit the Team page for that team
|
||||
Then I should see Join Team button
|
||||
When I click on Join Team button
|
||||
Then there should be no Join Team button and no message
|
||||
And I should see the updated information under Team Details
|
||||
"""
|
||||
self._set_team_configuration_and_membership(create_membership=False)
|
||||
self.team_page.visit()
|
||||
self.assertTrue(self.team_page.join_team_button_present)
|
||||
self.team_page.click_join_team_button()
|
||||
self.assertFalse(self.team_page.join_team_button_present)
|
||||
self.assertFalse(self.team_page.join_team_message_present)
|
||||
self.assert_team_details(num_members=1, invite_text='Send this link to friends so that they can join too.')
|
||||
|
||||
def test_already_member_message(self):
|
||||
"""
|
||||
Scenario: User should see `You are already in a team` if user is a
|
||||
member of other team.
|
||||
|
||||
Given I am enrolled in a course with a team configuration, a topic,
|
||||
and a team belonging to that topic
|
||||
And I am already a member of a team
|
||||
And I visit a team other than mine
|
||||
Then I should see `You are already in a team` message
|
||||
"""
|
||||
self._set_team_configuration_and_membership(membership_team_index=0, visit_team_index=1)
|
||||
self.team_page.visit()
|
||||
self.assertEqual(self.team_page.join_team_message, 'You already belong to another team.')
|
||||
self.assert_team_details(num_members=0, is_member=False)
|
||||
|
||||
def test_team_full_message(self):
|
||||
"""
|
||||
Scenario: User should see `Team is full` message when team is full.
|
||||
|
||||
Given I am enrolled in a course with a team configuration, a topic,
|
||||
and a team belonging to that topic
|
||||
And team has no space left
|
||||
And I am not a member of any team
|
||||
And I visit the team
|
||||
Then I should see `Team is full` message
|
||||
"""
|
||||
self._set_team_configuration_and_membership(
|
||||
create_membership=True,
|
||||
max_team_size=1,
|
||||
membership_team_index=0,
|
||||
visit_team_index=0,
|
||||
another_user=True
|
||||
)
|
||||
self.team_page.visit()
|
||||
self.assertEqual(self.team_page.join_team_message, 'This team is full.')
|
||||
self.assert_team_details(num_members=1, is_member=False, max_size=1)
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
define([
|
||||
'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team',
|
||||
'teams/js/views/team_join', 'teams/js/views/team_profile'
|
||||
], function (_, AjaxHelpers, TeamModel, TeamJoinView, TeamProfileView) {
|
||||
'use strict';
|
||||
describe('TeamJoinView', function () {
|
||||
var createTeamsUrl,
|
||||
createTeamModelData,
|
||||
createMembershipData,
|
||||
createJoinView,
|
||||
ACCOUNTS_API_URL = '/api/user/v1/accounts/',
|
||||
TEAMS_URL = '/api/team/v0/teams/',
|
||||
TEAMS_MEMBERSHIP_URL = '/api/team/v0/team_membership/';
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures(
|
||||
'<div class="msg-content"><div class="copy"></div></div><div class="header-action-view"></div>'
|
||||
);
|
||||
});
|
||||
|
||||
createTeamsUrl = function (teamId) {
|
||||
return TEAMS_URL + teamId + '?expand=user';
|
||||
};
|
||||
|
||||
createTeamModelData = function (teamId, teamName, membership) {
|
||||
return {
|
||||
id: teamId,
|
||||
name: teamName,
|
||||
membership: membership
|
||||
};
|
||||
};
|
||||
|
||||
createMembershipData = function (username) {
|
||||
return [
|
||||
{
|
||||
"user": {
|
||||
"username": username,
|
||||
"url": ACCOUNTS_API_URL + username
|
||||
}
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
createJoinView = function(maxTeamSize, currentUsername, teamModelData, teamId) {
|
||||
teamId = teamId || 'teamA';
|
||||
|
||||
var model = new TeamModel(teamModelData, { parse: true });
|
||||
model.url = createTeamsUrl(teamId);
|
||||
|
||||
var teamJoinView = new TeamJoinView(
|
||||
{
|
||||
model: model,
|
||||
teamsUrl: createTeamsUrl(teamId),
|
||||
maxTeamSize: maxTeamSize,
|
||||
currentUsername: currentUsername,
|
||||
teamMembershipsUrl: TEAMS_MEMBERSHIP_URL
|
||||
}
|
||||
);
|
||||
return teamJoinView.render();
|
||||
};
|
||||
|
||||
it('can render itself', function () {
|
||||
var teamModelData = createTeamModelData('teamA', 'teamAlpha', createMembershipData('ma'));
|
||||
var view = createJoinView(1, 'ma', teamModelData);
|
||||
|
||||
expect(view.$('.join-team').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('can join team successfully', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var currentUsername = 'ma1';
|
||||
var teamId = 'teamA';
|
||||
var teamName = 'teamAlpha';
|
||||
var teamModelData = createTeamModelData(teamId, teamName, []);
|
||||
var view = createJoinView(1, currentUsername, teamModelData);
|
||||
|
||||
// a get request will be sent to get user membership info
|
||||
// because current user is not member of current team
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'GET',
|
||||
TEAMS_MEMBERSHIP_URL + '?' + $.param({"username": currentUsername})
|
||||
);
|
||||
|
||||
// current user is not a member of any team so we should see the Join Team button
|
||||
AjaxHelpers.respondWithJson(requests, {"count": 0});
|
||||
expect(view.$('.action.action-primary').length).toEqual(1);
|
||||
|
||||
// a post request will be sent to add current user to current team
|
||||
view.$('.action.action-primary').click();
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'POST',
|
||||
TEAMS_MEMBERSHIP_URL,
|
||||
$.param({'username': currentUsername, 'team_id': teamId})
|
||||
);
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
|
||||
// on success, team model will be fetched and
|
||||
// join team view and team profile will be re-rendered
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'GET',
|
||||
createTeamsUrl(teamId)
|
||||
);
|
||||
AjaxHelpers.respondWithJson(
|
||||
requests, createTeamModelData(teamId, teamName, createMembershipData(currentUsername))
|
||||
);
|
||||
|
||||
// current user is now member of the current team then there should be no button and no message
|
||||
expect(view.$('.action.action-primary').length).toEqual(0);
|
||||
expect(view.$('.join-team-message').length).toEqual(0);
|
||||
});
|
||||
|
||||
it('shows already member message', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var currentUsername = 'ma1';
|
||||
var view = createJoinView(1, currentUsername, createTeamModelData('teamA', 'teamAlpha', []));
|
||||
|
||||
// a get request will be sent to get user membership info
|
||||
// because current user is not member of current team
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'GET',
|
||||
TEAMS_MEMBERSHIP_URL + '?' + $.param({"username": currentUsername})
|
||||
);
|
||||
|
||||
// current user is a member of another team so we should see the correct message
|
||||
AjaxHelpers.respondWithJson(requests, {"count": 1});
|
||||
expect(view.$('.action.action-primary').length).toEqual(0);
|
||||
expect(view.$('.join-team-message').text().trim()).toBe(view.alreadyMemberMessage);
|
||||
});
|
||||
|
||||
it('shows team full message', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var view = createJoinView(
|
||||
1,
|
||||
'ma1',
|
||||
createTeamModelData('teamA', 'teamAlpha', createMembershipData('ma'))
|
||||
);
|
||||
|
||||
// team has no space and current user is a not member of
|
||||
// current team so we should see the correct message
|
||||
expect(view.$('.action.action-primary').length).toEqual(0);
|
||||
expect(view.$('.join-team-message').text().trim()).toBe(view.teamFullMessage);
|
||||
|
||||
// there should be no request made
|
||||
expect(requests.length).toBe(0);
|
||||
});
|
||||
|
||||
it('shows correct error messages', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
var verifyErrorMessage = function (requests, errorMessage, expectedMessage) {
|
||||
createJoinView(1, 'ma', createTeamModelData('teamA', 'teamAlpha', []));
|
||||
AjaxHelpers.respondWithTextError(requests, 400, errorMessage);
|
||||
expect($('.msg-content .copy').text().trim()).toBe(expectedMessage);
|
||||
};
|
||||
|
||||
// verify user_message
|
||||
verifyErrorMessage(
|
||||
requests,
|
||||
JSON.stringify({'user_message': 'Awesome! You got an error.'}),
|
||||
'Awesome! You got an error.'
|
||||
);
|
||||
|
||||
// verify generic error message
|
||||
verifyErrorMessage(
|
||||
requests,
|
||||
'',
|
||||
'An error occurred. Try again.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
123
lms/djangoapps/teams/static/teams/js/views/team_join.js
Normal file
123
lms/djangoapps/teams/static/teams/js/views/team_join.js
Normal file
@@ -0,0 +1,123 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
|
||||
define(['backbone',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'teams/js/views/team_utils',
|
||||
'text!teams/templates/team-join.underscore'],
|
||||
function (Backbone, _, gettext, TeamUtils, teamJoinTemplate) {
|
||||
return Backbone.View.extend({
|
||||
|
||||
errorMessage: gettext("An error occurred. Try again."),
|
||||
alreadyMemberMessage: gettext("You already belong to another team."),
|
||||
teamFullMessage: gettext("This team is full."),
|
||||
|
||||
events: {
|
||||
"click .action-primary": "joinTeam"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.template = _.template(teamJoinTemplate);
|
||||
this.maxTeamSize = options.maxTeamSize;
|
||||
this.currentUsername = options.currentUsername;
|
||||
this.teamMembershipsUrl = options.teamMembershipsUrl;
|
||||
_.bindAll(this, 'render', 'joinTeam', 'getUserTeamInfo');
|
||||
this.listenTo(this.model, "change", this.render);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var message,
|
||||
showButton,
|
||||
teamHasSpace;
|
||||
|
||||
var view = this;
|
||||
this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) {
|
||||
teamHasSpace = info.teamHasSpace;
|
||||
|
||||
// if user is the member of current team then we wouldn't show anything
|
||||
if (!info.memberOfCurrentTeam) {
|
||||
showButton = !info.alreadyMember && teamHasSpace;
|
||||
|
||||
if (info.alreadyMember) {
|
||||
message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage;
|
||||
} else if (!teamHasSpace) {
|
||||
message = view.teamFullMessage;
|
||||
}
|
||||
}
|
||||
|
||||
view.$el.html(view.template({showButton: showButton, message: message}));
|
||||
});
|
||||
return view;
|
||||
},
|
||||
|
||||
joinTeam: function () {
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: view.teamMembershipsUrl,
|
||||
data: {'username': view.currentUsername, 'team_id': view.model.get('id')}
|
||||
}).done(function (data) {
|
||||
view.model.fetch({});
|
||||
}).fail(function (data) {
|
||||
try {
|
||||
var errors = JSON.parse(data.responseText);
|
||||
view.showMessage(errors.user_message);
|
||||
} catch (error) {
|
||||
view.showMessage(view.errorMessage);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getUserTeamInfo: function (username, maxTeamSize) {
|
||||
var deferred = $.Deferred();
|
||||
var info = {
|
||||
alreadyMember: false,
|
||||
memberOfCurrentTeam: false,
|
||||
teamHasSpace: false
|
||||
};
|
||||
|
||||
info.memberOfCurrentTeam = TeamUtils.isUserMemberOfTeam(this.model.get('membership'), username);
|
||||
var teamHasSpace = this.model.get('membership').length < maxTeamSize;
|
||||
|
||||
if (info.memberOfCurrentTeam) {
|
||||
info.alreadyMember = true;
|
||||
info.memberOfCurrentTeam = true;
|
||||
deferred.resolve(info);
|
||||
} else {
|
||||
if (teamHasSpace) {
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: view.teamMembershipsUrl,
|
||||
data: {'username': username}
|
||||
}).done(function (data) {
|
||||
info.alreadyMember = (data.count > 0);
|
||||
info.memberOfCurrentTeam = false;
|
||||
info.teamHasSpace = teamHasSpace;
|
||||
deferred.resolve(info);
|
||||
}).fail(function (data) {
|
||||
try {
|
||||
var errors = JSON.parse(data.responseText);
|
||||
view.showMessage(errors.user_message);
|
||||
} catch (error) {
|
||||
view.showMessage(view.errorMessage);
|
||||
}
|
||||
deferred.reject();
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(info);
|
||||
}
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
showMessage: function (message) {
|
||||
$('.wrapper-msg').removeClass('is-hidden');
|
||||
$('.msg-content .copy').text(message);
|
||||
$('.wrapper-msg').focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -15,10 +15,9 @@
|
||||
'click .invite-link-input': 'selectText'
|
||||
},
|
||||
initialize: function (options) {
|
||||
this.listenTo(this.model, "change", this.render);
|
||||
this.courseID = options.courseID;
|
||||
this.discussionTopicID = this.model.get('discussion_topic_id');
|
||||
this.maxTeamSize = options.maxTeamSize;
|
||||
this.memberships = this.model.get('membership');
|
||||
this.readOnly = options.readOnly;
|
||||
this.requestUsername = options.requestUsername;
|
||||
this.teamInviteUrl = options.teamInviteUrl;
|
||||
@@ -29,15 +28,17 @@
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var memberships = this.model.get('membership');
|
||||
var discussionTopicID = this.model.get('discussion_topic_id');
|
||||
this.$el.html(_.template(teamTemplate, {
|
||||
courseID: this.courseID,
|
||||
discussionTopicID: this.discussionTopicID,
|
||||
discussionTopicID: discussionTopicID,
|
||||
readOnly: this.readOnly,
|
||||
country: this.countries[this.model.get('country')],
|
||||
language: this.languages[this.model.get('language')],
|
||||
membershipText: TeamUtils.teamCapacityText(this.memberships.length, this.maxTeamSize),
|
||||
isMember: TeamUtils.isUserMemberOfTeam(this.memberships, this.requestUsername),
|
||||
hasCapacity: this.memberships.length < this.maxTeamSize,
|
||||
membershipText: TeamUtils.teamCapacityText(memberships.length, this.maxTeamSize),
|
||||
isMember: TeamUtils.isUserMemberOfTeam(memberships, this.requestUsername),
|
||||
hasCapacity: memberships.length < this.maxTeamSize,
|
||||
inviteLink: this.teamInviteUrl
|
||||
|
||||
}));
|
||||
@@ -52,7 +53,7 @@
|
||||
|
||||
renderTeamMembers: function() {
|
||||
var view = this;
|
||||
_.each(this.memberships, function(membership) {
|
||||
_.each(this.model.get('membership'), function(membership) {
|
||||
view.$('.members-info').append(_.template(teamMemberTemplate, {
|
||||
imageUrl: membership.user.profile_image.image_url_medium,
|
||||
username: membership.user.username,
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
'teams/js/views/my_teams',
|
||||
'teams/js/views/topic_teams',
|
||||
'teams/js/views/edit_team',
|
||||
'teams/js/views/team_join',
|
||||
'text!teams/templates/teams_tab.underscore'],
|
||||
function (Backbone, _, gettext, HeaderView, HeaderModel, TabbedView,
|
||||
TopicModel, TopicCollection, TeamModel, TeamCollection, TeamMembershipCollection,
|
||||
TopicsView, TeamProfileView, MyTeamsView, TopicTeamsView, TeamEditView,
|
||||
teamsTemplate) {
|
||||
TeamJoinView, teamsTemplate) {
|
||||
var TeamsHeaderModel = HeaderModel.extend({
|
||||
initialize: function (attributes) {
|
||||
_.extend(this.defaults, {nav_aria_label: gettext('teams')});
|
||||
@@ -241,7 +242,14 @@
|
||||
countries: self.countries
|
||||
}
|
||||
});
|
||||
deferred.resolve(self.createViewWithHeader(teamsView, topic));
|
||||
deferred.resolve(
|
||||
self.createViewWithHeader(
|
||||
{
|
||||
mainView: teamsView,
|
||||
subject: topic
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -277,33 +285,52 @@
|
||||
requestUsername: self.userInfo.username,
|
||||
countries: self.countries,
|
||||
languages: self.languages,
|
||||
teamInviteUrl: self.teamsBaseUrl + '#teams/' + topicID + '/' + teamID + '?invite=true'
|
||||
teamInviteUrl: self.teamsBaseUrl + '#teams/' + topicID + '/' + teamID + '?invite=true'
|
||||
});
|
||||
deferred.resolve(self.createViewWithHeader(view, team, topic));
|
||||
var teamJoinView = new TeamJoinView(
|
||||
{
|
||||
model: team,
|
||||
teamsUrl: self.teamsUrl,
|
||||
maxTeamSize: self.maxTeamSize,
|
||||
currentUsername: self.userInfo.username,
|
||||
teamMembershipsUrl: self.teamMembershipsUrl
|
||||
}
|
||||
);
|
||||
deferred.resolve(
|
||||
self.createViewWithHeader(
|
||||
{
|
||||
mainView: view,
|
||||
subject: team,
|
||||
parentTopic: topic,
|
||||
headerActionsView: teamJoinView
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
createViewWithHeader: function (mainView, subject, parentTopic) {
|
||||
createViewWithHeader: function (options) {
|
||||
var router = this.router,
|
||||
breadcrumbs, headerView;
|
||||
breadcrumbs = [{
|
||||
title: gettext('All Topics'),
|
||||
url: '#browse'
|
||||
}];
|
||||
if (parentTopic) {
|
||||
if (options.parentTopic) {
|
||||
breadcrumbs.push({
|
||||
title: parentTopic.get('name'),
|
||||
url: '#topics/' + parentTopic.id
|
||||
title: options.parentTopic.get('name'),
|
||||
url: '#topics/' + options.parentTopic.id
|
||||
});
|
||||
}
|
||||
headerView = new HeaderView({
|
||||
model: new TeamsHeaderModel({
|
||||
description: subject.get('description'),
|
||||
title: subject.get('name'),
|
||||
description: options.subject.get('description'),
|
||||
title: options.subject.get('name'),
|
||||
breadcrumbs: breadcrumbs
|
||||
}),
|
||||
headerActionsView: options.headerActionsView,
|
||||
events: {
|
||||
'click nav.breadcrumbs a.nav-item': function (event) {
|
||||
var url = $(event.currentTarget).attr('href');
|
||||
@@ -314,7 +341,7 @@
|
||||
});
|
||||
return new ViewWithHeader({
|
||||
header: headerView,
|
||||
main: mainView
|
||||
main: options.mainView
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="join-team form-actions">
|
||||
<% if (showButton) {%>
|
||||
<button class="action action-primary">
|
||||
<%- gettext("Join Team") %>
|
||||
</button>
|
||||
<% } else if (message) { %>
|
||||
<p class="join-team-message"><%- message %></p>
|
||||
<% } %>
|
||||
</div>
|
||||
@@ -8,6 +8,7 @@
|
||||
var HeaderView = Backbone.View.extend({
|
||||
initialize: function (options) {
|
||||
this.template = _.template(headerTemplate);
|
||||
this.headerActionsView = options.headerActionsView;
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.render();
|
||||
},
|
||||
@@ -15,6 +16,9 @@
|
||||
render: function () {
|
||||
var json = this.model.attributes;
|
||||
this.$el.html(this.template(json));
|
||||
if (this.headerActionsView) {
|
||||
this.headerActionsView.setElement(this.$('.header-action-view')).render();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -800,7 +800,8 @@
|
||||
'lms/include/teams/js/spec/views/teams_tab_spec.js',
|
||||
'lms/include/teams/js/spec/views/topic_card_spec.js',
|
||||
'lms/include/teams/js/spec/views/topic_teams_spec.js',
|
||||
'lms/include/teams/js/spec/views/topics_spec.js'
|
||||
'lms/include/teams/js/spec/views/topics_spec.js',
|
||||
'lms/include/teams/js/spec/views/team_join_spec.js'
|
||||
]);
|
||||
|
||||
}).call(this, requirejs, define);
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
|
||||
.action-view {
|
||||
@extend %btn-pl-default-base;
|
||||
float: right;
|
||||
@include float(right);
|
||||
margin: ($baseline/4) 0;
|
||||
}
|
||||
}
|
||||
@@ -242,11 +242,11 @@
|
||||
|
||||
.meta-detail {
|
||||
margin-top: ($baseline/4);
|
||||
margin-right: ($baseline*.75);
|
||||
@include margin-right ($baseline*.75);
|
||||
color: $gray;
|
||||
|
||||
.icon {
|
||||
margin-right: ($baseline/4);
|
||||
@include margin-right ($baseline/4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
}
|
||||
|
||||
.team-activity {
|
||||
float: right;
|
||||
@include float(right);
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
@@ -328,7 +328,7 @@
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: ($baseline/2);
|
||||
left: -($baseline/4);
|
||||
@include left(-($baseline/4));
|
||||
box-shadow: 1px 1px 1px 0 $blue-d1;
|
||||
background-color: $m-blue-l2;
|
||||
padding: ($baseline/10) ($baseline*.75);
|
||||
@@ -400,8 +400,8 @@
|
||||
display: inline-block;
|
||||
|
||||
@include tooltip-hover-style(-($baseline*2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.create-team {
|
||||
@@ -484,7 +484,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
.required-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 60%; // TODO: susy grid
|
||||
}
|
||||
|
||||
.optional-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 35%; // TODO: susy grid
|
||||
@include margin-left(2%);
|
||||
border-left: 2px solid $gray-l4;
|
||||
padding-left: 2%;
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: $baseline;
|
||||
}
|
||||
|
||||
@@ -512,25 +528,24 @@
|
||||
&:focus {
|
||||
border: 1px solid $link-color;
|
||||
color: $link-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.required-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 60%; // TODO: susy grid
|
||||
}
|
||||
.header-action-view {
|
||||
display: inline-block;
|
||||
width: 33%;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
.optional-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 35%; // TODO: susy grid
|
||||
margin-left: 2%;
|
||||
border-left: 2px solid $gray-l4;
|
||||
padding-left: 2%;
|
||||
.join-team.form-actions, .join-team-message {
|
||||
@include text-align(right);
|
||||
}
|
||||
}
|
||||
|
||||
.join-team-message {
|
||||
@extend %t-copy-sub1;
|
||||
color: $gray-l1;
|
||||
}
|
||||
|
||||
.team-actions {
|
||||
@extend %ui-well;
|
||||
margin: 20px 1.2%;
|
||||
@@ -687,3 +702,5 @@
|
||||
.create-team.form-actions {
|
||||
margin-top: $baseline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,4 +11,5 @@
|
||||
<h2 class="page-title"><%- title %></h2>
|
||||
<p class="page-description"><%- description %></p>
|
||||
</div>
|
||||
<div class="header-action-view"></div>
|
||||
</header>
|
||||
|
||||
Reference in New Issue
Block a user