more updates
This commit is contained in:
parent
eca1705ff8
commit
edd2d52015
@ -812,7 +812,7 @@ class NoteForm(forms.ModelForm):
|
||||
),
|
||||
}
|
||||
labels = {
|
||||
"content": _("Comment"),
|
||||
"content": _("Note"),
|
||||
}
|
||||
|
||||
# def __init__(self, *args, **kwargs):
|
||||
@ -2186,7 +2186,7 @@ class MessageForm(forms.ModelForm):
|
||||
self.fields["job"].queryset = JobPosting.objects.filter(
|
||||
id__in=job_ids
|
||||
).order_by("-created_at")
|
||||
|
||||
|
||||
print("Agency user job queryset:", self.fields["job"].queryset)
|
||||
elif self.user.user_type == "candidate":
|
||||
# Candidates can only see jobs they applied for
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-27 15:36
|
||||
# Generated by Django 5.2.6 on 2025-12-02 10:27
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
@ -31,6 +31,18 @@ class Migration(migrations.Migration):
|
||||
('end_time', models.TimeField(verbose_name='End Time')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EmailContent',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('subject', models.CharField(max_length=255, verbose_name='Subject')),
|
||||
('message', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Message Body')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Email Content',
|
||||
'verbose_name_plural': 'Email Contents',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FormStage',
|
||||
fields=[
|
||||
@ -57,7 +69,6 @@ class Migration(migrations.Migration):
|
||||
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
||||
('location_type', models.CharField(choices=[('Remote', 'Remote (e.g., Zoom, Google Meet)'), ('Onsite', 'In-Person (Physical Location)')], db_index=True, max_length=10, verbose_name='Location Type')),
|
||||
('topic', models.CharField(blank=True, help_text="e.g., 'Zoom Topic: Software Interview' or 'Main Conference Room'", max_length=255, verbose_name='Meeting/Location Topic')),
|
||||
('details_url', models.URLField(blank=True, max_length=2048, null=True, verbose_name='Meeting/Location URL')),
|
||||
('timezone', models.CharField(default='UTC', max_length=50, verbose_name='Timezone')),
|
||||
('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')),
|
||||
('duration', models.PositiveIntegerField(verbose_name='Duration (minutes)')),
|
||||
@ -65,6 +76,7 @@ class Migration(migrations.Migration):
|
||||
('meeting_id', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='External Meeting ID')),
|
||||
('password', models.CharField(blank=True, max_length=20, null=True)),
|
||||
('zoom_gateway_response', models.JSONField(blank=True, null=True)),
|
||||
('details_url', models.JSONField(blank=True, null=True)),
|
||||
('participant_video', models.BooleanField(default=True)),
|
||||
('join_before_host', models.BooleanField(default=False)),
|
||||
('host_email', models.CharField(blank=True, max_length=255, null=True)),
|
||||
@ -278,24 +290,6 @@ class Migration(migrations.Migration):
|
||||
'verbose_name_plural': 'Applications',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='InterviewNote',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
||||
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
||||
('note_type', models.CharField(choices=[('Feedback', 'Candidate Feedback'), ('Logistics', 'Logistical Note'), ('General', 'General Comment')], default='Feedback', max_length=50, verbose_name='Note Type')),
|
||||
('content', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Content/Feedback')),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interview_notes', to=settings.AUTH_USER_MODEL, verbose_name='Author')),
|
||||
('interview', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='recruitment.interview', verbose_name='Scheduled Interview')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Interview Note',
|
||||
'verbose_name_plural': 'Interview Notes',
|
||||
'ordering': ['created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JobPosting',
|
||||
fields=[
|
||||
@ -363,12 +357,15 @@ class Migration(migrations.Migration):
|
||||
('start_date', models.DateField(db_index=True, verbose_name='Start Date')),
|
||||
('end_date', models.DateField(db_index=True, verbose_name='End Date')),
|
||||
('working_days', models.JSONField(verbose_name='Working Days')),
|
||||
('topic', models.CharField(max_length=255, verbose_name='Interview Topic')),
|
||||
('start_time', models.TimeField(verbose_name='Start Time')),
|
||||
('end_time', models.TimeField(verbose_name='End Time')),
|
||||
('break_start_time', models.TimeField(blank=True, null=True, verbose_name='Break Start Time')),
|
||||
('break_end_time', models.TimeField(blank=True, null=True, verbose_name='Break End Time')),
|
||||
('interview_duration', models.PositiveIntegerField(verbose_name='Interview Duration (minutes)')),
|
||||
('buffer_time', models.PositiveIntegerField(default=0, verbose_name='Buffer Time (minutes)')),
|
||||
('schedule_interview_type', models.CharField(choices=[('Remote', 'Remote (e.g., Zoom)'), ('Onsite', 'In-Person (Physical Location)')], default='Onsite', max_length=10, verbose_name='Interview Type')),
|
||||
('physical_address', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('applications', models.ManyToManyField(blank=True, related_name='interview_schedules', to='recruitment.application')),
|
||||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('interview', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='schedule_templates', to='recruitment.interview', verbose_name='Location Template (Zoom/Onsite)')),
|
||||
@ -438,6 +435,25 @@ class Migration(migrations.Migration):
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Note',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
||||
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
||||
('note_type', models.CharField(choices=[('Feedback', 'Candidate Feedback'), ('Logistics', 'Logistical Note'), ('General', 'General Comment')], default='Feedback', max_length=50, verbose_name='Note Type')),
|
||||
('content', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Content/Feedback')),
|
||||
('application', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='recruitment.application', verbose_name='Application')),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interview_notes', to=settings.AUTH_USER_MODEL, verbose_name='Author')),
|
||||
('interview', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='recruitment.interview', verbose_name='Scheduled Interview')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Interview Note',
|
||||
'verbose_name_plural': 'Interview Notes',
|
||||
'ordering': ['created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Notification',
|
||||
fields=[
|
||||
@ -478,7 +494,7 @@ class Migration(migrations.Migration):
|
||||
('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/', validators=[recruitment.validators.validate_image_size], verbose_name='Profile Image')),
|
||||
('linkedin_profile', models.URLField(blank=True, null=True, verbose_name='LinkedIn Profile URL')),
|
||||
('agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='recruitment.hiringagency', verbose_name='Hiring Agency')),
|
||||
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='person_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')),
|
||||
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='person_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Person',
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-28 10:24
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='person',
|
||||
name='user',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='person_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account'),
|
||||
),
|
||||
]
|
||||
@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.6 on 2025-12-01 12:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bulkinterviewtemplate',
|
||||
name='schedule_interview_type',
|
||||
field=models.CharField(choices=[('Remote', 'Remote (e.g., Zoom)'), ('Onsite', 'In-Person (Physical Location)')], default='Onsite', max_length=10, verbose_name='Interview Type'),
|
||||
),
|
||||
]
|
||||
@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.6 on 2025-12-01 13:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0002_bulkinterviewtemplate_schedule_interview_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bulkinterviewtemplate',
|
||||
name='physical_address',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@ -1,19 +0,0 @@
|
||||
# Generated by Django 5.2.6 on 2025-12-01 14:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0003_bulkinterviewtemplate_physical_address'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bulkinterviewtemplate',
|
||||
name='topic',
|
||||
field=models.CharField(default='', max_length=255, verbose_name='Interview Topic'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@ -1,14 +0,0 @@
|
||||
# Generated by Django 5.2.6 on 2025-12-02 10:08
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0002_alter_person_user'),
|
||||
('recruitment', '0004_bulkinterviewtemplate_topic'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
@ -27,9 +27,9 @@ except ImportError:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
OPENROUTER_API_KEY ='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'
|
||||
# OPENROUTER_MODEL = 'qwen/qwen-2.5-72b-instruct:free'
|
||||
OPENROUTER_MODEL = 'qwen/qwen-2.5-72b-instruct'
|
||||
|
||||
OPENROUTER_MODEL = 'openai/gpt-oss-20b'
|
||||
# OPENROUTER_MODEL = 'qwen/qwen-2.5-7b-instruct'
|
||||
# OPENROUTER_MODEL = 'openai/gpt-oss-20b'
|
||||
# OPENROUTER_MODEL = 'mistralai/mistral-small-3.2-24b-instruct:free'
|
||||
|
||||
@ -623,7 +623,8 @@ def handle_resume_parsing_and_scoring(pk: int):
|
||||
}}
|
||||
|
||||
If a top-level key or its required fields are missing, set the field to null, an empty list, or an empty object as appropriate.
|
||||
|
||||
Be Clear and Direct Avoid overly indirect politeness which can add confusion.
|
||||
Be strict,objective and concise and critical in your responses, and don't give inflated scores to weak candidates.
|
||||
Output only valid JSON—no markdown, no extra text.
|
||||
"""
|
||||
|
||||
|
||||
@ -713,7 +713,7 @@ def request_cvs_download(request, slug):
|
||||
if not job.applications.exists():
|
||||
messages.warning(request, _("No applications found for this job. ZIP file generation skipped."))
|
||||
return redirect('job_detail', slug=slug)
|
||||
|
||||
|
||||
async_task('recruitment.tasks.generate_and_save_cv_zip', job.id)
|
||||
|
||||
# Provide user feedback and redirect
|
||||
@ -4868,7 +4868,7 @@ def message_delete(request, message_id):
|
||||
Redirects to the message list on success (either via standard redirect
|
||||
or HTMX's hx-redirect header).
|
||||
"""
|
||||
|
||||
|
||||
# 1. Retrieve the message
|
||||
# Use select_related to fetch linked objects efficiently for checks/logging
|
||||
message = get_object_or_404(
|
||||
@ -4879,13 +4879,13 @@ def message_delete(request, message_id):
|
||||
# Only the sender or recipient can delete the message
|
||||
if message.sender != request.user and message.recipient != request.user:
|
||||
messages.error(request, "You don't have permission to delete this message.")
|
||||
|
||||
|
||||
# HTMX requests should handle redirection via client-side logic (hx-redirect)
|
||||
if "HX-Request" in request.headers:
|
||||
# Returning 403 or 400 is ideal, but 200 with an empty body is often accepted
|
||||
# by HTMX and the message is shown on the next page/refresh.
|
||||
return HttpResponse(status=403)
|
||||
|
||||
return HttpResponse(status=403)
|
||||
|
||||
# Standard navigation redirect
|
||||
return redirect("message_list")
|
||||
|
||||
@ -4899,7 +4899,7 @@ def message_delete(request, message_id):
|
||||
# 1. Set the HTMX response header for redirection
|
||||
response = HttpResponse(status=200)
|
||||
response["HX-Redirect"] = reverse("message_list") # <--- EXPLICIT HEADER
|
||||
return response
|
||||
return response
|
||||
|
||||
# Standard navigation fallback
|
||||
return redirect("message_list")
|
||||
@ -5069,7 +5069,8 @@ def document_upload(request, slug):
|
||||
if upload_target == 'person':
|
||||
return redirect("applicant_portal_dashboard")
|
||||
else:
|
||||
return redirect("applicant_application_detail", slug=application.slug)
|
||||
return render(request, 'recruitment/application_detail.html', {'application': application})
|
||||
# return redirect("application_detail", slug=application.slug)
|
||||
|
||||
# Handle GET request for AJAX
|
||||
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
@ -5081,7 +5082,6 @@ def document_upload(request, slug):
|
||||
def document_delete(request, document_id):
|
||||
"""Delete a document"""
|
||||
document = get_object_or_404(Document, id=document_id)
|
||||
print(document)
|
||||
|
||||
# Initialize variables for redirection outside of the complex logic
|
||||
is_htmx = "HX-Request" in request.headers
|
||||
@ -5144,7 +5144,9 @@ def document_delete(request, document_id):
|
||||
if is_htmx or request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
# For HTMX, return a 200 OK. The front-end is expected to use hx-swap='outerHTML'
|
||||
# to remove the element, or hx-redirect to navigate.
|
||||
return HttpResponse(status=200)
|
||||
response = HttpResponse(status=200)
|
||||
response["HX-Refresh"] = "true" # Instruct HTMX to refresh the current view
|
||||
return response
|
||||
|
||||
# --- Standard Navigation Fallback ---
|
||||
else:
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
|
||||
<div class="container-fluid max-width-1600">
|
||||
|
||||
|
||||
|
||||
|
||||
<a class="navbar-brand text-white d-none d-lg-block me-4 pe-4" href="{% url 'dashboard' %}" aria-label="Home">
|
||||
<img src="{% static 'image/kaauh_green1.png' %}" alt="{% trans 'kaauh logo green bg' %}" style="width: 60px; height: 60px;">
|
||||
@ -206,7 +206,7 @@
|
||||
</form>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
|
||||
<li class="d-lg-none"><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none text-teal" href="{% url 'message_list' %}"> <i class="fas fa-envelope fs-5 me-3"></i> <span>{% trans "Messages" %}</span></a></li>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none text-teal" href="{% url 'user_detail' request.user.pk %}"><i class="fas fa-user-circle me-3 fs-5"></i> <span>{% trans "My Profile" %}</span></a></li>
|
||||
@ -293,10 +293,10 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item me-lg-4">
|
||||
<a class="nav-link {% if request.resolver_match.url_name == 'list_meetings' %}active{% endif %}" href="{% url 'interview_list' %}">
|
||||
<a class="nav-link {% if request.resolver_match.url_name == 'interview_list' %}active{% endif %}" href="{% url 'interview_list' %}">
|
||||
<span class="d-flex align-items-center gap-2">
|
||||
<i class="fas fa-calendar-check me-2"></i>
|
||||
{% trans "Meetings" %}
|
||||
{% trans "Meetings & interviews" %}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% load static %}
|
||||
{% load file_filters %}
|
||||
{% load i18n %}
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-white border-bottom d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0 text-primary">{% trans "Documents" %}</h5>
|
||||
@ -25,12 +26,8 @@
|
||||
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'application_document_upload' application.slug %}"
|
||||
enctype="multipart/form-data"
|
||||
hx-post="{% url 'application_document_upload' application.slug %}"
|
||||
hx-target="#documents-pane"
|
||||
hx-select="#documents-pane"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::after-request="bootstrap.Modal.getInstance(document.getElementById('documentUploadModal')).hide()"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
@ -64,7 +61,7 @@
|
||||
id="documentDescription"
|
||||
rows="3"
|
||||
class="form-control"
|
||||
placeholder="{% trans "Optional description..." %}"
|
||||
placeholder='{% trans "Optional description..." %}'
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,22 +98,23 @@
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<a
|
||||
href="{% url 'document_download' document.id %}"
|
||||
class="btn btn-sm btn-outline-primary me-2"
|
||||
title="{% trans "Download" %}"
|
||||
>
|
||||
<i class="fas fa-download"></i>
|
||||
href="{% url 'document_download' document.id %}"
|
||||
class="btn btn-sm btn-outline-primary me-2"
|
||||
title='{% trans "Download" %}'
|
||||
>
|
||||
<i class="fas fa-download"></i>
|
||||
</a>
|
||||
|
||||
{% if user.is_superuser or application.job.assigned_to == user %}
|
||||
<button
|
||||
<a
|
||||
hx-post="{% url 'document_delete' document.id %}"
|
||||
hx-confirm='{% trans "Are you sure you want to delete" %}'
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
onclick="confirmDelete({{ document.id }}, '{{ document.file.name|filename|default:"Document" }}')"
|
||||
title="{% trans "Delete" %}"
|
||||
title='{% trans "Delete" %}'
|
||||
>
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@ -131,6 +129,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.hover-bg-light:hover {
|
||||
background-color: #f8f9fa;
|
||||
@ -139,7 +138,7 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function confirmDelete(documentId, fileName) {
|
||||
/*function confirmDelete(documentId, fileName) {
|
||||
var deletePrefix = "{% trans "Are you sure you want to delete" %}";
|
||||
if (confirm(deletePrefix + ' "' + fileName + '"?')) {
|
||||
htmx.ajax('POST', `{% url 'document_delete' 0 %}`.replace('0', documentId), {
|
||||
@ -147,5 +146,16 @@ function confirmDelete(documentId, fileName) {
|
||||
swap: 'innerHTML'
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
function closeUploadModal() {
|
||||
var modalElement = document.getElementById('documentUploadModal');
|
||||
if (modalElement) {
|
||||
var modal = bootstrap.Modal.getInstance(modalElement);
|
||||
if (modal) {
|
||||
modal.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -480,7 +480,7 @@
|
||||
|
||||
{# TAB 5 CONTENT: PARSED SUMMARY #}
|
||||
{% if application.parsed_summary %}
|
||||
|
||||
|
||||
<div class="tab-pane fade" id="summary-pane" role="tabpanel" aria-labelledby="summary-tab">
|
||||
<h5 class="text-primary mb-4">{% trans "AI Generated Summary" %}</h5>
|
||||
<div class="border-start border-primary ps-3 pt-1 pb-1">
|
||||
@ -663,7 +663,7 @@
|
||||
<i class="fas fa-eye me-1"></i>
|
||||
{% trans "View Actual Resume" %}
|
||||
</a> {% endcomment %}
|
||||
|
||||
|
||||
<a href="{{ application.resume.url }}" download class="btn btn-outline-primary">
|
||||
<i class="fas fa-download me-1"></i>
|
||||
{% trans "Download Resume" %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user