Add or remove organizations and teams from boards

This commit is contained in:
Emile NDAGIJIMANA 2021-07-05 11:27:38 +02:00
parent 6efcac2a0e
commit b236d95636
8 changed files with 622 additions and 0 deletions

View file

@ -31,6 +31,26 @@ template(name='homeSidebar')
+activities(mode="board")
template(name="membersWidget")
.board-widget.board-widget-members
h3
i.fa.fa-users
| {{_ 'organizations'}}
.board-widget-content
+boardOrgGeneral
.clearfix
br
hr
.board-widget.board-widget-members
h3
i.fa.fa-users
| {{_ 'teams'}}
.board-widget-content
+boardTeamGeneral
.clearfix
br
hr
.board-widget.board-widget-members
h3
i.fa.fa-users
@ -65,6 +85,30 @@ template(name="membersWidget")
button.js-member-invite-accept.primary {{_ 'accept'}}
button.js-member-invite-decline {{_ 'decline'}}
template(name="boardOrgGeneral")
table
tbody
tr
th {{_ 'displayName'}}
th
if currentUser.isBoardAdmin
a.member.orgOrTeamMember.add-member.js-manage-board-addOrg(title="{{_ 'add-members'}}")
i.fa.fa-plus
each org in currentBoard.activeOrgs
+boardOrgRow(orgId=org.orgId)
template(name="boardTeamGeneral")
table
tbody
tr
th {{_ 'displayName'}}
th
if currentUser.isBoardAdmin
a.member.orgOrTeamMember.add-member.js-manage-board-addTeam(title="{{_ 'add-members'}}")
i.fa.fa-plus
each currentBoard.activeteams
+boardTeamRow(teamId=this.teamId)
template(name="boardChangeColorPopup")
.board-backgrounds-list.clearfix
each backgroundColors
@ -409,6 +453,40 @@ template(name="leaveBoardPopup")
p {{_ 'leave-board-pop' boardTitle=board.title}}
button.js-confirm.negate.full(type="submit") {{_ 'leave-board'}}
template(name="addBoardOrgPopup")
select.js-boardOrgs#jsBoardOrgs
option(value="-1") {{_ 'organizations'}} :
each value in orgsDatas
option(value="{{value._id}}") {{_ value.orgDisplayName}}
template(name="removeBoardOrgPopup")
form
input.hide#hideOrgId(type="text" value=org._id)
label
| {{_ 'leave-board'}} ?
br
hr
div.buttonsContainer
input.primary.wide.leaveBoardBtn#leaveBoardBtn(type="submit" value="{{_ 'leave-board'}}")
input.primary.wide.cancelLeaveBoardBtn#cancelLeaveBoardBtn(type="submit" value="{{_ 'Cancel'}}")
template(name="addBoardTeamPopup")
select.js-boardTeams#jsBoardTeams
option(value="-1") {{_ 'teams'}} :
each value in teamsDatas
option(value="{{value._id}}") {{_ value.teamDisplayName}}
template(name="removeBoardTeamPopup")
form
input.hide#hideTeamId(type="text" value=team._id)
label
| {{_ 'leave-board'}} ?
br
hr
div.buttonsContainer
input.primary.wide.leaveBoardBtn#leaveBoardTeamBtn(type="submit" value="{{_ 'leave-board'}}")
input.primary.wide.cancelLeaveBoardBtn#cancelLeaveBoardTeamBtn(type="submit" value="{{_ 'Cancel'}}")
template(name="addMemberPopup")
.js-search-member
+esInput(index="users")

View file

@ -313,6 +313,8 @@ Template.membersWidget.events({
'click .js-member': Popup.open('member'),
'click .js-open-board-menu': Popup.open('boardMenu'),
'click .js-manage-board-members': Popup.open('addMember'),
'click .js-manage-board-addOrg': Popup.open('addBoardOrg'),
'click .js-manage-board-addTeam': Popup.open('addBoardTeam'),
'click .js-import': Popup.open('boardImportBoard'),
submit: this.onSubmit,
'click .js-import-board': Popup.open('chooseBoardSource'),
@ -1168,6 +1170,283 @@ BlazeComponent.extendComponent({
},
}).register('addMemberPopup');
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
});
},
onRendered() {
this.setLoading(false);
},
setError(error) {
this.error.set(error);
},
setLoading(w) {
this.loading.set(w);
},
isLoading() {
return this.loading.get();
},
events() {
return [
{
'keyup input'() {
this.setError('');
},
'change #jsBoardOrgs'() {
let currentBoard = Boards.findOne(Session.get('currentBoard'));
let selectElt = document.getElementById("jsBoardOrgs");
let selectedOrgId = selectElt.options[selectElt.selectedIndex].value;
let selectedOrgDisplayName = selectElt.options[selectElt.selectedIndex].text;
let boardOrganizations = [];
if(currentBoard.orgs !== undefined){
for(let i = 0; i < currentBoard.orgs.length; i++){
boardOrganizations.push(currentBoard.orgs[i]);
}
}
if(!boardOrganizations.some((org) => org.orgDisplayName == selectedOrgDisplayName)){
boardOrganizations.push({
"orgId": selectedOrgId,
"orgDisplayName": selectedOrgDisplayName,
"isActive" : true,
})
if (selectedOrgId != "-1") {
Meteor.call('setBoardOrgs', boardOrganizations, currentBoard._id);
}
}
Popup.close();
},
},
];
},
}).register('addBoardOrgPopup');
Template.addBoardOrgPopup.helpers({
orgsDatas() {
// return Org.find({}, {sort: { createdAt: -1 }});
let orgs = Org.find({}, {sort: { createdAt: -1 }});
return orgs;
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
});
},
onRendered() {
this.setLoading(false);
},
setError(error) {
this.error.set(error);
},
setLoading(w) {
this.loading.set(w);
},
isLoading() {
return this.loading.get();
},
events() {
return [
{
'keyup input'() {
this.setError('');
},
'click #leaveBoardBtn'(){
let stringOrgId = document.getElementById('hideOrgId').value;
let currentBoard = Boards.findOne(Session.get('currentBoard'));
let boardOrganizations = [];
if(currentBoard.orgs !== undefined){
for(let i = 0; i < currentBoard.orgs.length; i++){
if(currentBoard.orgs[i].orgId != stringOrgId){
boardOrganizations.push(currentBoard.orgs[i]);
}
}
}
Meteor.call('setBoardOrgs', boardOrganizations, currentBoard._id);
Popup.close();
},
'click #cancelLeaveBoardBtn'(){
Popup.close();
},
},
];
},
}).register('removeBoardOrgPopup');
Template.removeBoardOrgPopup.helpers({
org() {
return Org.findOne(this.orgId);
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
});
},
onRendered() {
this.setLoading(false);
},
setError(error) {
this.error.set(error);
},
setLoading(w) {
this.loading.set(w);
},
isLoading() {
return this.loading.get();
},
events() {
return [
{
'keyup input'() {
this.setError('');
},
'change #jsBoardTeams'() {
let currentBoard = Boards.findOne(Session.get('currentBoard'));
let selectElt = document.getElementById("jsBoardTeams");
let selectedTeamId = selectElt.options[selectElt.selectedIndex].value;
let selectedTeamDisplayName = selectElt.options[selectElt.selectedIndex].text;
let boardTeams = [];
if(currentBoard.teams !== undefined){
for(let i = 0; i < currentBoard.teams.length; i++){
boardTeams.push(currentBoard.teams[i]);
}
}
if(!boardTeams.some((team) => team.teamDisplayName == selectedTeamDisplayName)){
boardTeams.push({
"teamId": selectedTeamId,
"teamDisplayName": selectedTeamDisplayName,
"isActive" : true,
})
if (selectedTeamId != "-1") {
Meteor.call('setBoardTeams', boardTeams, currentBoard._id);
}
}
Popup.close();
},
},
];
},
}).register('addBoardTeamPopup');
Template.addBoardTeamPopup.helpers({
teamsDatas() {
let teams = Team.find({}, {sort: { createdAt: -1 }});
return teams;
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
});
},
onRendered() {
this.setLoading(false);
},
setError(error) {
this.error.set(error);
},
setLoading(w) {
this.loading.set(w);
},
isLoading() {
return this.loading.get();
},
events() {
return [
{
'keyup input'() {
this.setError('');
},
'click #leaveBoardTeamBtn'(){
let stringTeamId = document.getElementById('hideTeamId').value;
let currentBoard = Boards.findOne(Session.get('currentBoard'));
let boardTeams = [];
if(currentBoard.teams !== undefined){
for(let i = 0; i < currentBoard.teams.length; i++){
if(currentBoard.teams[i].teamId != stringTeamId){
boardTeams.push(currentBoard.teams[i]);
}
}
}
Meteor.call('setBoardTeams', boardTeams, currentBoard._id);
Popup.close();
},
'click #cancelLeaveBoardTeamBtn'(){
Popup.close();
},
},
];
},
}).register('removeBoardTeamPopup');
Template.removeBoardTeamPopup.helpers({
team() {
return Team.findOne(this.teamId);
},
});
Template.changePermissionsPopup.events({
'click .js-set-admin, click .js-set-normal, click .js-set-no-comments, click .js-set-comment-only, click .js-set-worker'(
event,

View file

@ -214,3 +214,13 @@
i.fa
padding: 8px 0px 8px 16px
font-weight: bold
#jsBoardOrgs, #jsBoardTeams
width: 90%
.leaveBoardBtn
background-color: green !important
.cancelLeaveBoardBtn
margin-left: 5% !important
background-color: red !important

View file

@ -19,6 +19,44 @@ template(name="userAvatarInitials")
svg.avatar.avatar-initials(viewBox="0 0 {{viewPortWidth}} 15")
text(x="50%" y="13" text-anchor="middle")= initials
template(name="orgAvatar")
a.member.orgOrTeamMember(class="js-member" title="{{orgData.orgDisplayName}}")
+boardOrgName(orgId=orgData._id)
template(name="boardOrgRow")
tr
if orgData.orgIsActive
td <s>{{ orgData.orgDisplayName }}</s>
else
td {{ orgData.orgDisplayName }}
td
if currentUser.isBoardAdmin
a.member.orgOrTeamMember.add-member.js-manage-board-removeOrg(title="{{_ 'remove-from-board'}}")
i.fa.fa-minus
template(name="boardTeamRow")
tr
if teamData.teamIsActive
td <s>{{ teamData.teamDisplayName }}</s>
else
td {{ teamData.teamDisplayName }}
td
if currentUser.isBoardAdmin
a.member.orgOrTeamMember.add-member.js-manage-board-removeTeam(title="{{_ 'remove-from-board'}}")
i.fa.fa-minus
template(name="boardOrgName")
svg.avatar.avatar-initials(viewBox="0 0 {{orgViewPortWidth}} 15")
text(x="50%" y="13" text-anchor="middle")= orgName
template(name="teamAvatar")
a.member.orgOrTeamMember(class="js-member" title="{{teamData.teamDisplayName}}")
+boardTeamName(orgId=orgData._id)
template(name="boardTeamName")
svg.avatar.avatar-initials(viewBox="0 0 {{teamViewPortWidth}} 15")
text(x="50%" y="13" text-anchor="middle")= teamName
template(name="userPopup")
.board-member-menu
.mini-profile-info

View file

@ -1,6 +1,8 @@
import Cards from '/models/cards';
import Avatars from '/models/avatars';
import Users from '/models/users';
import Org from '/models/org';
import Team from '/models/team';
Template.userAvatar.helpers({
userData() {
@ -46,6 +48,132 @@ Template.userAvatarInitials.helpers({
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
});
},
onRendered() {
this.setLoading(false);
},
setError(error) {
this.error.set(error);
},
setLoading(w) {
this.loading.set(w);
},
isLoading() {
return this.loading.get();
},
events() {
return [
{
'keyup input'() {
this.setError('');
},
'click .js-manage-board-removeOrg': Popup.open('removeBoardOrg'),
},
];
},
}).register('boardOrgRow');
Template.boardOrgRow.helpers({
orgData() {
const orgCollection = this.esSearch ? ESSearchResults : Org;
return orgCollection.findOne(this.orgId);
},
currentUser(){
return Meteor.user();
},
});
Template.boardOrgName.helpers({
orgName() {
const org = Org.findOne(this.orgId);
return org && org.orgDisplayName;
},
orgViewPortWidth() {
const org = Org.findOne(this.orgId);
return ((org && org.orgDisplayName.length) || 1) * 12;
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
});
},
onRendered() {
this.setLoading(false);
},
setError(error) {
this.error.set(error);
},
setLoading(w) {
this.loading.set(w);
},
isLoading() {
return this.loading.get();
},
events() {
return [
{
'keyup input'() {
this.setError('');
},
'click .js-manage-board-removeTeam': Popup.open('removeBoardTeam'),
},
];
},
}).register('boardTeamRow');
Template.boardTeamRow.helpers({
teamData() {
const teamCollection = this.esSearch ? ESSearchResults : Team;
return teamCollection.findOne(this.teamId);
},
currentUser(){
return Meteor.user();
},
});
Template.boardTeamName.helpers({
teamName() {
const team = Team.findOne(this.teamId);
return team && team.teamDisplayName;
},
teamViewPortWidth() {
const team = Team.findOne(this.teamId);
return ((team && team.teamDisplayName.length) || 1) * 12;
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');

View file

@ -227,6 +227,56 @@ Boards.attachSchema(
type: String,
allowedValues: ['public', 'private'],
},
orgs: {
/**
* the list of organizations that a board belongs to
*/
type: [Object],
optional: true,
},
'orgs.$.orgId':{
/**
* The uniq ID of the organization
*/
type: String,
},
'orgs.$.orgDisplayName':{
/**
* The display name of the organization
*/
type: String,
},
'orgs.$.isActive': {
/**
* Is the organization active?
*/
type: Boolean,
},
teams: {
/**
* the list of teams that a board belongs to
*/
type: [Object],
optional: true,
},
'teams.$.teamId':{
/**
* The uniq ID of the team
*/
type: String,
},
'teams.$.teamDisplayName':{
/**
* The display name of the team
*/
type: String,
},
'teams.$.isActive': {
/**
* Is the team active?
*/
type: Boolean,
},
color: {
/**
* The color of the board.
@ -695,6 +745,23 @@ Boards.helpers({
return _.where(this.members, { isActive: true });
},
activeOrgs() {
return _.where(this.orgs, { isActive: true });
},
// hasNotAnyOrg(){
// return this.orgs === undefined || this.orgs.length <= 0;
// },
activeteams() {
return _.where(this.teams, { isActive: true });
},
// hasNotAnyTeam(){
// return this.teams === undefined || this.teams.length <= 0;
// },
activeAdmins() {
return _.where(this.members, { isActive: true, isAdmin: true });
},
@ -1454,6 +1521,24 @@ if (Meteor.isServer) {
} else throw new Meteor.Error('error-board-notAMember');
} else throw new Meteor.Error('error-board-doesNotExist');
},
setBoardOrgs(boardOrgsArray, currBoardId){
check(boardOrgsArray, Array);
check(currBoardId, String);
Boards.update(currBoardId, {
$set: {
orgs: boardOrgsArray,
},
});
},
setBoardTeams(boardTeamsArray, currBoardId){
check(boardTeamsArray, Array);
check(currBoardId, String);
Boards.update(currBoardId, {
$set: {
teams: boardTeamsArray,
},
});
},
});
}

View file

@ -442,6 +442,8 @@ Users.safeFields = {
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
orgs: 1,
teams: 1,
};
if (Meteor.isClient) {

View file

@ -34,6 +34,8 @@ Meteor.publish('boards', function() {
description: 1,
color: 1,
members: 1,
orgs: 1,
teams: 1,
permission: 1,
type: 1,
sort: 1,