Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List Admin Extensions React Conversion #289

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{% extends "standard.html" %}
{% extends "apcd_cms/templates/standard.html" %}
{% load static %}

{% block content %}

<link rel="stylesheet" href="{% static 'apcd-cms/css/table.css' %}">
<link rel="stylesheet" href="{% static 'apcd-cms/css/modal.css' %}">
<link rel="stylesheet" href="{% static 'admin_extension/css/table.css' %}">

<div class="container">
Expand Down Expand Up @@ -31,42 +32,7 @@ <h1>View Extension Requests</h1>
{% endif %}
</div>
</div>
<table id="extensionTable" class="extension-table">
<thead>
<tr>
{% for k in header %}
<th>{{k}}</th>
{% endfor %}
</tr>
</thead>
<tbody id='extensionTableBody'>
{% for r in page %}
<tr>
<td class="created">{{r.created_at}}</td>
<td class="entity_name">{{r.entity_name}}</td>
<td class="requestor_name">{{r.requestor_name}}</td>
<td class="extension_type">{{r.extension_type}}</td>
<td class="outcome">{{r.outcome}}</td>
<td class="status">{{r.status}}</td>
<td class="approved-expiration-date">{{r.approved_expiration_date}}</td>
<td class="modal-cell">
{% include "view_admin_extension_modal.html" %}
{% include "edit_extension_modal.html" %}
<select id='actionsDropdown_{{r.extension_id}}' onchange="openAction('{{r.extension_id}}')">
<div class="filter-container">
<div class="filter-content">
<option value="">Select Action</option>
<option value="viewAdminExtensions">View Record</option>
<option value="editExtension">Edit Record</option>
</div>
</div>
</select>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div id="list-registrations-root"></div>
<div id="admin-extensions-root"></div>
{% include 'paginator.html' %}
</div>
<script>
Expand Down
11 changes: 9 additions & 2 deletions apcd-cms/src/apps/admin_extension/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
from django.urls import path
from django.views.generic import TemplateView
from apps.admin_extension.views import AdminExtensionsTable


app_name = 'admin_extension'
urlpatterns = [
path('list-extensions/', AdminExtensionsTable.as_view(), name="list_extensions"),
path('list-extensions/', TemplateView.as_view(template_name='list_admin_extension.html'), name="list_extensions"),
path('list-extensions/<str:status>', AdminExtensionsTable.as_view(), name='status'),
path('list-extensions/<str:org>', AdminExtensionsTable.as_view(), name='org'),
path('list-extensions/<str:status><str:org>', AdminExtensionsTable.as_view(), name='status_org')
path('list-extensions/<str:status><str:org>', AdminExtensionsTable.as_view(), name='status_org'),
path(r'list-extensions/api/', AdminExtensionsTable.as_view(), name='admin_extensions_table_api'),
path(r'list-extensions/api/?status=(?P<status>)/', AdminExtensionsTable.as_view(),
name='admin_extensions_table_api'),
path(r'list-extensions/api/?org=(?P<org>)/', AdminExtensionsTable.as_view(), name='admin_extensions_table_api'),
path(r'list-extensions/api/?status=(?P<status>)&org=(?P<org>)/', AdminExtensionsTable.as_view(),
name='admin_extensions_table_api')
]
92 changes: 86 additions & 6 deletions apcd-cms/src/apps/admin_extension/views.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The datetime import needs to be updated to the following:
from datetime import date as datetimeDate

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this import

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from apps.utils.utils import title_case
from apps.components.paginator.paginator import paginator
from dateutil import parser
from datetime import datetime
from datetime import date as datetimeDate
import logging

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -45,16 +45,96 @@ def _edit_extension(form):
def get(self, request, *args, **kwargs):
extension_content = get_all_extensions()


context = self.get_context_data(extension_content, *args,**kwargs)
template = loader.get_template(self.template_name)
return HttpResponse(template.render(context, request))
#context = self.get_context_data(extension_content, *args,**kwargs)
#template = loader.get_template(self.template_name)
#return HttpResponse(template.render(context, request))
context = self.get_extensions_list_json(extension_content, *args, **kwargs)
return JsonResponse({'response': context})

def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated or not is_apcd_admin(request.user):
return HttpResponseRedirect('/')
return super(AdminExtensionsTable, self).dispatch(request, *args, **kwargs)

def get_extensions_list_json(self, extensions, *args, **kwargs):
context = {}

context['header'] = ['Created', 'Entity Organization', 'Requestor Name', 'Extension Type', 'Outcome', 'Status', 'Approved Expiration', 'Actions']
context['status_options'] = ['All']
context['org_options'] = ['All']
context['outcome_options'] = []
context['extensions'] = []
context['action_options'] = ['Select Action', 'View Record', 'Edit Record']

try:
page_num = int(self.request.GET.get('page'))
except:
page_num = 1

def getDate(row):
date = row[2]
return date if date is not None else datetimeDate(1,1,1) # put 'None' date entries all together at end of listing w/ date 1-1-0001

extensions = sorted(extensions, key=lambda row:getDate(row), reverse=True)

extensions_table_entries = []

for extension in extensions:
extensions_table_entries.append(self._set_extension(extension))
context['extensions'].append(self._set_extension(extension))

entity_name = title_case(extension[18])
status = title_case(extension[7])
outcome = title_case(extension[8])
if entity_name not in context['org_options']:
context['org_options'].append(entity_name)
context['org_options'] = sorted(context['org_options'], key=lambda x: (x != 'All', x))
# Remove empty strings
context['org_options'] = [option for option in context['org_options'] if option != '']
if status not in context['status_options']:
context['status_options'].append(status)
context['status_options'] = sorted(context['status_options'], key=lambda x: (x != 'All', x))
if outcome not in context['outcome_options']:
context['outcome_options'].append(outcome)
context['outcome_options'] = sorted(context['outcome_options'], key=lambda x: (x is not None, x))

queryStr = ''
status_filter = self.request.GET.get('status')
org_filter = self.request.GET.get('org')

context['selected_status'] = None
if status_filter is not None and status_filter != 'All':
context['selected_status'] = status_filter
queryStr += f'&status={status_filter}'
extensions_table_entries = table_filter(status_filter, extensions_table_entries, 'ext_status')

context['selected_org'] = None
if org_filter is not None and org_filter != 'All':
context['selected_org'] = org_filter
queryStr += f'&org={org_filter}'
extensions_table_entries = table_filter(org_filter.replace("(", "").replace(")",""), extensions_table_entries, 'org_name')

context['query_str'] = queryStr
page_info = paginator(self.request, extensions_table_entries)
context['page'] = [{'org_name': obj['org_name'], 'created': obj['created'], 'type': obj['type'], 'requestor': obj['requestor'], 'ext_outcome': obj['ext_outcome'], 'ext_status': obj['ext_status'], 'ext_id': obj['ext_id'], 'submitter_id': obj['submitter_id'], 'approved_expiration_date': obj['approved_expiration_date']} for obj in page_info['page']]

#context['page'] = list(page_info['page'].object_list.values())
context['pagination_url_namespaces'] = 'administration:admin_extension'
return context

def _set_extension(self, ext):
return {
'org_name': ext[18],
'created': ext[9],
'type': title_case(ext[5].replace('_', ' ')) if ext[5] else None,
'requestor': title_case(ext[14]),
'ext_outcome': title_case(ext[8]) if ext[8] else "None",
'ext_status': title_case(ext[7]),
'ext_id': ext[0],
'submitter_id': ext[1],
'approved_expiration_date': ext[4] if ext[4] else "None",
}

def get_context_data(self, extension_content, *args, **kwargs):
context = super(AdminExtensionsTable, self).get_context_data(*args, **kwargs)
def _set_extensions(extension):
Expand Down Expand Up @@ -145,4 +225,4 @@ def _get_applicable_data_period(value):
try:
return datetime.strptime(str(value), '%Y%m').strftime('%b. %Y')
except:
return None
return None
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { useEffect, useMemo } from 'react';
import { useExtensions, ExtensionRow } from 'hooks/admin';

export const AdminExtensions: React.FC = () => {
const { data, isLoading, isError } = useExtensions({});

if (isLoading) {
return <div>Loading...</div>;
}

if (isError) {
return <div>Error loading data</div>;
}

return (
<table id="extensionTable" className="extension-table">
<thead>
<tr>
{data?.header.map((columnName: string, index: number) => (
<th key={index}>{columnName}</th>
))}
</tr>
</thead>
<tbody>
{data?.page.map((row: ExtensionRow, rowIndex: number) => (
<tr key={rowIndex}>
<td>{row.created}</td>
<td>{row.org_name}</td>
<td>{row.requestor}</td>
<td>{row.type}</td>
<td>{row.ext_outcome}</td>
<td>{row.ext_status}</td>
<td>{row.approved_expiration_date}</td>
<td className="modal-cell">
<select id={`actionsDropdown_${row.ext_id}`} onChange={`openAction('${row.ext_id}')`}>
<option value="">Select Action</option>
<option value="viewAdminExtensions">View Record</option>
<option value="editExtension">Edit Record</option>
</select>
</td>
</tr>
))}
</tbody>
</table>
);
};
4 changes: 4 additions & 0 deletions apcd-cms/src/client/src/components/Admin/Extensions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// index.ts
import { AdminExtensions } from './AdminExtensions';

export { AdminExtensions };
24 changes: 24 additions & 0 deletions apcd-cms/src/client/src/hooks/admin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,28 @@ export type SubmissionLogsModalContent = {
outcome: string;
};

export type ExtensionRow = {
created: string;
org_name: string;
requestor: string;
type: string;
ext_outcome: string;
ext_status: string;
ext_id: string;
submitter_id: string;
approved_expiration_date: string;
};

export type ExtensionResult = {
header: string[];
status_options: string[];
org_options: string[];
selected_status: string;
query_str: string;
pagination_url_namespaces: string;
page: ExtensionRow[];
};

export type ExceptionRow = {
created_at: string;
entity_name: string;
Expand All @@ -135,7 +157,9 @@ export type ExceptionResult = {
pagination_url_namespaces: string;
page: ExceptionRow[];
};

export {
useExtensions,
useRegistrations,
useSubmissions,
useUsers,
Expand Down
20 changes: 20 additions & 0 deletions apcd-cms/src/client/src/hooks/admin/useAdmin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery, UseQueryResult } from 'react-query';
import { fetchUtil } from 'utils/fetchUtil';
import {
ExtensionResult,
RegistrationResult,
UserResult,
SubmissionResult,
Expand Down Expand Up @@ -66,6 +67,25 @@ export const useSubmissions = (
return { ...query };
};

const getExtensions = async (params: any) => {
const url = `administration/list-extensions/api/`;
const response = await fetchUtil({
url,
params,
});
return response.response;
};

export const useExtensions = (
params: any
): UseQueryResult<ExtensionResult> => {
const query = useQuery(['extensions', params], () =>
getExtensions(params)
) as UseQueryResult<ExtensionResult>;

return { ...query };
};

const getExceptions = async (params: any) => {
const url = `administration/list-exceptions/api/`;
const response = await fetchUtil({
Expand Down
2 changes: 2 additions & 0 deletions apcd-cms/src/client/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { BrowserRouter } from 'react-router-dom';
import { AdminRegistrations } from './components/Admin/Registrations';
import { ViewUsers } from './components/Admin/ViewUsers';
import { AdminSubmissions } from './components/Admin/Submissions';
import { AdminExtensions } from './components/Admin/Extensions';
import { AdminExceptions } from './components/Admin/Exceptions';
import { QueryClient, QueryClientProvider } from 'react-query';

Expand All @@ -29,6 +30,7 @@ const componentMap: { [key: string]: React.ComponentType<any> } = {
'list-registrations-root': AdminRegistrations,
'view-users-root': ViewUsers,
'list-admin-submissions': AdminSubmissions,
'admin-extensions-root': AdminExtensions,
'admin-exceptions-root': AdminExceptions,
// Add new components with html id in the list above.
};
Expand Down