Skip to content

Commit

Permalink
People assignment and de-assignment works, will need reload of page f…
Browse files Browse the repository at this point in the history
…or others still
  • Loading branch information
alneberg committed Jan 16, 2025
1 parent 23b7402 commit 3a418f1
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 18 deletions.
132 changes: 117 additions & 15 deletions run_dir/static/js/projects_components.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,7 @@ export const vProjectDetails = {
<i class="fa-regular fa-arrow-up-right-from-square"></i> Old Project Page
</a>
</h3>
<div class="col-auto ml-auto">
<h2>
<v-project-people-assignments :project_id="project_id" :as_modal="as_modal"></v-project-people-assignments>
</h2>
</div>
<v-project-people-assignments :project_id="project_id" :as_modal="as_modal" :in_card="false"></v-project-people-assignments>
</div>
<h2><span :class="'badge w-100 mt-1 mb-4 ' + status_bg_class">{{project_data.status}}</span></h2>
</div>
Expand Down Expand Up @@ -569,7 +565,7 @@ export const vProjectCard = {
</div>
<div class="col-auto ml-auto">
<h4>
<v-project-people-assignments :project_id="this.project_id" :as_modal="True"></v-project-people-assignments>
<v-project-people-assignments :project_id="this.project_id" :as_modal="true" :in_card="true"></v-project-people-assignments>
</h4>
</div>
</div>
Expand All @@ -595,10 +591,42 @@ export const vProjectCard = {

export const vProjectPeopleAssignments = {
name: 'v-project-people-assignments',
props: ['project_id', 'as_modal'],
props: ['project_id', 'as_modal', 'in_card'],
data: function() {
return {
people_menu_open: false,
search_phrase: ''
}
},
computed: {
people() {
return this.$root.project_people_assignments[this.project_id]
if (this.project_id in this.$root.project_people_assignments) {
return this.$root.project_people_assignments[this.project_id]
} else {
return []
}
},
matching_people() {
let people_list = {} // New object to be returned
for (let person_id in this.$root.all_users) {
let person = this.$root.all_users[person_id]
if (this.search_phrase == '') {
people_list[person_id] = person;
} else if (person.name == undefined) {
continue
} else if (person.name.toLowerCase().includes(this.search_phrase.toLowerCase())) {
people_list[person_id] = person
}
}

let sorted_people_list = Object.entries(people_list)
.sort(([, a], [, b]) => a.name.localeCompare(b.name))
.reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});

return sorted_people_list;
}
},
methods: {
Expand All @@ -608,15 +636,90 @@ export const vProjectPeopleAssignments = {
} else {
return identifier
}
}
},
name(identifier) {
if (this.$root.all_users[identifier]['name'] != '') {
return this.$root.all_users[identifier]['name']
} else {
return identifier
}
},
remove_from_project(person_id) {
console.log('Removing person from project')
this.$root.removePersonFromProject(this.project_id, person_id)
},
add_to_project(person_id) {
this.$root.addPersonToProject(this.project_id, person_id)
this.search_phrase = ''
},
togglePeopleMenu(event) {
if (this.people_menu_open) {
this.people_menu_open = false;
} else {
this.people_menu_open = true;
}
},
},
template:
/*html*/`
<template v-for="person in people">
<span class="badge rounded-pill bg-success mr-1">
{{ initials(person) }}
</span>
</template>
<div class="col-auto ml-auto">
<v-template v-if="in_card">
<h4>
<template v-for="person in people">
<span class="badge rounded-pill bg-success mr-1">
{{ initials(person) }}
</span>
</template>
</h4>
</v-template>
<v-template v-else>
<v-template v-if="!people_menu_open">
<h2>
<template v-for="person in people">
<span class="badge rounded-pill bg-success mr-1" @click="togglePeopleMenu">
{{ initials(person) }}
</span>
</template>
<button class="btn ml-2" @click="togglePeopleMenu"><i class="fa-solid fa-users mr-2"></i><i class="fa-solid fa-up-right-and-down-left-from-center"></i></button>
</h2>
</v-template>
<template v-if="people_menu_open">
<h3>
<template v-for="person_id in people">
<span class="badge rounded-pill bg-success mr-1" @click="togglePeopleMenu">
{{ name(person_id) }}
<button type="button" class="btn btn-lg m-0" @click="remove_from_project(person_id)"><i class="fa-regular fa-trash-can text-white"></i></button>
</span>
</template>
<div class="btn-group">
<span class="badge rounded-pill bg-success mr-1">
<button type="button" class="btn btn-lg" id="dropdown_add_person" data-toggle="dropdown" aria-expanded="false">
<i class="fa-solid fa-plus text-white"></i>
</button>
<div :class="['dropdown-menu', {'dropdown-menu-right': !as_modal}]" aria-labelledby="dropdown_add_person">
<form class="px-3 py-3">
<div class="form-group">
<label for="addPeopleInput" class="form-label">Add People</label>
<input type="text" class="form-control" id="addPeopleInput" placeholder="Search for person" v-model="this.search_phrase">
</div>
<div>
<template v-for="person_id in Object.keys(this.matching_people)">
<a class="dropdown-item" href="#" @click="add_to_project(person_id)">
{{ this.matching_people[person_id]['name'] }}
</a>
</template>
</div>
</form>
</div>
</span>
</div>
<button type="button" class="btn btn-close ml-1" aria-label="Close" @click="togglePeopleMenu"></button>
</h3>
</template>
</template>
</div>
`
}

Expand Down Expand Up @@ -799,7 +902,6 @@ export const vProjectCards = {
<div class="mx-2">
<div ref="project_cards_header">
<h1>Project Cards</h1>
{{ this.$root.all_users}}
<div class="card">
<div class="card-header py-3" @click="toggleCardFilterMenu">
<h5 class="mb-0">
Expand Down
33 changes: 32 additions & 1 deletion run_dir/static/js/projects_main_vue.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,17 +283,48 @@ const vProjectsStatus = {
}

axios
.post('/api/v1/people_assignments', post_body)
.post('/api/v1/list_people_assignments', post_body)
.then(response => {
let data = response.data
if (data !== null) {
this.project_people_assignments = Object.assign({}, this.project_people_assignments, data);
}
})
.catch(error => {
console.log(error)
this.error_messages.push('Unable to fetch people assignments, please try again or contact a system administrator.')
})
},
async addPersonToProject(project_id, person_id) {
axios
.put(`/api/v1/project/${project_id}/people/${person_id}`)
.then(response => {
let data = response.data
if ((data !== null) && (data[project_id] !== null)) {
this.project_people_assignments[project_id] = data['people'];
}
})
.catch(error => {
console.log(error)
this.error_messages.push('Unable to assign person to project, please try again or contact a system administrator.')
}
)
},
async removePersonFromProject(project_id, person_id) {
axios
.delete(`/api/v1/project/${project_id}/people/${person_id}`)
.then(response => {
let data = response.data
if ((data !== null) && (data[project_id] !== null)) {
this.project_people_assignments[project_id] = data['people'];
}
})
.catch(error => {
console.log(error)
this.error_messages.push('Unable to remove person from project, please try again or contact a system administrator.')
}
)
},
setupWebsocket() {
/* This is still a proof of concept */
// Taken from https://stackoverflow.com/a/10418013
Expand Down
61 changes: 61 additions & 0 deletions status/people_assignments.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,64 @@ def post(self):

self.set_header("Content-type", "application/json")
self.write(people_assignments)


class ProjectPeopleAssignmentDataHandler(SafeHandler):
def put(self, project_id, person_id):
if not project_id:
self.set_status(400)
return self.write("Error: no project_id supplied")
if not person_id:
self.set_status(400)
return self.write("Error: no person_id supplied")

people_assignments = self.application.cloudant.get_document(
db="people_assignments", doc_id=project_id
).get_result()

# TODO Handle the case if the document doesn't exist here

if "people" not in people_assignments:
people_assignments["people"] = []

if person_id in people_assignments["people"]:
# Should be nice enough to tolerate double assignments
pass
else:
people_assignments["people"].append(person_id)
self.application.cloudant.put_document(
db="people_assignments", doc_id=project_id, document=people_assignments
)

self.set_header("Content-type", "application/json")
self.write(people_assignments)

def delete(self, project_id, person_id):
if not project_id:
self.set_status(400)
return self.write("Error: no project_id supplied")
if not person_id:
self.set_status(400)
return self.write("Error: no person_id supplied")

people_assignments = self.application.cloudant.get_document(
db="people_assignments", doc_id=project_id
).get_result()

# TODO handle the case if the document doesn't exist here

if "people" not in people_assignments:
people_assignments["people"] = []
elif person_id not in people_assignments["people"]:
# Should be nice enough to tolerate double assignments
pass
else:
people_assignments["people"].remove(person_id)
self.application.cloudant.put_document(
db="people_assignments",
doc_id=project_id,
document=people_assignments,
)

self.set_header("Content-type", "application/json")
self.write(people_assignments)
12 changes: 10 additions & 2 deletions status_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@
from status.multiqc_report import MultiQCReportHandler
from status.ngisweden_stats import NGISwedenHandler
from status.ont_plot import ONTFlowcellPlotHandler, ONTFlowcellYieldHandler
from status.people_assignments import PeopleAssignmentsDataHandler
from status.people_assignments import (
PeopleAssignmentsDataHandler,
ProjectPeopleAssignmentDataHandler,
)
from status.pricing import (
AgreementDataHandler,
AgreementMarkSignHandler,
Expand Down Expand Up @@ -289,6 +292,7 @@ def __init__(self, settings):
("/api/v1/latest_sticky_run_note", LatestStickyNotesMultipleHandler),
("/api/v1/libpooling_queues", LibraryPoolingQueuesDataHandler),
("/api/v1/lims_project_data/([^/]*)$", LIMSProjectCloningHandler),
("/api/v1/list_people_assignments", PeopleAssignmentsDataHandler),
("/api/v1/mark_agreement_signed", AgreementMarkSignHandler),
("/api/v1/pricing_date_to_version", PricingDateToVersionDataHandler),
("/api/v1/pricing_exchange_rates", PricingExchangeRatesDataHandler),
Expand All @@ -299,8 +303,12 @@ def __init__(self, settings):
("/api/v1/proj_staged/([^/]*)$", DataDeliveryHandler),
("/api/v1/projects", ProjectsDataHandler),
("/api/v1/project/([^/]*)$", ProjectSamplesDataHandler),
("/api/v1/project/([^/]*)/people", ProjectPeopleAssignmentDataHandler),
(
"/api/v1/project/([^/]*)/people/([^/]*)$",
ProjectPeopleAssignmentDataHandler,
),
("/api/v1/project/([^/]*)/tickets", ProjectTicketsDataHandler),
("/api/v1/people_assignments", PeopleAssignmentsDataHandler),
("/api/v1/projects_fields", ProjectsFieldsDataHandler),
("/api/v1/project_summary/([^/]*)$", ProjectDataHandler),
("/api/v1/project_search/([^/]*)$", ProjectsSearchHandler),
Expand Down

0 comments on commit 3a418f1

Please sign in to comment.