mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-11 08:51:32 +08:00
adds custom query to fetch teams data
This commit is contained in:
parent
782daabce1
commit
db16da7bd6
12 changed files with 141 additions and 39 deletions
|
|
@ -37,11 +37,11 @@ module ClientApi
|
||||||
end
|
end
|
||||||
|
|
||||||
def teams
|
def teams
|
||||||
{ teams: current_user.teams }
|
{ teams: current_user.teams_data }
|
||||||
end
|
end
|
||||||
|
|
||||||
def change_current_team
|
def change_current_team
|
||||||
team_id = params.fetch(:team_id) { raise MissingTeamError }
|
team_id = params.fetch(:team_id) { raise MissingTeamError }
|
||||||
unless current_user.teams.pluck(:id).include? team_id
|
unless current_user.teams.pluck(:id).include? team_id
|
||||||
raise MissingTeamError
|
raise MissingTeamError
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ export default {
|
||||||
all_teams: "All teams",
|
all_teams: "All teams",
|
||||||
in_team: "You are member of {num} team",
|
in_team: "You are member of {num} team",
|
||||||
in_teams: "You are member of {num} team",
|
in_teams: "You are member of {num} team",
|
||||||
|
leave_team_modal: {
|
||||||
|
title: "Leave team {teamName}"
|
||||||
|
},
|
||||||
account: "Account",
|
account: "Account",
|
||||||
team: "Team",
|
team: "Team",
|
||||||
avatar: "Avatar",
|
avatar: "Avatar",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types";
|
import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types";
|
||||||
|
|
||||||
export function leaveTeamModalShow(show, id) {
|
export function leaveTeamModalShow(show, id, teamName) {
|
||||||
return({
|
return({
|
||||||
payload: { show, id },
|
payload: { show, id, teamName },
|
||||||
type: SHOW_LEAVE_TEAM_MODAL
|
type: SHOW_LEAVE_TEAM_MODAL
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
|
import PropTypes, { bool, number, string } from "prop-types";
|
||||||
import { Modal, Button } from "react-bootstrap";
|
import { Modal, Button } from "react-bootstrap";
|
||||||
|
import _ from "lodash";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
class LeaveTeamModal extends Component {
|
class LeaveTeamModal extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Modal show={this.props.showModal}>
|
<Modal show={this.props.showModal}>
|
||||||
<Modal.Header closeButton>
|
<Modal.Header closeButton>
|
||||||
<Modal.Title>
|
<Modal.Title>
|
||||||
<FormattedMessage id="activities.modal_title" />
|
<FormattedMessage
|
||||||
|
id="settings_page.leave_team_modal.title"
|
||||||
|
values={{ teamName: this.props.teamName }}
|
||||||
|
/>
|
||||||
</Modal.Title>
|
</Modal.Title>
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body>BANANAN</Modal.Body>
|
<Modal.Body>BANANAN</Modal.Body>
|
||||||
|
|
@ -23,9 +29,24 @@ class LeaveTeamModal extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LeaveTeamModal.propTypes = {
|
||||||
|
showModal: bool.isRequired,
|
||||||
|
teamId: number.isRequired,
|
||||||
|
teamName: string.isRequired,
|
||||||
|
teams: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
id: number.isRequired,
|
||||||
|
name: string.isRequired,
|
||||||
|
current_team: bool.isRequired,
|
||||||
|
role: string.isRequired,
|
||||||
|
members: number.isRequired,
|
||||||
|
}).isRequired
|
||||||
|
)
|
||||||
|
};
|
||||||
const mapStateToProps = ({ showLeaveTeamModal }) => ({
|
const mapStateToProps = ({ showLeaveTeamModal }) => ({
|
||||||
showModal: showLeaveTeamModal.show,
|
showModal: showLeaveTeamModal.show,
|
||||||
teamId: showLeaveTeamModal.id
|
teamId: showLeaveTeamModal.id,
|
||||||
|
teamName: showLeaveTeamModal.teamName
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(LeaveTeamModal);
|
export default connect(mapStateToProps)(LeaveTeamModal);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import { SHOW_LEAVE_TEAM_MODAL } from '../../app/action_types'
|
import { SHOW_LEAVE_TEAM_MODAL } from "../../app/action_types";
|
||||||
|
|
||||||
export function showLeaveTeamModal(state = {show: false, id: 0}, action) {
|
export function showLeaveTeamModal(
|
||||||
if(action.type ===SHOW_LEAVE_TEAM_MODAL) {
|
state = { show: false, id: 0, teamName: "" },
|
||||||
return {...state, ...action.payload}
|
action
|
||||||
|
) {
|
||||||
|
if (action.type === SHOW_LEAVE_TEAM_MODAL) {
|
||||||
|
return { ...state, ...action.payload };
|
||||||
}
|
}
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes, { number, string, bool } from "prop-types";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
@ -38,9 +38,11 @@ const SettingsTeams = ({ teams }) =>
|
||||||
SettingsTeams.propTypes = {
|
SettingsTeams.propTypes = {
|
||||||
teams: PropTypes.arrayOf(
|
teams: PropTypes.arrayOf(
|
||||||
PropTypes.shape({
|
PropTypes.shape({
|
||||||
id: PropTypes.number.isRequired,
|
id: number.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: string.isRequired,
|
||||||
current_team: PropTypes.bool.isRequired
|
current_team: bool.isRequired,
|
||||||
|
role: string.isRequired,
|
||||||
|
members: number.isRequired,
|
||||||
}).isRequired
|
}).isRequired
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { TableHeaderColumn } from "react-bootstrap-table";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Button } from "react-bootstrap";
|
import { Button } from "react-bootstrap";
|
||||||
import { leaveTeamModalShow } from "../../../../../shared/actions/LeaveTeamActions";
|
import { leaveTeamModalShow } from "../../../../../shared/actions/LeaveTeamActions";
|
||||||
|
|
@ -8,12 +7,14 @@ import DataTable from "../../../../../shared/data_table";
|
||||||
class TeamsDataTable extends Component {
|
class TeamsDataTable extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.leaveTeamModal = this.leaveTeamModal.bind(this);
|
this.leaveTeamModal = this.leaveTeamModal.bind(this);
|
||||||
|
this.leaveTeamButton = this.leaveTeamButton.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveTeamModal(e, id) {
|
leaveTeamModal(e, id) {
|
||||||
e.peventDefault();
|
const team = _.find(this.props.teams, el => el.id === id);
|
||||||
this.props.leaveTeamModalShow(true, id);
|
this.props.leaveTeamModalShow(true, id, team.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveTeamButton(id) {
|
leaveTeamButton(id) {
|
||||||
|
|
@ -23,23 +24,33 @@ class TeamsDataTable extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
const columns = [
|
||||||
<DataTable data={this.props.teams}>
|
{ id: "name", name: "Name", isKey: false, textId: "name", position: 0 },
|
||||||
<TableHeaderColumn isKey dataField="name">
|
{ id: "role", name: "Role", isKey: false, textId: "role", position: 1 },
|
||||||
Name
|
{
|
||||||
</TableHeaderColumn>
|
id: "members",
|
||||||
<TableHeaderColumn dataField="role">Role</TableHeaderColumn>
|
name: "Members",
|
||||||
<TableHeaderColumn dataField="members">Memebers</TableHeaderColumn>
|
isKey: false,
|
||||||
<TableHeaderColumn dataField="id" dataFormat={this.leaveTeamButton} />
|
textId: "members",
|
||||||
</DataTable>
|
position: 2
|
||||||
);
|
},
|
||||||
|
{
|
||||||
|
id: "id",
|
||||||
|
name: "",
|
||||||
|
isKey: true,
|
||||||
|
textId: "id",
|
||||||
|
dataFormat: this.leaveTeamButton,
|
||||||
|
position: 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return <DataTable data={this.props.teams} columns={columns} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// const mapDispatchToProps = dispatch => ({
|
||||||
|
// leaveTeamModalShow(show, id) {
|
||||||
|
// dispatch(leaveTeamModalShow(show, id));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
export default connect(null, { leaveTeamModalShow })(TeamsDataTable);
|
||||||
leaveTeamModalShow(show, id) {
|
|
||||||
dispatch(leaveTeamModalShow(show, id));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(TeamsDataTable);
|
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,21 @@ class User < ApplicationRecord
|
||||||
Team.find_by_id(self.current_team_id)
|
Team.find_by_id(self.current_team_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the data needed in all teams page
|
||||||
|
def teams_data
|
||||||
|
ActiveRecord::Base.connection.execute(
|
||||||
|
ActiveRecord::Base.send(
|
||||||
|
:sanitize_sql_array,
|
||||||
|
['SELECT teams.id AS id, teams.name AS name, user_teams.role ' \
|
||||||
|
'AS role, (SELECT COUNT(*) FROM user_teams WHERE ' \
|
||||||
|
'user_teams.team_id = teams.id) AS members, ' \
|
||||||
|
'CASE WHEN teams.id=? THEN true ELSE false END AS current_team ' \
|
||||||
|
'FROM teams INNER JOIN user_teams ON teams.id=user_teams.team_id ' \
|
||||||
|
'WHERE user_teams.user_id=?', self.current_team_id, self.id]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# Search all active users for username & email. Can
|
# Search all active users for username & email. Can
|
||||||
# also specify which team to ignore.
|
# also specify which team to ignore.
|
||||||
def self.search(
|
def self.search(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
json.teams do
|
json.teams do
|
||||||
json.collection teams do |team|
|
json.collection teams do |team|
|
||||||
json.id team.id
|
json.id team.fetch('id')
|
||||||
json.name team.name
|
json.name team.fetch('name')
|
||||||
json.current_team team == current_user.current_team
|
json.members team.fetch('members')
|
||||||
|
json.role UserTeam.roles.keys[team.fetch('role')]
|
||||||
|
json.current_team team.fetch('current_team')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
5
spec/factories/user_teams.rb
Normal file
5
spec/factories/user_teams.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
FactoryGirl.define do
|
||||||
|
factory :user_team do
|
||||||
|
role 'admin'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -149,4 +149,44 @@ describe User, type: :model do
|
||||||
expect(user.name).to eq 'Axe'
|
expect(user.name).to eq 'Axe'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'teams_data should return a list of teams' do
|
||||||
|
# needs persistence because is testing a sql query
|
||||||
|
let(:team) { create :team }
|
||||||
|
let(:user_one) do
|
||||||
|
create :user, email: 'user1@asdf.com', current_team_id: team.id
|
||||||
|
end
|
||||||
|
let(:user_two) { create :user, email: 'user2@asdf.com' }
|
||||||
|
|
||||||
|
it 'in a specific format' do
|
||||||
|
create :user_team, team: team, user: user_one
|
||||||
|
expected_result = {
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
members: 1,
|
||||||
|
role: 2,
|
||||||
|
current_team: true
|
||||||
|
}
|
||||||
|
|
||||||
|
user_one.teams_data.first.each do |k, v|
|
||||||
|
expect(v).to eq(expected_result.fetch(k.to_sym))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return correct number of team members' do
|
||||||
|
create :user_team, team: team, user: user_one
|
||||||
|
create :user_team, team: team, user: user_two
|
||||||
|
expected_result = {
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
members: 2,
|
||||||
|
role: 2,
|
||||||
|
current_team: true
|
||||||
|
}
|
||||||
|
|
||||||
|
user_one.teams_data.first.each do |k, v|
|
||||||
|
expect(v).to eq(expected_result.fetch(k.to_sym))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue