[FIX] PMS: Bug fixing and style updations

This commit is contained in:
Horilla
2025-10-10 15:58:54 +05:30
parent dc912cde79
commit c94126736e
9 changed files with 742 additions and 197 deletions

View File

@@ -156,7 +156,7 @@
</ul>
</div>
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent">
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent" style="min-height: 467px;">
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
<span class="oh-card-dashboard__title"> {% trans "Objectives At-Risk" %}</span>
</div>
@@ -166,6 +166,8 @@
<div class="animated-background">
</div>
</div>
{% comment %} {% if okr_at_risk %}
<ul class="oh-card-dashboard__user-list">
{% for okr in okr_at_risk %}

View File

@@ -0,0 +1,171 @@
{% extends 'index.html' %}
{% load static i18n %}
{% load i18n %}
{% block content %}
<div class="oh-wrapper oh-card--w-resp-75">
<div class="p-6" style="border: 1px solid #ffffffff;padding: 80px;margin: 50px;background: white; border-radius:10px;">
<form action="{% url 'feedback-answer-post' id=feedback.id %}" method="post">
{% csrf_token %}
<!-- Header -->
<div class="oh-main__titlebar oh-main__titlebar--left mb-4 border-b pb-2">
<h3 class="text-lg font-semibold">{% trans "Feedback Answer" %}</h3>
</div>
<!-- Questions Section -->
<div class="oh-card p-6 space-y-6">
{% for q in questions %}
<div class="p-4 border border-gray-100 rounded-md bg-gray-30 hover:shadow-sm transition">
<span class="oh-label oh-label--question font-semibold text-gray-700 mb-2 block">
{{ forloop.counter }}. {{ q.question }}
</span>
{% if q.question_type == '1' %}
<!-- Text Question -->
<input type="text" class="oh-input w-full" name="answer{{ q.id }}" required />
{% endif %}
{% if q.question_type == '2' %}
<!-- Rating Question -->
<div class="oh-rate mt-2 flex items-center gap-3" style="flex-direction: row-reverse; justify-content: flex-end;">
<input type="radio" id="star5{{ q.id }}" name="answer{{ q.id }}" value="5" />
<label for="star5{{ q.id }}" title="5 {% trans 'Stars' %}"></label>
<input type="radio" id="star4{{ q.id }}" name="answer{{ q.id }}" value="4" />
<label for="star4{{ q.id }}" title="4 {% trans 'Stars' %}"></label>
<input type="radio" id="star3{{ q.id }}" name="answer{{ q.id }}" value="3" />
<label for="star3{{ q.id }}" title="3 {% trans 'Stars' %}"></label>
<input type="radio" id="star2{{ q.id }}" name="answer{{ q.id }}" value="2" />
<label for="star2{{ q.id }}" title="2 {% trans 'Stars' %}"></label>
<input type="radio" id="star1{{ q.id }}" name="answer{{ q.id }}" value="1" />
<label for="star1{{ q.id }}" title="1 {% trans 'Star' %}"></label>
</div>
{% endif %}
{% if q.question_type == '3' %}
<!-- Boolean Question -->
<div class="oh-input__group mt-2">
<div class="oh-input-picker-group flex gap-5">
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--4">
{% trans "Yes" %}
<input type="radio" name="answer{{ q.id }}" value="yes" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--1">
{% trans "No" %}
<input type="radio" name="answer{{ q.id }}" value="no" />
</label>
</div>
</div>
{% endif %}
{% if q.question_type == '4' %}
<!-- Multi-choice Question -->
<div class="mt-2 space-y-2">
{% for option in options %}
{% if option.question_id.id == q.id %}
<div class="flex flex-wrap gap-4">
<label class="custom-radio-container flex items-center gap-2">
<input type="radio" name="answer{{ q.id }}" value="{{ option.option_a }}" />
<span>{{ option.option_a }}</span>
</label>
<label class="custom-radio-container flex items-center gap-2">
<input type="radio" name="answer{{ q.id }}" value="{{ option.option_b }}" />
<span>{{ option.option_b }}</span>
</label>
<label class="custom-radio-container flex items-center gap-2">
<input type="radio" name="answer{{ q.id }}" value="{{ option.option_c }}" />
<span>{{ option.option_c }}</span>
</label>
<label class="custom-radio-container flex items-center gap-2">
<input type="radio" name="answer{{ q.id }}" value="{{ option.option_d }}" />
<span>{{ option.option_d }}</span>
</label>
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% if q.question_type == '5' %}
<!-- Likert Question -->
<div class="oh-input-picker-group oh-input-picker-group--resp mt-3 flex flex-wrap gap-3">
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--1">
{% trans "Strongly Disagree" %}
<input type="radio" name="answer{{ q.id }}" value="Strongly Disagree" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--2">
{% trans "Disagree" %}
<input type="radio" name="answer{{ q.id }}" value="Disagree" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--3">
{% trans "Neutral" %}
<input type="radio" name="answer{{ q.id }}" value="Neutral" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--4">
{% trans "Agree" %}
<input type="radio" name="answer{{ q.id }}" value="Agree" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--5">
{% trans "Strongly Agree" %}
<input type="radio" name="answer{{ q.id }}" value="Strongly Agree" />
</label>
</div>
{% endif %}
</div>
{% endfor %}
</div>
<!-- Key Results Section -->
{% if feedback.employee_key_results_id.all %}
<div class="oh-main__titlebar oh-main__titlebar--left mt-8 mb-3 border-b pb-2">
<h1 class="oh-main__titlebar-title fw-bold ml-3 text-lg">
{% trans "Key Result" %}
</h1>
</div>
<div class="oh-card p-6 space-y-6">
{% for key_result in feedback.employee_key_results_id.all %}
<div class="p-4 border border-gray-100 rounded-md bg-gray-30 hover:shadow-sm transition">
<span class="oh-label oh-label--question font-semibold text-gray-700 mb-2 block">
{{ forloop.counter }}. {{ key_result.key_result }}
</span>
<div class="oh-input-picker-group oh-input-picker-group--resp mt-2 flex flex-wrap gap-3">
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--4">
{% trans "Perfect" %}
<input type="radio" name="key_result{{ key_result.id }}" value="Perfect" required />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--3">
{% trans "Good" %}
<input type="radio" name="key_result{{ key_result.id }}" value="Good" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--2">
{% trans "Average" %}
<input type="radio" name="key_result{{ key_result.id }}" value="Average" />
</label>
<label class="oh-input-picker oh-input-picker--likert oh-input-picker--1">
{% trans "Bad" %}
<input type="radio" name="key_result{{ key_result.id }}" value="Bad" />
</label>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<!-- Footer -->
<div class="flex justify-end mt-6 mb-3">
<button type="submit" class="oh-btn oh-btn--secondary oh-btn--shadow px-5 py-2">
{% trans "Save" %}
</button>
</div>
</form>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,114 @@
{% extends 'index.html' %}
{% load static i18n %}
{% load i18n %}
{% block content %}
<style>
{% comment %} .oh-rate input[disabled] + label {
pointer-events: none; /* prevent hover and click */
} {% endcomment %}
.oh-rate input[disabled] ~ label {
pointer-events: none;
opacity: 0.6;
}
</style>
<div class="oh-wrapper w-75">
<div class="p-6" style="border: 1px solid #ffffffff;padding: 80px;margin: 50px;background: white; border-radius:10px;">
<div class="oh-main__titlebar oh-main__titlebar--left mb-5 border-b pb-2">
<h3 class="text-lg font-semibold">
{% trans "Feedback Responses" %}
</h3>
</div>
<div class="oh-activity-sidebar__body">
<ol class="oh-activity-sidebar__qa-list" role="list">
{% for answer in answers %}
<li class="oh-activity-sidebar__qa-item">
<span class="oh-activity-sidebar__q"> {{forloop.counter}}. {{answer.question_id.question}}?</span>
{% if answer.question_id.question_type == '1' %} <!--question type = Text-->
<span class="oh-activity-sidebar__a">{{ answer.answer.answer}}.</span>
{% endif %}
{% if answer.question_id.question_type == '2' %} <!--question type = Rating-->
<div class="d-block mb-0">
<div class="oh-rate">
<input type="radio" id="star5" value="5" disabled {% if answer.answer.answer == '5' %} checked {% endif %} />
<label for="star5" title="5 Stars">5 {% trans "Stars" %}</label>
<input type="radio" id="star4" value="4" disabled {% if answer.answer.answer == '4' %} checked {% endif %} />
<label for="star4" title="4 Stars">4 {% trans "Stars" %}</label>
<input type="radio" id="star3" value="3" disabled {% if answer.answer.answer == '3' %} checked {% endif %} />
<label for="star3" title="3 Stars">3 {% trans "Stars" %}</label>
<input type="radio" id="star2" value="2" disabled {% if answer.answer.answer == '2' %} checked {% endif %} />
<label for="star2" title="2 Stars">2 {% trans "Stars" %}</label>
<input type="radio" id="star1" value="1" disabled {% if answer.answer.answer == '1' %} checked {% endif %} />
<label for="star1" title="1 Star">1 {% trans "Star" %}</label>
</div>
</div>
{% endif %}
{% if answer.question_id.question_type == '3' %} <!--question type = Boolean-->
<div class="oh-input__group">
<div class="oh-input-picker-group">
<div class="oh-input-picker oh-input-picker--selected boolean-colour ">
{{answer.answer.answer}}
<input type="radio" selected />
</div>
</div>
</div>
{% endif %}
{% if answer.question_id.question_type == '4' %} <!--question type = Multi-choices-->
<div class="d-block">
<ul class="oh-questions mt-2">
<li class="oh-questions__answer">
<div class="oh-radio">
<input type="radio" class="oh-radio" id="answer1" name="answer{{q.id}}" value="{{option.option_a}}"
checked />
<span class="oh-radio__checkmark"></span>
<label class="oh-label" for="answer1"> {{answer.answer.answer}}</label>
</div>
</li>
</ul>
</div>
{% endif %}
{% if answer.question_id.question_type == '5' %} <!--question type = Likert-->
<div class="d-block">
<div class="oh-input-picker-group oh-input-picker-group--resp mt-2">
<div class="oh-input-picker oh-input-picker--likert likert-colour oh-input-picker--selected ">
{{answer.answer.answer}}
</div>
</div>
</div>
{% endif %}
</li>
{% endfor %}
{% if key_result_feedback %} <!-- if the user has key result selected in feedback -->
<div class="oh-main__titlebar oh-main__titlebar--left">
<h4 class="oh-main__titlebar-title fw-bold mb-0 mt-3">
{% trans "Key Results" %}
</h4>
</div>
{% for key_result in key_result_feedback %}
<li class="oh-activity-sidebar__qa-item">
<span class="oh-activity-sidebar__q"> {{forloop.counter}}. {{key_result.key_result_id.key_result}}</span>
<span
class="oh-input-picker {% if key_result.answer.answer == 'Perfect' %} oh-input-picker--likert likert-colour oh-input-picker--selected oh-input-picker--4
{% elif key_result.answer.answer == 'Good' %} oh-input-picker--likert likert-colour oh-input-picker--selected oh-input-picker--3
{% elif key_result.answer.answer == 'Average' %} oh-input-picker--likert likert-colour oh-input-picker--selected oh-input-picker--2
{% elif key_result.answer.answer == 'Bad' %} oh-input-picker--likert likert-colour oh-input-picker--selected oh-input-picker--1
{% endif %}"
>
{{key_result.answer.answer}}.
</span>
</li>
{% endfor %}
{% endif %}
</ol>
</div>
</div>
</div>
<script src="{% static 'src/feedback/feedback_answer.js' %}"></script>
{% endblock content %}

View File

@@ -15,6 +15,11 @@
</div>
</div>
{% endif %}
<style>
.select2-selection{
margin-bottom:18px; !important
}
</style>
<div class="oh-wrapper" id="message"></div>
<div class="bg-white p-5 pe-2 pt-3 rounded-md shadow-card w-full lg:w-2/4 m-auto">
@@ -139,198 +144,33 @@
</div>
</div>
<!-- end of period modal -->
<button
id="colleguesButton"
hx-get="{% url 'get-collegues' %}"
hx-target="#id_colleague_id"
hidden
></button>
<button
id="managerButton"
hx-get="{% url 'get-collegues' %}"
hx-target="#id_manager_id"
hidden
></button>
<button
id="subordinatesButton"
hx-get="{% url 'get-collegues' %}"
hx-target="#id_subordinate_id"
hidden
></button>
<button
id="keyresultButtton"
hx-get="{% url 'get-collegues' %}"
hx-target="#id_employee_key_results_id"
hidden
></button>
<script>
function get_collegues(element) {
var employee_id = $(element).val();
// Check if the employee_id is valid
// Dynamically set the hx-vals attribute for the manager, colleagues, subordinates, keyresult buttons
if (employee_id) {
$("#managerButton")
.attr(
"hx-vals",
JSON.stringify({
employee_id: employee_id,
data: "manager",
})
)
.click();
$("#colleguesButton")
.attr(
"hx-vals",
JSON.stringify({
employee_id: employee_id,
data: "colleagues",
})
)
.click();
$("#subordinatesButton")
.attr(
"hx-vals",
JSON.stringify({
employee_id: employee_id,
data: "subordinates",
})
)
.click();
$("#keyresultButtton")
.attr(
"hx-vals",
JSON.stringify({
employee_id: employee_id,
data: "keyresults",
})
)
.click();
} else {
console.error("Invalid employee_id");
}
}
</script>
<script src="{% static 'src/feedback/feedback_creation.js' %}"></script>
<script src="{% static 'src/period/period.js' %}"></script>
{% endblock%}
{% comment %} {% extends 'index.html' %}
{% load static i18n widget_tweaks %}
{% block styles %}
<link rel="stylesheet" href="{% static 'css/pms.css' %}" />
{% endblock styles %}
{% block content %}
{% if feedback_form.errors %}
<div class="oh-wrapper">
<div class="oh-alert-container">
{% for error in feedback_form.non_field_errors %}
<div class="oh-alert oh-alert--animated oh-alert--danger">
{{ error }}
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="oh-wrapper" id="message"></div>
<div class="bg-white p-5 pe-2 pt-3 rounded-md shadow-card w-full lg:w-2/4 m-auto">
<h3 class="text-lg font-semibold mb-3">{{feedback_form.verbose_name}}</h3>
<form action="{%url 'feedback-creation' %}" id="feedbackCreationForm" method="post">
{{feedback_form.non_field_errors}}
<div class="grid grid-cols-12 gap-4 h-[calc(100vh_-_260px)] overflow-hidden overflow-y-auto">
<div class="col-span-12 md:col-span-12">
<div class="p-4 border border-dark-50 rounded-md">
<label class="text-xs font-medium" for="{{feedback_form.review_cycle.id_for_label}}">{{feedback_form.review_cycle.label}}</label>
{{feedback_form.review_cycle}}
{{feedback_form.review_cycle.errors}}
<label class="text-xs font-medium" for="{{feedback_form.employee_id.id_for_label}}">{{feedback_form.employee_id.label}}</label>
{{feedback_form.employee_id }}
{{feedback_form.employee_id.errors }}
<label class="text-xs font-medium" for="{{feedback_form.manager_id.id_for_label}}">{{feedback_form.manager_id.label}}</label>
{{feedback_form.manager_id}}
{{feedback_form.manager_id.errros}}
<div class="flex items-center gap-1 pb-2 overflow-visible relative">
<label class="text-xs font-medium" for="{{feedback_form.subordinate_id.id_for_label}}">
{{ feedback_form.subordinate_id.label }}
</label>
<span class="oh-info" title="{{ feedback_form.subordinate_id.help_text|safe }}"></span>
</div>
{{feedback_form.subordinate_id}}
{{feedback_form.subordinate_id.errors}}
<div class="flex items-center gap-1 pb-2 overflow-visible relative">
<label class="text-xs font-medium" for="{{feedback_form.colleague_id.id_for_label}}">
{{ feedback_form.colleague_id.label }}
</label>
<span class="oh-info" title="{{ feedback_form.colleague_id.help_text|safe }}"></span>
</div>
{{feedback_form.colleague_id}}
{{feedback_form.colleague_id.errors}}
<label class="text-xs font-medium" for="{{feedback_form.others_id.id_for_label}}">{{feedback_form.others_id.label}}</label>
{{feedback_form.others_id}}
{{feedback_form.others_id.errros}}
<label class="text-xs font-medium" for="{{feedback_form.period.id_for_label}}">{{feedback_form.period.label}}</label>
{{feedback_form.period}}
{{feedback_form.period.errros}}
<label class="text-xs font-medium" for="{{feedback_form.start_date.id_for_label}}">{{feedback_form.start_date.label}}</label>
{{feedback_form.start_date}}
{{feedback_form.start_date.errros}}
<label class="text-xs font-medium" for="{{feedback_form.end_date.id_for_label}}">{{feedback_form.end_date.label}}</label>
{{feedback_form.end_date}}
{{feedback_form.end_date.errros}}
<label class="text-xs font-medium" for="{{feedback_form.question_template_id.id_for_label}}">{{feedback_form.question_template_id.label}}</label>
{{feedback_form.question_template_id}}
{{feedback_form.question_template_id.errros}}
<label class="text-xs font-medium" for="{{feedback_form.employee_key_results_id.id_for_label}}">{{feedback_form.employee_key_results_id.label}}</label>
{{feedback_form.employee_key_results_id}}
{{feedback_form.employee_key_results_id.errros}}
<!-- Limit Leave Days Toggle -->
<div class="flex items-center justify-between mb-2">
<label class="text-xs font-medium" for="{{feedback_form.cyclic_feedback.id_for_label}}">{{feedback_form.cyclic_feedback.label}}</label>
<div class="oh-switch">
{{feedback_form.cyclic_feedback}}
</div>
{{feedback_form.cyclic_feedback.errors}}
</div>
<label class="text-xs font-medium" for="{{feedback_form.cyclic_feedback_days_count.id_for_label}}">{{feedback_form.cyclic_feedback_days_count.label}}</label>
{{feedback_form.cyclic_feedback_days_count}}
{{feedback_form.cyclic_feedback_days_count.errros}}
</div>
</div>
</div>
<div class="flex gap-1 justify-end border-t border-dark-50 pt-3 mt-3">
<button
class="px-4 py-2 border border-primary-600 text-primary-600 rounded-md text-xs flex items-center gap-2 hover:text-white hover:bg-primary-800 transition duration-300">
Cancel
</button>
<button
class="px-4 py-2 bg-primary-600 text-white rounded-md text-xs flex items-center gap-2 hover:bg-primary-800 transition duration-300">
Save
</button>
</div>
</form>
</div>
<!-- period modal -->
<div
class="oh-modal"
id="PeriodModal"
role="dialog"
aria-labelledby="editKeyResultModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<!-- for creating period -->
<div class="oh-modal__dialog-header">
<button
type="button"
class="oh-modal__close"
aria-label="Close"
>
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div class="oh-modal__dialog-body" id="periodModalTarget"></div>
</div>
</div>
<!-- end of period modal -->
<script>
(document).ready(function () {
$(document).ready(function () {
get_collegues($("#id_employee_id"));
setTimeout(function () {
select = $("select");
@@ -385,9 +225,13 @@
console.error("Invalid employee_id");
}
}
$(document).ready(function(){
$("#feedbackCreationForm").find("select").select2({
width:'100%'
})
})
</script>
<script src="{% static 'src/feedback/feedback_creation.js' %}"></script>
<script src="{% static 'src/period/period.js' %}"></script>
{% endblock%} {% endcomment %}
{% endblock%}

View File

@@ -0,0 +1,106 @@
{% load static i18n audit_filters %}
<div id="generic-history-container">
<button hidden hx-get="{{ request.path }}" class="reload-record" hx-target="#generic-history-container" hx-swap="outerHTML"></button>
<div class="oh-activity-sidebar__header mt-5 sticky top-0 z-[100] bg-white pb-3">
<a style="cursor: pointer;" onclick="$('.oh-activity-sidebar--show').removeClass('oh-activity-sidebar--show');">
<ion-icon name="chevron-forward-outline" class="oh-activity-sidebar__header-icon me-2 oh-activity-sidebar__close md flip-rtl hydrated"></ion-icon>
</a>
<span class="oh-activity-sidebar__title fw-bold">{{ object }}'s Logs</span>
</div>
{% if tracking %}
<div class="relative max-w-[800px] m-auto pt-8 pb-10" style="margin-right:165px;">
<!-- Center vertical line -->
<div class="absolute left-1/2 transform -translate-x-1/2 h-full w-1 bg-[#dbdbdb] hidden md:block"></div>
<ul class="space-y-10">
{% for history in tracking %}
<li class="flex justify-between items-start relative">
<!-- Left side: Date/Time -->
<div class="md:w-1/2 md:pr-10 md:text-right mt-2 md:mt-0 order-1 md:order-none">
<div class="inline-block px-4 py-2 rounded-md text-center bg-primary-200 text-primary-600">
<span class="text-xs block font-semibold">
<span class="dateformat_changer">{{ history.pair.1.history_date|date:'M. d, Y' }}</span>
&nbsp,&nbsp
<span class="timeformat_changer">{{ history.pair.1.history_date|date:'g:i A' }}</span>
</span>
</div>
</div>
<!-- Timeline dot with user avatar -->
<div class="absolute top-0 left-1/2 transform -translate-x-1/2 z-10 w-10 h-10 rounded-full bg-white border-2 border-primary-600 flex items-center justify-center overflow-hidden">
<img src="{{ history.updated_by.get_avatar }}" alt="user" class="w-full h-full object-cover rounded-full" />
</div>
<!-- Right side: Details -->
<div class="md:w-1/2 md:pl-10 md:text-left mt-2">
<h5 class="text-xs font-semibold">
{{ history.updated_by.get_full_name|default:"Horilla Bot" }}
</h5>
{% if history.pair.0.history_title %}
<p class="text-xs text-[#777777] mb-2">{{ history.pair.0.history_title }}</p>
{% endif %}
{% if history.pair.0.history_description %}
<p class="text-xs text-[#777777] mb-2">{{ history.pair.0.history_description }}</p>
{% endif %}
{% if history.pair.0.history_tags.all %}
<div class="oh-history_tabs mb-2">
{% for tag in history.pair.0.history_tags.all %}
<a href="#" class="oh-history_msging-email oh-history_tabs-items">{{ tag.title }}</a>
{% endfor %}
</div>
{% endif %}
<div class="bg-white p-3 rounded-md border border-gray-200 shadow-sm">
<h3 class="text-primary-600 font-semibold text-xs mb-2">{% trans "Changes" %}</h3>
<ul class="space-y-1">
{% for change in history.changes %}
<li class="text-xs flex items-center justify-between gap-1">
<span>{{ history.pair.1|fk_history:change }}</span>
<img src="{% static '/images/ui/arrow-right-line.svg' %}" alt="→" class="w-3 h-3 inline-block" />
<span>{{ history.pair.0|fk_history:change }}</span>
<i class="text-gray-500 text-[10px]">({{ change.field }})</i>
</li>
{% endfor %}
</ul>
{% if has_perm_to_revert and history.pair.1.pk %}
<div class="mt-2 text-right">
<button hidden id="revert{{history.pair.1.pk}}" hx-post="{% url 'history-revert' object.pk history.pair.1.pk %}?model={{ model }}"></button>
<a href="javascript:void(0);" class="text-primary-600 text-xs" title="Restore previous state"
onclick="Swal.fire({
title: 'Are you sure?',
text: 'This will revert the object to a previous state.',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, revert it'
}).then(result => {
if (result.isConfirmed) {
document.getElementById('revert{{ history.pair.1.pk }}').click();
}
})">
<ion-icon name="git-pull-request-outline" class="text-base"></ion-icon>
{% trans "Revert" %}
</a>
</div>
{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>
</div>
{% else %}
<div class="oh-wrapper h-full text-center my-10">
<div class="bg-white p-6 rounded-md shadow-md inline-block">
<img src="{% static 'images/ui/history.png' %}" alt="No history" width="250" class="mx-auto mb-4" />
<p class="text-[#666] mb-2">{% trans "No history found." %}</p>
</div>
</div>
{% endif %}
</div>

View File

@@ -0,0 +1,307 @@
{% load i18n %}
{% load pmsfilters %}
<style>
/* ======= General Layout ======= */
.oh-activity-sidebar__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.8rem 1rem;
border-bottom: 1px solid #e5e7eb;
background-color: #f9fafb;
}
.oh-activity-sidebar__title {
font-size: 1rem;
font-weight: 600;
color: #374151;
}
.oh-activity-list {
list-style: none;
margin: 0;
padding: 0.5rem 1rem;
overflow-y: auto;
max-height: 75vh;
}
/* ======= Comment Styles ======= */
.oh-activity-list__comment-title {
margin-bottom: 0.3rem;
}
.oh-activity-list__comment-container {
background: #f3f4f6;
padding: 0.7rem 1rem;
border-radius: 10px;
margin-left: 2.5rem;
margin-bottom: 0.8rem;
position: relative;
}
.oh-activity-list__comment-container::before {
content: "";
position: absolute;
top: 8px;
left: -6px;
border-width: 6px;
border-style: solid;
border-color: transparent #f3f4f6 transparent transparent;
}
.oh-activity-list__comment {
font-size: 0.85rem;
color: #374151;
margin-bottom: 0;
line-height: 1.5;
}
.oh-activity-list__photo img {
border-radius: 50%;
width: 32px;
height: 32px;
}
.oh-activity-list__description strong {
color: #111827;
}
/* ======= Change Log / Activity ======= */
.oh-activity-list__item {
display: flex;
align-items: center;
font-size: 0.85rem;
color: #4b5563;
}
.oh-activity-list__item strong {
color: #111827;
}
.oh-activity-list li {
margin-bottom: 0.7rem;
}
.oh-activity-list small {
font-size: 0.75rem;
color: #6b7280;
}
/* ======= Editor Styles ======= */
#commentEditor {
padding: 0.8rem 1rem;
border-top: 1px solid #e5e7eb;
background: #fff;
}
.note-editor.note-frame {
border: 1px solid #d1d5db;
border-radius: 10px;
}
.note-toolbar {
border-bottom: 1px solid #e5e7eb !important;
}
.note-editable {
font-size: 0.9rem;
min-height: 60px;
}
/* Align send button right */
#commentEditor .note-toolbar .note-btn-group.send-group {
margin-left: auto;
}
#commentEditor .note-btn-group button {
background: #ff3b38;
color: white !important;
border-radius: 6px;
}
#commentEditor .note-btn-group button:hover {
background: #ff3b38;
}
/* Alert message styling */
.oh-alert {
font-size: 0.85rem;
border-radius: 8px;
margin: 0.8rem 1rem;
}
</style>
{% if messages %}
<div class="oh-wrapper">
{% for message in messages %}
<div class="oh-alert-container">
<div class="oh-alert oh-alert--animated {{ message.tags }}">{{ message }}</div>
</div>
{% endfor %}
</div>
{% endif %}
<div id="activityContainer">
<div class="oh-activity-sidebar__header mb-1" style="display:inline-flex; border:none; background:white;">
<a style="cursor: pointer;"
onclick="$('.oh-activity-sidebar--show').removeClass('oh-activity-sidebar--show');">
<ion-icon name="chevron-forward-outline"
class="oh-activity-sidebar__header-icon me-2 oh-activity-sidebar__close"
data-target="#leaveactivitySidebar"></ion-icon>
</a>
<span class="oh-activity-sidebar__title">{% trans 'Activities' %}</span>
</div>
<form method="post"
hx-target="#activityContainer"
hx-post="{% url 'objective-detailed-view-comment' objective.id %}"
id="commentForm">
{% csrf_token %}
<div id="commentEditor">
<textarea rows="2" cols="2" name="comment" id="editor"></textarea>
<button type="submit" id="commentButton"
class="oh-btn oh-btn--secondary mt-2 mr-0 oh-btn--w-100-resp"
style="display: none;">
{% trans 'Comment' %}
</button>
</div>
</form>
<ul class="oh-activity-list">
{% for activity in activity_list %}
{% if activity.type == 'Changes' %}
<ul class="d-flex justify-content-between align-items-center pt-3 mb-3 border-top">
<li class="oh-activity-list__item align-items-center mb-0">
<div class="oh-activity-list__photo oh-activity-list__photo--small me-2">
<img src="https://ui-avatars.com/api/?name={{ activity.updated_by }}&background=random" class="oh-activity-list__image" alt="Albert Camus" />
</div>
<small class="oh-activity-list__description">
<strong>{{ activity.updated_by }}</strong>
{% trans 'updated' %}
<strong>{{ activity.changes.0.field|title|cut:'_' }}</strong> {% trans 'from' %}
<strong>{{ activity.changes.0.old }}</strong> {% trans "to" %} <strong>{{ activity.changes.0.new }}</strong>
</small>
</li>
<li>
<small>
<span class="dateformat_changer">{{ activity.pair.0.history_date|date:'M. d, Y' }}</span>&nbsp,&nbsp
<span class="timeformat_changer">{{ activity.pair.0.history_date|date:'g:i a' }}</span>
</small>
</li>
</ul>
{% elif activity.type == 'key_result' %}
{% for history in activity.key_result.delta.changes %}
<ul class="d-flex justify-content-between align-items-center pt-3 mb-3 border-top">
<li class="oh-activity-list__item align-items-center mb-0">
<div class="oh-activity-list__photo oh-activity-list__photo--small me-2">
<img src="https://ui-avatars.com/api/?name={{ activity.key_result.changed_user }}&background=random" class="oh-activity-list__image" alt="Albert Camus" />
</div>
<small class="oh-activity-list__description">
<strong>{{ activity.key_result.changed_user }}</strong>
{% trans 'updated' %}
<strong>{{ history.field|replace|title }}</strong> {% trans 'field of ' %}
<strong>{{ activity.key_result.k_r }}</strong> {% trans 'key result' %},{% trans 'from' %}
<strong>{{ history.old }}</strong> {% trans 'to' %} <strong>{{ history.new }}</strong>
{% comment %} <strong>{{ activity.changes.0.field|title|cut:'_' }}</strong> {% trans 'from' %}
<strong>{{ activity.changes.0.old }}</strong> to <strong>{{ activity.changes.0.new }}</strong> {% endcomment %}
</small>
</li>
<li>
<small>
<span class="dateformat_changer">{{ activity.date|date:'M. d, Y' }}</span>&nbsp,&nbsp
<span class="timeformat_changer">{{ activity.date|date:'g:i a' }}</span>
</small>
</li>
</ul>
{% endfor %}
{% elif activity.type == 'comment' %}
<ul class="pt-3 border-top">
<div class="oh-activity-list__comment-title d-flex justify-content-between align-items-center">
<div class="oh-activity-list__item align-items-center mb-0">
<div class="oh-activity-list__photo oh-activity-list__photo--small me-2">
<img src="https://ui-avatars.com/api/?name={{ activity.comment.employee_id }}&background=random"
class="oh-activity-list__image"
alt="{{ activity.comment.employee_id }}" />
</div>
<small class="oh-activity-list__description">
<strong>{{ activity.comment.employee_id }}</strong>
{% trans 'added a comment' %}
</small>
</div>
<div>
<small>
<span class="dateformat_changer">{{ activity.comment.created_at|date:'M. d, Y' }}</span>&nbsp;&nbsp;
<span class="timeformat_changer">{{ activity.comment.created_at|date:'g:i a' }}</span>
</small>
</div>
</div>
<div class="oh-activity-list__comment-container">
<p class="oh-activity-list__comment">{{ activity.comment.comment|safe }}</p>
</div>
</ul>
{% else %}
<!-- Default activity / change history -->
<ul class="d-flex justify-content-between align-items-center pt-3 mb-3 border-top">
<li class="oh-activity-list__item align-items-center mb-0">
<div class="oh-activity-list__photo oh-activity-list__photo--small me-2">
<img src="https://ui-avatars.com/api/?name={{ activity.updated_by }}&background=random"
class="oh-activity-list__image" alt="{{ activity.updated_by }}" />
</div>
<small class="oh-activity-list__description">
<strong>{{ activity.updated_by }}</strong>
{% trans 'updated objective details' %}
</small>
</li>
<li>
<small>
<span class="dateformat_changer">{{ activity.date|date:'M. d, Y' }}</span>&nbsp;&nbsp;
<span class="timeformat_changer">{{ activity.date|date:'g:i a' }}</span>
</small>
</li>
</ul>
{% endif %}
{% endfor %}
</ul>
</div>
<script>
var sendButton = function (context) {
var ui = $.summernote.ui
return ui
.button({
contents: 'Add comment <ion-icon name="paper-plane-outline"></ion-icon>',
tooltip: 'Send Content',
click: function () {
const content = context.invoke('code')
$("#commentEditor button[type=submit]").click()
}
})
.render()
}
// Initialize Summernote
$('#editor').summernote({
height: 70,
placeholder: 'Write a comment...',
toolbar: [
['insert', ['link', 'picture', 'pdfUpload']],
['sendGroup', ['send']]
],
buttons: {
pdfUpload: pdfUploadButton,
send: sendButton
}
})
$(document).ready(function () {
$('.note-toolbar .note-btn-group').last().addClass('send-group')
})
</script>
<script>
$(document).ready(function () {
// Hide the Summernote backdrop if it ever appears
setInterval(function () {
$(".note-modal-backdrop").css("display", "none");
}, 300);
});
</script>

View File

@@ -452,7 +452,7 @@ class EmployeeObjective(HorillaModel):
"""
for detail view of page
"""
url = reverse("view-employee-objective", kwargs={"emp_obj_id": self.pk})
url = reverse("view-employee-objective", kwargs={"pk": self.pk})
return url
def title_col(self):

View File

@@ -144,6 +144,7 @@ if (keyResultStatusChartCtx != null) {
}
function keyResultStatusDataUpdate(data) {
console.log('keyresult',data)
keyResultStatusData.labels = data.key_result_label;
keyResultStatusData.datasets[0].data = data.key_result_value;
keyResultStatusData.message = data.message;

View File

@@ -46,7 +46,7 @@
</div>
{% endfor %}
</div>
{% endcomment %}
{% endcomment %}
{{ form.non_field_errors }} {{form.errors}}
<div class="row">
<div class="col-12" style="padding-right: 0"></div>
@@ -131,6 +131,6 @@
$("#options").show()
} else {
$("#options").hide()
}
}
}
</script>
</script>