Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9bd90f6
added changes from previous branch to avoid all files being commited
conwelld Jul 21, 2026
56d5a29
fixed some pr comments
conwelld Jul 21, 2026
faf1957
fixed some pr comments for css styling
conwelld Jul 21, 2026
1204269
fixed useless code
conwelld Jul 21, 2026
0f166c2
fixed department code
conwelld Jul 21, 2026
6f5850a
We have change the hard coded part with variable able to be flexible …
Jul 22, 2026
813f398
Temporary allocation logic will be replaced by the official shared se…
Jul 22, 2026
7584ffa
fix the review comment from Minran, all of them
DanielRukwasha Jul 27, 2026
e9a4415
Merge branch 'department-portal-base' into new-allocation-card, resol…
DanielRukwasha Jul 28, 2026
20b424c
Fix import after allocationUtilization rename to getAllocation, add i…
DanielRukwasha Jul 29, 2026
ee0e066
Address PR review comments: consolidate getAllocation return dict, ex…
DanielRukwasha Jul 30, 2026
6abd704
Merge branch 'department-portal-base' into new-allocation-card, resol…
DanielRukwasha Jul 30, 2026
8618b68
Adopt approval-status filtering from UsedAllocFunction branch in getA…
DanielRukwasha Jul 30, 2026
a0ba238
Polish the allocation card: dynamic Fall/Spring term label, "X of Y" …
munsakad Aug 3, 2026
86bee45
Merge branch 'department-portal-base' into new-allocation-card
munsakad Aug 3, 2026
45b13e0
Fix duplicate main.managePositions endpoint left over from the depart…
munsakad Aug 3, 2026
74bdd3a
Rework allocation rows to the "N hr: X contracts (out of Y allocation…
munsakad Aug 3, 2026
a7ca474
Address allocation card review: camelCase naming, stacked layout, con…
munsakad Aug 4, 2026
c7ef1ec
Merge branch 'department-portal-base' of https://github.com/BCStudent…
munsakad Aug 5, 2026
25d9a9b
Reuse allocationManager.py in getAllocation.py
munsakad Aug 5, 2026
f5640b3
Fix missing LaborReleaseForm import in demo_data.py
munsakad Aug 5, 2026
4c17019
Fix allocation card showing zeros for departments with only a draft a…
munsakad Aug 5, 2026
f3b43c6
removed unneccesary comments
munsakad Aug 5, 2026
6ae3931
removed department information in main routes
munsakad Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/controllers/main_routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ def injectGlobalData():
from app.controllers.main_routes import studentLaborEvaluation
from app.controllers.main_routes import search
from app.controllers.main_routes import studentResponse
from app.controllers.main_routes import departmentPortal
62 changes: 55 additions & 7 deletions app/controllers/main_routes/main_routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from flask import render_template, request, json, redirect, url_for, send_file, g, flash, jsonify
from peewee import JOIN, DoesNotExist
from peewee import JOIN, DoesNotExist, fn
from flask_bootstrap import forms
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
from functools import reduce
import operator
from app.models.department import Department
Expand All @@ -16,6 +17,9 @@
from app.login_manager import require_login, logout
from app.logic.getTableData import getDatatableData
from app.logic.banner import Banner
from app.models.allocation import Allocation
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
from app.logic.tracy import Tracy
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
from app.models.positionHistory import PositionHistory

@main_bp.route('/logout', methods=['GET'])
def triggerLogout():
Expand Down Expand Up @@ -51,9 +55,12 @@ def supervisorPortal():
@main_bp.route('/department/<org>', methods=['GET'])
@main_bp.route('/department/<org>/<account>', methods=['GET'])
def departmentPortal(org=None,account=None):
try:
dept = Department.get(Department.ORG == org, Department.ACCOUNT == account)
except (NameError, DoesNotExist):
if org and account:
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
try:
dept = Department.get(Department.ORG == org, Department.ACCOUNT == account)
except (NameError, DoesNotExist):
dept = None
else:
dept = None


Expand All @@ -62,11 +69,52 @@ def departmentPortal(org=None,account=None):
departments = list(Department.select().order_by(Department.isActive.desc(), Department.DEPT_NAME.asc()))
else:
departments = list(getDepartmentsForSupervisor(g.currentUser).order_by(Department.isActive.desc(), Department.DEPT_NAME.asc()))

try:
Comment thread
munsakad marked this conversation as resolved.
Outdated
allocation = Allocation.select(Allocation, Term).join(Term).where(Allocation.department == dept, Allocation.termCode == 202500).get()
except DoesNotExist:
allocation = None

totalPositions = Allocation.select(fn.SUM(Allocation.primary_10) + fn.SUM(Allocation.primary_12) + fn.SUM(Allocation.primary_15) + fn.SUM(Allocation.primary_20) + fn.sum(Allocation.secondary_5) + fn.SUM(Allocation.secondary_10)).where(Allocation.department == dept, Allocation.termCode == 202500).scalar() # Total allocated positions for this department/term, summed across all hour buckets
usedAllocation = len([hours for hours in LaborStatusForm.select(LaborStatusForm.weeklyHours).where(LaborStatusForm.department == dept, LaborStatusForm.termCode == 202500, LaborStatusForm.contractHours.is_null(True))]) # Count how many of those positions are currently filled (excludes contract/break-hour forms)

def count_workers(job_type, hours_bucket):
return LaborStatusForm.select().where(LaborStatusForm.department == dept, LaborStatusForm.termCode == 202500, LaborStatusForm.jobType == job_type, LaborStatusForm.weeklyHours == hours_bucket, LaborStatusForm.contractHours.is_null(True)).count()

usedPositions = {
"used_10": count_workers("Primary", "10"),
"used_12": count_workers("Primary", "12"),
"used_15": count_workers("Primary", "15"),
"used_20": count_workers("Primary", "20"),
"used_5_sec": count_workers("Secondary", "5"),
"used_10_sec": count_workers("Secondary", "10"),
}
break_allocation = LaborStatusForm.select(LaborStatusForm.contractHours).where(LaborStatusForm.department == dept, LaborStatusForm.termCode == 202500, LaborStatusForm.contractHours.is_null(False))
sumBreak = sum(form.contractHours or 0 for form in break_allocation)

return render_template('main/departmentPortal.html',
departments = departments,
department = dept)

department = dept,
allocation = allocation,
total_allocation = totalPositions,
used_allocation = usedAllocation,
term = g.openTerm.termName,
usedPositions = usedPositions,
break_hours = sumBreak,
)
@main_bp.route('/department/<org>/<account>/managepositions', methods=['GET'])
Comment thread
conwelld marked this conversation as resolved.
Outdated
def managePositions(org, account):
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
try:
dept = Department.get(Department.ORG == org, Department.ACCOUNT == account)
except DoesNotExist:
return render_template('errors/404.html'), 404

positions = Tracy().getPositionsFromDepartment(org, account)
print(positions)
return render_template('main/managepositions.html',
department = dept,
department_name = dept.DEPT_NAME,
positions = positions
)
@main_bp.route('/supervisorPortal/addUserToDept', methods=['GET', 'POST'])
Comment thread
munsakad marked this conversation as resolved.
Outdated
def addUserToDept():
userDeptData = request.form
Expand Down
1 change: 1 addition & 0 deletions app/models/positionHistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from app.models.department import Department

class PositionHistory(baseModel):
positionTitle = CharField()
Comment thread
munsakad marked this conversation as resolved.
positionCode = CharField()
department = ForeignKeyField(Department)
status = CharField()
Expand Down
1 change: 1 addition & 0 deletions app/static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ a {
background-clip: border-box;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
overflow: hidden;
}

.card-body {
Expand Down
75 changes: 75 additions & 0 deletions app/static/css/departmentPortal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.card {
border-radius: 1rem;
overflow: hidden;
width: 100%;
height: 100%;
min-width: 100%;
box-shadow: 2px 2px 4px rgba(100, 100, 100, 0.26);
}
.bi-suitcase-lg-fill { /* Bootstrap Icon */
border: 1px solid #c0c0c0;
border-radius: 8px;
padding: 3px 3.5px 1.5px 3.5px;
font-size: 3rem;
color:#6e6e6e;
}
.bi-clock {
Comment thread
munsakad marked this conversation as resolved.
border: 1px solid #c0c0c0;
border-radius: 8px;
padding: 3px 3.5px 1.5px 3.5px;
font-size: 3rem;
color:#6e6e6e;
}
.bi-info-circle {
padding: 3px 3.5px 1.5px 3.5px;
font-size: 1.5rem;
vertical-align: middle;
color:#6e6e6e;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 2%;
padding-right: 10px;
}
.allocation-list {
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 10px;
padding-right: 10px;
}
.primary-chart {
font-size: 1.2em;
padding-left: 7%;
}
.secondary-chart {
font-size: 1.2em;
padding-right: 7%;
}

.bi-people-fill { /* Bootstrap Icon for Members Card */
border: 1px solid #c0c0c0;
border-radius: 8px;
padding: 3px 3.5px 1.5px 3.5px;
font-size: 3rem;
color:#6e6e6e;
}

.card-group {
gap: 1rem;
}
.form-group {
width: 50%;
margin-left: auto ;
margin-right:auto;
}
.card-body {
padding: 1rem 1rem;
min-width: 100%
}
.row {
display: flex;
flex-wrap: wrap;
}
4 changes: 4 additions & 0 deletions app/static/js/departmentPortal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ $(document).ready(function() {
window.location = `/department/${deptData.org}/${deptData.account}`;
});
});

$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
47 changes: 45 additions & 2 deletions app/templates/main/departmentPortal.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
{% block scripts %}
{{super()}}
<script type="text/javascript" src="{{url_for('static', filename='js/departmentPortal.js') }}?u={{lastStaticUpdate}}"></script>
<link rel="stylesheet" type="text/css" href="/static/css/departmentPortal.css?u={{lastStaticUpdate}}"/>
{% endblock %}

{% block app_content %}
<h2 class="text-center">{% if department %} {{department.DEPT_NAME}} Portal {% else %} Choose a Department: {% endif %} </h2>


<!--selectpicker for department-->
<div class="form-group">
<select class="selectpicker"
Expand All @@ -22,6 +23,48 @@ <h2 class="text-center">{% if department %} {{department.DEPT_NAME}} Portal {% e
"<span>{{d.DEPT_NAME}}</span><small class='text-muted'> ({{d.ORG}}-{{d.ACCOUNT}}) </small>">{{d.DEPT_NAME}}</option>
{% endfor %}
</select>
</div>

{% if department %}
<div class="row g-3">
<div class="col-12 col-lg-4 ">
<section class="card" aria-labelledby="allocationTitle">
<div class="card-body">
<div class="media">
<div class="media-left media-middle">
<span aria-hidden="true" style="color: #424242; font-size: 24px;">
<i class="bi bi-clock"></i>
</span>
</div>
<div class="media-body media-middle">
<h1>Allocations</h1>
Comment thread
DanielRukwasha marked this conversation as resolved.
Outdated
</div>
<div class="header-container">
<h3>AY 2025-2026 <i class="bi bi-info-circle" data-toggle="tooltip" data-placement="top" title="All values are shown as Used/Given"></i></h3> <h3>{{used_allocation}}/{{total_allocation or 0}} Positions</h3>
</div>
<div class="allocation-list">
<ul class="primary-chart">
<li>10 Hour - {{usedPositions.used_10}}/{{allocation.primary_10}}</li>
<li>12 Hour - {{usedPositions.used_12}}/{{allocation.primary_12}}</li>
<li>15 Hour - {{usedPositions.used_15}}/{{allocation.primary_15}}</li>
<li>20 Hour - {{usedPositions.used_20}}/{{allocation.primary_20}}</li>
</ul>
<ul class="secondary-chart">
<li>5 Hour - {{usedPositions.used_5_sec}}/{{allocation.secondary_5}}</li>
<li>10 Hour - {{usedPositions.used_10_sec}}/{{allocation.secondary_10}}</li>
</ul>
</div>
<div class="header-container">
<h3>Break Hours <i class="bi bi-info-circle" data-toggle="tooltip" data-placement="top" title="the values do not reflect actual hours worked, but rather contracts fulfilled."></i></h3><h3>{{break_hours}}/{{allocation.breakHours or 0}} Hours</h3>
</div>
</div>
</div>
<div class="card-footer text-center">
<a href="/department/{{ department.ORG }}/{{ department.ACCOUNT }}/REPLACEME" class="btn btn-primary">View Allocations<span class="glyphicon glyphicon-chevron-right"></span></a>
</div>
</section>
</div>
</div>
{% endblock %}
{% endif %}

{% endblock %}
Loading