[FIX] PMS: Bug fixing and style updations
This commit is contained in:
@@ -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 %}
|
||||
|
||||
171
horilla_theme/templates/feedback/answer/feedback_answer.html
Normal file
171
horilla_theme/templates/feedback/answer/feedback_answer.html
Normal 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 %}
|
||||
@@ -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 %}
|
||||
@@ -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%}
|
||||
|
||||
106
horilla_theme/templates/generic/horilla_history_view.html
Normal file
106
horilla_theme/templates/generic/horilla_history_view.html
Normal 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>
|
||||
 , 
|
||||
<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>
|
||||
@@ -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> , 
|
||||
<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> , 
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
@@ -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):
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user