diff --git a/nmhs_cms/settings/base.py b/nmhs_cms/settings/base.py index 77507538..f906ecf1 100644 --- a/nmhs_cms/settings/base.py +++ b/nmhs_cms/settings/base.py @@ -53,7 +53,7 @@ "pages.organisation_pages.projects", "pages.organisation_pages.tenders", "pages.organisation_pages.vacancies", - "pages.organisation_pages.orgchart", + "pages.organisation_pages.staff", "pages.email_subscription", "pages.surveys", "pages.search", diff --git a/pages/organisation_pages/organisation/models.py b/pages/organisation_pages/organisation/models.py index f8e9a469..6c918aae 100644 --- a/pages/organisation_pages/organisation/models.py +++ b/pages/organisation_pages/organisation/models.py @@ -16,7 +16,7 @@ class OrganisationIndexPage(MetadataPageMixin, Page): 'vacancies.VacanciesPage', 'projects.ProjectIndexPage', 'tenders.TendersPage', - 'orgchart.OrganisationChartPage' + 'staff.StaffPage', 'flex_page.FlexPage', ] show_in_menus_default = True diff --git a/pages/organisation_pages/orgchart/migrations/0002_organisationchartpage_introduction_text_and_more.py b/pages/organisation_pages/orgchart/migrations/0002_organisationchartpage_introduction_text_and_more.py deleted file mode 100644 index 4a292c02..00000000 --- a/pages/organisation_pages/orgchart/migrations/0002_organisationchartpage_introduction_text_and_more.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2.7 on 2024-04-19 20:34 - -from django.db import migrations, models -import wagtail.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('orgchart', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='organisationchartpage', - name='introduction_text', - field=wagtail.fields.RichTextField(blank=True, help_text='Introduction section description', null=True, verbose_name='Introduction text'), - ), - migrations.AddField( - model_name='organisationchartpage', - name='introduction_title', - field=models.CharField(blank=True, help_text='Introduction section title', max_length=100, null=True, verbose_name='Introduction Title'), - ), - ] diff --git a/pages/organisation_pages/orgchart/migrations/0003_organisationchartpage_introduction_heading_and_more.py b/pages/organisation_pages/orgchart/migrations/0003_organisationchartpage_introduction_heading_and_more.py deleted file mode 100644 index 1a62d8fd..00000000 --- a/pages/organisation_pages/orgchart/migrations/0003_organisationchartpage_introduction_heading_and_more.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.2.7 on 2024-04-19 21:05 - -from django.db import migrations, models -import wagtail.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('orgchart', '0002_organisationchartpage_introduction_text_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='organisationchartpage', - name='introduction_heading', - field=models.CharField(blank=True, default='MEET OUR TEAM', help_text='Introduction section heading', max_length=100, null=True, verbose_name='Introduction Heading'), - ), - migrations.AlterField( - model_name='organisationchartpage', - name='introduction_text', - field=wagtail.fields.RichTextField(blank=True, default="We're a team of scientists, meteroologist, analysists, software engineers and researchers.We are invigorated by challenging weather phenomena, thrive on surpassing previous records, and are dedicated to improving the world's conditions with each passing day. ", help_text='Introduction section description', null=True, verbose_name='Introduction text'), - ), - migrations.AlterField( - model_name='organisationchartpage', - name='introduction_title', - field=models.CharField(blank=True, default='Weather and Climate through Us', help_text='Introduction section title', max_length=100, null=True, verbose_name='Introduction Title'), - ), - ] diff --git a/pages/organisation_pages/orgchart/migrations/0004_alter_employee_options_and_more.py b/pages/organisation_pages/orgchart/migrations/0004_alter_employee_options_and_more.py deleted file mode 100644 index aace14fd..00000000 --- a/pages/organisation_pages/orgchart/migrations/0004_alter_employee_options_and_more.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2.7 on 2024-04-19 23:08 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('orgchart', '0003_organisationchartpage_introduction_heading_and_more'), - ] - - operations = [ - migrations.AlterModelOptions( - name='employee', - options={'verbose_name': '{name} ({role})', 'verbose_name_plural': '{name} ({role})'}, - ), - migrations.AlterModelOptions( - name='organisationchartpage', - options={'verbose_name': 'Staff/Management Page'}, - ), - ] diff --git a/pages/organisation_pages/orgchart/migrations/0005_alter_department_options_alter_employee_options_and_more.py b/pages/organisation_pages/orgchart/migrations/0005_alter_department_options_alter_employee_options_and_more.py deleted file mode 100644 index b05a6034..00000000 --- a/pages/organisation_pages/orgchart/migrations/0005_alter_department_options_alter_employee_options_and_more.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 4.2.7 on 2024-04-20 00:54 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('orgchart', '0004_alter_employee_options_and_more'), - ] - - operations = [ - migrations.AlterModelOptions( - name='department', - options={'ordering': ['-order']}, - ), - migrations.AlterModelOptions( - name='employee', - options={'ordering': ['sort_order'], 'verbose_name': '{name} ({role})', 'verbose_name_plural': '{name} ({role})'}, - ), - migrations.AddField( - model_name='department', - name='order', - field=models.PositiveIntegerField(default=0, verbose_name='Order'), - ), - ] diff --git a/pages/organisation_pages/orgchart/views.py b/pages/organisation_pages/orgchart/views.py deleted file mode 100644 index 458b10e9..00000000 --- a/pages/organisation_pages/orgchart/views.py +++ /dev/null @@ -1,67 +0,0 @@ -import json -from django.shortcuts import render -from django.http import JsonResponse -from django.views.decorators.csrf import csrf_exempt -# Create your views here. -from orgchart.models import Employee - -def save_organizational_structure(request): - if request.method == "POST": - try: - # Parse JSON data from the request body - json_data = json.loads(request.body.decode('utf-8')) - print(json_data['json_data']) - - # Iterate over the organizational structure data and save/update records - for node_data in json_data['json_data']: - key = node_data.get("key") - name = node_data.get("name") - position = node_data.get("position") - supervisor = node_data.get("supervisor") - - # Check if the record already exists in the database - if Employee.objects.filter(key=key).exists(): - # Update existing record - organizational_structure = Employee.objects.get(key=key) - organizational_structure.name = name - organizational_structure.position = position - organizational_structure.supervisor = supervisor - organizational_structure.save() - else: - # Create new record - organizational_structure = Employee.objects.create( - key=key, name=name, position=position, supervisor=supervisor - ) - - return JsonResponse({"success": True}) - except Exception as e: - return JsonResponse({"error": str(e)}, status=500) - else: - return JsonResponse({"error": "Invalid request method."}, status=400) -def organizational_chart_editor(request): - # Retrieve all employees from the database - employees = Employee.objects.all() - - # Convert employee data to a format suitable for GoJS - employee_data = [ - {"key": employee.id, "name": employee.name, "position": employee.position, "supervisor": employee.supervisor_id} - for employee in employees - ] - - # Convert employee data to JSON format - employee_data_json = json.dumps(employee_data) - - print(employee_data_json) - - return render(request, 'orgchart/organizational_chart_editor.html', {'employee_data_json': employee_data_json}) - - -@csrf_exempt -def load_organizational_structure(request): - if request.method == "GET": - # Retrieve organizational structure data from the database - # Deserialize the data and return it as JSON response - organizational_structure_data = {...} # Retrieve data from database - return JsonResponse(organizational_structure_data) - else: - return JsonResponse({"error": "Invalid request method."}, status=400) \ No newline at end of file diff --git a/pages/organisation_pages/orgchart/wagtail_hooks.py b/pages/organisation_pages/orgchart/wagtail_hooks.py deleted file mode 100644 index e79b6bc3..00000000 --- a/pages/organisation_pages/orgchart/wagtail_hooks.py +++ /dev/null @@ -1,23 +0,0 @@ -from django.urls import reverse -from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register -from wagtail import hooks -from django.urls import path -from django.views.generic import View -from django.shortcuts import render -from wagtail.admin.menu import MenuItem - - -@hooks.register('register_admin_urls') -def register_custom_admin_urls(): - return [ - path('organizational-chart/', OrganizationalChartView.as_view(), name='organizational_chart'), - ] - -class OrganizationalChartView(View): - def get(self, request): - return render(request, 'orgchart/organizational_chart_editor.html') - - -@hooks.register('construct_settings_menu') -def add_custom_menu_item(request, menu_items): - menu_items.append(MenuItem('Organizational Chart', reverse('organizational_chart'), classnames='icon icon-fa-sitemap', order=100)) \ No newline at end of file diff --git a/pages/organisation_pages/orgchart/__init__.py b/pages/organisation_pages/staff/__init__.py similarity index 100% rename from pages/organisation_pages/orgchart/__init__.py rename to pages/organisation_pages/staff/__init__.py diff --git a/pages/organisation_pages/orgchart/admin.py b/pages/organisation_pages/staff/admin.py similarity index 100% rename from pages/organisation_pages/orgchart/admin.py rename to pages/organisation_pages/staff/admin.py diff --git a/pages/organisation_pages/orgchart/apps.py b/pages/organisation_pages/staff/apps.py similarity index 53% rename from pages/organisation_pages/orgchart/apps.py rename to pages/organisation_pages/staff/apps.py index 28bcee74..119e6472 100644 --- a/pages/organisation_pages/orgchart/apps.py +++ b/pages/organisation_pages/staff/apps.py @@ -1,6 +1,6 @@ from django.apps import AppConfig -class OrgchartConfig(AppConfig): +class StaffConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'pages.organisation_pages.orgchart' + name = 'pages.organisation_pages.staff' diff --git a/pages/organisation_pages/orgchart/migrations/0001_initial.py b/pages/organisation_pages/staff/migrations/0001_initial.py similarity index 61% rename from pages/organisation_pages/orgchart/migrations/0001_initial.py rename to pages/organisation_pages/staff/migrations/0001_initial.py index 82112b7b..bd9e7747 100644 --- a/pages/organisation_pages/orgchart/migrations/0001_initial.py +++ b/pages/organisation_pages/staff/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.7 on 2024-04-18 20:10 +# Generated by Django 4.2.7 on 2024-04-23 07:18 from django.db import migrations, models import django.db.models.deletion @@ -24,39 +24,47 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=100)), ('desc', wagtail.fields.RichTextField(blank=True, null=True)), + ('order', models.PositiveIntegerField(default=0, verbose_name='Order')), ], + options={ + 'ordering': ['order'], + }, ), migrations.CreateModel( - name='OrganisationChartPage', + name='StaffPage', fields=[ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), ('banner_title', models.CharField(max_length=255, verbose_name='Banner Title')), ('banner_subtitle', models.CharField(blank=True, max_length=255, null=True, verbose_name='Banner Subtitle')), ('call_to_action_button_text', models.CharField(blank=True, max_length=100, null=True, verbose_name='Call to action button text')), + ('introduction_heading', models.CharField(blank=True, default='MEET OUR MEMBERS', help_text='Introduction section heading', max_length=100, null=True, verbose_name='Introduction Heading')), + ('introduction_title', models.CharField(blank=True, default='Forecasting the Future: Weather & Climate at the Frontline', help_text='Introduction section title', max_length=100, null=True, verbose_name='Introduction Title')), + ('introduction_text', wagtail.fields.RichTextField(blank=True, default="We're a team of scientists, meteroologist, analysists, software engineers and researchers.We are invigorated by challenging weather phenomena, thrive on surpassing previous records, and are dedicated to improving the world's conditions with each passing day. ", help_text='Introduction section description', null=True, verbose_name='Introduction text')), ('banner_image', models.ForeignKey(blank=True, help_text='A high quality banner image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Banner Image')), ('call_to_action_related_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.page', verbose_name='Call to action related page')), ('search_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Search image')), ], options={ - 'abstract': False, + 'verbose_name': 'Staff Page', }, bases=(wagtailmetadata.models.WagtailImageMetadataMixin, 'wagtailcore.page', models.Model, wagtailcache.cache.WagtailCacheMixin), ), migrations.CreateModel( - name='Employee', + name='StaffMember', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), - ('name', models.CharField(help_text='First and Last names of employee', max_length=100, verbose_name="Employee's name")), - ('role', models.CharField(help_text='The role/position of the employee', max_length=100, verbose_name="Employee's role")), - ('bio', wagtail.fields.RichTextField(blank=True, help_text='Optional Summary biography of the employe', null=True, verbose_name='Employee Biography')), - ('department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='orgchart.department', verbose_name="Employee's Department")), - ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='employees', to='orgchart.organisationchartpage')), - ('photo', models.ForeignKey(blank=True, help_text='A high quality square image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Employee Image')), + ('name', models.CharField(help_text='First and Last names of Staff member', max_length=100, verbose_name="Staff member's name")), + ('role', models.CharField(help_text='The role/position of the Staff member', max_length=100, verbose_name="Staff member's role")), + ('bio', wagtail.fields.RichTextField(blank=True, help_text='Optional Summary biography of the Staff member', null=True, verbose_name='Staff member Biography')), + ('department', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='staff.department', verbose_name="Staff member's Department")), + ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='staffmembers', to='staff.staffpage')), + ('photo', models.ForeignKey(blank=True, help_text='A high quality square image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name="Staff member's Profile Image")), ], options={ + 'verbose_name': 'Staff Member', + 'verbose_name_plural': 'Staff Members', 'ordering': ['sort_order'], - 'abstract': False, }, ), ] diff --git a/pages/organisation_pages/orgchart/migrations/__init__.py b/pages/organisation_pages/staff/migrations/__init__.py similarity index 100% rename from pages/organisation_pages/orgchart/migrations/__init__.py rename to pages/organisation_pages/staff/migrations/__init__.py diff --git a/pages/organisation_pages/orgchart/models.py b/pages/organisation_pages/staff/models.py similarity index 73% rename from pages/organisation_pages/orgchart/models.py rename to pages/organisation_pages/staff/models.py index a3adf2a6..a938ebb2 100644 --- a/pages/organisation_pages/orgchart/models.py +++ b/pages/organisation_pages/staff/models.py @@ -37,8 +37,8 @@ class Meta: ordering = ['order'] -class OrganisationChartPage(AbstractBannerPage): - template = 'orgchart/orgchart_page.html' +class StaffPage(AbstractBannerPage): + template = 'staff/staff_page.html' parent_page_types = ['organisation.OrganisationIndexPage'] subpage_types = [] show_in_menus_default = True @@ -46,9 +46,9 @@ class OrganisationChartPage(AbstractBannerPage): max_count = 1 introduction_heading = models.CharField(max_length=100, verbose_name=_('Introduction Heading'), - help_text=_("Introduction section heading"), null=True, blank=True, default='MEET OUR TEAM') + help_text=_("Introduction section heading"), null=True, blank=True, default='MEET OUR MEMBERS') introduction_title = models.CharField(max_length=100, verbose_name=_('Introduction Title'), - help_text=_("Introduction section title"), null=True, blank=True, default='Weather and Climate through Us') + help_text=_("Introduction section title"), null=True, blank=True, default="Forecasting the Future: Weather & Climate at the Frontline") introduction_text = RichTextField(features=SUMMARY_RICHTEXT_FEATURES, verbose_name=_('Introduction text'), help_text=_("Introduction section description"), null=True, blank=True, default="We're a team of scientists, meteroologist, analysists, software engineers and researchers.We are invigorated by challenging weather phenomena, thrive on surpassing previous records, and are dedicated to improving the world's conditions with each passing day. ") @@ -58,36 +58,35 @@ class OrganisationChartPage(AbstractBannerPage): FieldPanel('introduction_title'), FieldPanel('introduction_text'), ], heading=_('Introduction Section')), - InlinePanel('employees', heading=_("Employee"), label=_("Employee")), + InlinePanel('staffmembers', heading=_("Staff"), label=_("Staff")), ] @cached_property def all_departments(self): # Annotate the queryset with the count of employees per department - departments_with_employee_count = Employee.objects.values('department__name').annotate(employee_count=Count('department')).order_by('department__order') - + departments_with_staff_count = StaffMember.objects.values('department__name').annotate(staffmembers_count=Count('department')).order_by('department__order') # Filter departments with at least one employee - departments_with_employees = departments_with_employee_count.filter(employee_count__gt=0) + departments_with_staff = departments_with_staff_count.filter(staffmembers_count__gt=0) - return departments_with_employees + return departments_with_staff class Meta: - verbose_name = _("Staff/Management Page") + verbose_name = _("Staff Page") -class Employee(Orderable): - page = ParentalKey(OrganisationChartPage, on_delete=models.CASCADE, related_name="employees") - name = models.CharField(max_length=100,verbose_name=_("Employee's name"), - help_text=_("First and Last names of employee")) - role = models.CharField(max_length=100, verbose_name=_("Employee's role"), - help_text=_("The role/position of the employee")) - bio = RichTextField(features=SUMMARY_RICHTEXT_FEATURES, null=True, blank=True,verbose_name=_("Employee Biography"), - help_text=_("Optional Summary biography of the employe")) - department = models.ForeignKey(Department, on_delete=models.PROTECT, blank=True, null=True, - verbose_name=_("Employee's Department")) +class StaffMember(Orderable): + page = ParentalKey(StaffPage, on_delete=models.CASCADE, related_name="staffmembers") + name = models.CharField(max_length=100,verbose_name=_("Staff member's name"), + help_text=_("First and Last names of Staff member")) + role = models.CharField(max_length=100, verbose_name=_("Staff member's role"), + help_text=_("The role/position of the Staff member")) + bio = RichTextField(features=SUMMARY_RICHTEXT_FEATURES, null=True, blank=True,verbose_name=_("Staff member Biography"), + help_text=_("Optional Summary biography of the Staff member")) + department = models.ForeignKey(Department, on_delete=models.PROTECT, blank=False, null=True, + verbose_name=_("Staff member's Department")) photo = models.ForeignKey( 'wagtailimages.Image', - verbose_name=_("Employee Image"), + verbose_name=_("Staff member's Profile Image"), help_text=_("A high quality square image"), null=True, blank=True, @@ -104,8 +103,8 @@ class Employee(Orderable): ] class Meta: - verbose_name = "{name} ({role})" - verbose_name_plural = "{name} ({role})" + verbose_name = _("Staff Member") + verbose_name_plural = _("Staff Members") ordering = ['sort_order'] diff --git a/pages/organisation_pages/orgchart/templates/orgchart/orgchart_page.html b/pages/organisation_pages/staff/templates/staff/staff_page.html similarity index 75% rename from pages/organisation_pages/orgchart/templates/orgchart/orgchart_page.html rename to pages/organisation_pages/staff/templates/staff/staff_page.html index 777c9df3..432a6583 100644 --- a/pages/organisation_pages/orgchart/templates/orgchart/orgchart_page.html +++ b/pages/organisation_pages/staff/templates/staff/staff_page.html @@ -3,6 +3,21 @@ {% get_settings use_default_site=True %} {% block extra_css %} + + {% endblock extra_css %} @@ -49,38 +64,41 @@