From f162b6b7e3b0f454f0b19e2de072d92aaf64e866 Mon Sep 17 00:00:00 2001 From: Jeremy Booker Date: Sat, 13 Sep 2025 12:49:36 -0400 Subject: [PATCH 1/2] WIP on reporting interfaces --- class/Command/ShowReports.php | 44 +++++++++++++++++++++++++++++ class/InternshipInventory.php | 5 ++++ class/ReportsView.php | 34 ++++++++++++++++++++++ class/UI/TopUI.php | 53 ++++++++++++++++++----------------- templates/reports.tpl | 1 + templates/top.tpl | 4 +++ 6 files changed, 115 insertions(+), 26 deletions(-) create mode 100644 class/Command/ShowReports.php create mode 100644 class/ReportsView.php create mode 100644 templates/reports.tpl diff --git a/class/Command/ShowReports.php b/class/Command/ShowReports.php new file mode 100644 index 00000000..69021179 --- /dev/null +++ b/class/Command/ShowReports.php @@ -0,0 +1,44 @@ +. + * + * Copyright 2011-2025 Appalachian State University + */ + +namespace Intern\Command; + +use \Intern\UI\NotifyUI; +use \Intern\ReportsView; + +class ShowReports +{ + public function __construct() {} + + public function execute(): ReportsView + { + // Check permissions + if (!\Current_User::allow('intern', 'view_reports')) { + \NQ::simple('intern', NotifyUI::ERROR, 'You do not have permission to view reports.'); + \NQ::close(); + \PHPWS_Core::home(); + } + + $view = new ReportsView(); + + return $view; + } +} diff --git a/class/InternshipInventory.php b/class/InternshipInventory.php index b40767a4..90a69591 100644 --- a/class/InternshipInventory.php +++ b/class/InternshipInventory.php @@ -359,6 +359,11 @@ public function handleRequest() $ctrl = new Command\CipCodeRest(); $ctrl->execute(); break; + case 'reports': + $ctrl = new Command\ShowReports(); + $view = $ctrl->execute(); + $this->content = $view->render(); + break; default: $menu = new UI\InternMenu(); $this->content = $menu->display(); diff --git a/class/ReportsView.php b/class/ReportsView.php new file mode 100644 index 00000000..218b7d60 --- /dev/null +++ b/class/ReportsView.php @@ -0,0 +1,34 @@ +. + * + * Copyright 2011-2025 Appalachian State University + */ + +namespace Intern; + +class ReportsView +{ + public function __construct() {} + + public function render(): string + { + $tpl = array(); + + return \PHPWS_Template::process($tpl, 'intern', 'reports.tpl'); + } +} diff --git a/class/UI/TopUI.php b/class/UI/TopUI.php index 22f1e89a..054278e0 100644 --- a/class/UI/TopUI.php +++ b/class/UI/TopUI.php @@ -1,4 +1,5 @@ user->auth_script == 'local.php'){ + if ($auth->user->auth_script == 'local.php') { $tpl['PASSWORD_DROPDOWN_NAME'] = \Current_User::getDisplayName();; - }else { + } else { // Otherwise, it's just their name with no dropdown menu $tpl['USER_FULL_NAME'] = \Current_User::getDisplayName(); } @@ -61,59 +61,60 @@ public static function plug() $adminOptions = array(); // Edit terms - if(\Current_User::allow('intern', 'edit_terms')){ - $adminOptions['EDIT_TERMS_LINK'] = \PHPWS_Text::secureLink('Terms','intern',array('action' => 'edit_terms'), null, null, 'dropdown-item'); + if (\Current_User::allow('intern', 'edit_terms')) { + $adminOptions['EDIT_TERMS_LINK'] = \PHPWS_Text::secureLink('Terms', 'intern', array('action' => 'edit_terms'), null, null, 'dropdown-item'); } // Edit departments - if(\Current_User::allow('intern', 'edit_dept')){ - $adminOptions['EDIT_DEPARTMENTS_LINK'] = \PHPWS_Text::secureLink('Departments','intern',array('action' => 'showEditDept'), null, null, 'dropdown-item'); + if (\Current_User::allow('intern', 'edit_dept')) { + $adminOptions['EDIT_DEPARTMENTS_LINK'] = \PHPWS_Text::secureLink('Departments', 'intern', array('action' => 'showEditDept'), null, null, 'dropdown-item'); } // Edit list of majors - if(\Current_User::allow('intern', 'edit_major')){ - $adminOptions['EDIT_MAJORS_LINK'] = \PHPWS_Text::secureLink('Majors & Programs','intern',array('action' => 'showEditMajors'), null, null, 'dropdown-item'); + if (\Current_User::allow('intern', 'edit_major')) { + $adminOptions['EDIT_MAJORS_LINK'] = \PHPWS_Text::secureLink('Majors & Programs', 'intern', array('action' => 'showEditMajors'), null, null, 'dropdown-item'); } // Edit list of student levels - if(\Current_User::allow('intern', 'edit_level')){ - $adminOptions['EDIT_STUDENT_LEVEL'] = \PHPWS_Text::secureLink('Student Levels','intern',array('action' => 'edit_level'), null, null, 'dropdown-item'); - + if (\Current_User::allow('intern', 'edit_level')) { + $adminOptions['EDIT_STUDENT_LEVEL'] = \PHPWS_Text::secureLink('Student Levels', 'intern', array('action' => 'edit_level'), null, null, 'dropdown-item'); } // Edit list of 'normal' courses - if(\Current_User::allow('intern', 'edit_courses')){ - $adminOptions['EDIT_COURSES_LINK'] = \PHPWS_Text::secureLink('Course List','intern',array('action' => 'edit_courses'), null, null, 'dropdown-item'); + if (\Current_User::allow('intern', 'edit_courses')) { + $adminOptions['EDIT_COURSES_LINK'] = \PHPWS_Text::secureLink('Course List', 'intern', array('action' => 'edit_courses'), null, null, 'dropdown-item'); } // Edit list of states - if(\Current_User::allow('intern', 'edit_states')){ - $adminOptions['EDIT_STATES_LINK'] = \PHPWS_Text::secureLink('Allowed States','intern',array('action' => 'edit_states'), null, null, 'dropdown-item'); + if (\Current_User::allow('intern', 'edit_states')) { + $adminOptions['EDIT_STATES_LINK'] = \PHPWS_Text::secureLink('Allowed States', 'intern', array('action' => 'edit_states'), null, null, 'dropdown-item'); } // Link to the Affiliation Agreements - if(\Current_User::allow('intern', 'affiliation_agreement')){ - $adminOptions['AFFIL_AGREE_LINK'] = \PHPWS_Text::secureLink('Affiliation Agreements','intern',array('action' => 'showAffiliateAgreement'), null, null, 'dropdown-item'); + if (\Current_User::allow('intern', 'affiliation_agreement')) { + $adminOptions['AFFIL_AGREE_LINK'] = \PHPWS_Text::secureLink('Affiliation Agreements', 'intern', array('action' => 'showAffiliateAgreement'), null, null, 'dropdown-item'); } - if(\Current_User::allow('intern', 'student_import')){ + if (\Current_User::allow('intern', 'student_import')) { $adminOptions['STUDENT_IMPORT'] = \PHPWS_Text::secureLink('Import Student Data', 'intern', array('action' => 'ShowStudentImport'), null, null, 'dropdown-item'); } - if(\Current_User::allow('intern', 'internship_import')){ + if (\Current_User::allow('intern', 'internship_import')) { $adminOptions['ACTIVITY_IMPORT'] = \PHPWS_Text::secureLink('Import Activities', 'intern', array('action' => 'ShowImportActivitiesStart'), null, null, 'dropdown-item'); } - if(\Current_User::isDeity()){ - $adminOptions['CONTROL_PANEL'] = \PHPWS_Text::secureLink('Control Panel','controlpanel', null, null, null, 'dropdown-item'); - $adminOptions['ADMIN_SETTINGS'] = \PHPWS_Text::secureLink('Admin Settings','intern',array('action' => 'showAdminSettings'), null, null, 'dropdown-item'); - $adminOptions['EDIT_ADMINS_LINK'] = \PHPWS_Text::secureLink('Dept. Administrators','intern',array('action' => 'showEditAdmins'), null, null, 'dropdown-item'); + if (\Current_User::isDeity()) { + $adminOptions['CONTROL_PANEL'] = \PHPWS_Text::secureLink('Control Panel', 'controlpanel', null, null, null, 'dropdown-item'); + $adminOptions['ADMIN_SETTINGS'] = \PHPWS_Text::secureLink('Admin Settings', 'intern', array('action' => 'showAdminSettings'), null, null, 'dropdown-item'); + $adminOptions['EDIT_ADMINS_LINK'] = \PHPWS_Text::secureLink('Dept. Administrators', 'intern', array('action' => 'showEditAdmins'), null, null, 'dropdown-item'); } + $adminOptions['REPORTS_LINK'] = \PHPWS_Text::secureLink('Reports', 'intern', array('action' => 'reports'), null, null, 'dropdown-item'); + // If any admin options were added, them show the dropdown and merge those // links into the main set of template tags - if(sizeof($adminOptions) > 0){ + if (sizeof($adminOptions) > 0) { $tpl['ADMIN_OPTIONS'] = ''; // dummy var to show dropdown menu in template $tpl = array_merge($tpl, $adminOptions); } diff --git a/templates/reports.tpl b/templates/reports.tpl new file mode 100644 index 00000000..623542a7 --- /dev/null +++ b/templates/reports.tpl @@ -0,0 +1 @@ +

Reports

\ No newline at end of file diff --git a/templates/top.tpl b/templates/top.tpl index ac5bb2ee..2013bd7e 100644 --- a/templates/top.tpl +++ b/templates/top.tpl @@ -56,6 +56,10 @@
  • +
  • {REPORTS_LINK}
  • +
  • + +
  • {STUDENT_IMPORT}
  • From 69bcdb35f87643e34330d4eedd4a8e4109613c8c Mon Sep 17 00:00:00 2001 From: Jeremy Booker Date: Sat, 4 Oct 2025 11:39:01 -0400 Subject: [PATCH 2/2] Add basics of report view. --- class/ReportsView.php | 3 ++ entryPoints.js | 1 + javascript/pages/ReportsPage.jsx | 66 +++++++++++++++++++++++++++++ javascript/reports/ReportsTable.jsx | 35 +++++++++++++++ templates/reports.tpl | 5 ++- 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 javascript/pages/ReportsPage.jsx create mode 100644 javascript/reports/ReportsTable.jsx diff --git a/class/ReportsView.php b/class/ReportsView.php index 218b7d60..614c435e 100644 --- a/class/ReportsView.php +++ b/class/ReportsView.php @@ -29,6 +29,9 @@ public function render(): string { $tpl = array(); + $tpl['vendor_bundle'] = AssetResolver::resolveJsPath('assets.json', 'vendor'); + $tpl['entry_bundle'] = AssetResolver::resolveJsPath('assets.json', 'reports'); + return \PHPWS_Template::process($tpl, 'intern', 'reports.tpl'); } } diff --git a/entryPoints.js b/entryPoints.js index 25806860..b17c569b 100644 --- a/entryPoints.js +++ b/entryPoints.js @@ -20,6 +20,7 @@ module.exports = { majorSelector: JS_DIR + '/majorSelector/MajorSelector.jsx', adminSettings: JS_DIR + '/settings/settings.jsx', editTerms: JS_DIR + '/editTerms/TermEditor.jsx', + reports: JS_DIR + '/pages/ReportsPage.jsx', vendor: ['jquery', 'react', 'react-dom', 'react-bootstrap'] } }; diff --git a/javascript/pages/ReportsPage.jsx b/javascript/pages/ReportsPage.jsx new file mode 100644 index 00000000..1b32af02 --- /dev/null +++ b/javascript/pages/ReportsPage.jsx @@ -0,0 +1,66 @@ +import React, { useState } from 'react'; +import { createRoot } from 'react-dom/client'; + +import { ErrorBoundary } from 'react-error-boundary'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; + +import Offcanvas from 'react-bootstrap/Offcanvas'; +import ReportsTable from '../reports/ReportsTable'; + +const queryClient = new QueryClient(); + +function ReportsPage() { + const [showNewReportPanel, setShowNewReportPanel] = useState(false); + + const handleShowNewReportPanel = () => { + setShowNewReportPanel(true); + }; + + const handleHideNewReportPanel = () => { + setShowNewReportPanel(false); + }; + + return ( +
    +

    + Reports +

    + +
    +
    +
    + +
    +
    +
    + + + + Create a New Report + + +

    Report creation functionality coming soon!

    +
    +
    + + Something went wrong.
    }> + + + + ); +} + +const root = createRoot(document.getElementById('content')); + +root.render( + + + +); + +if (process.env.NODE_ENV !== 'production') { + const axe = require('@axe-core/react'); + axe(React, root, 1000); +} diff --git a/javascript/reports/ReportsTable.jsx b/javascript/reports/ReportsTable.jsx new file mode 100644 index 00000000..9869fc51 --- /dev/null +++ b/javascript/reports/ReportsTable.jsx @@ -0,0 +1,35 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import { AgGridReact } from 'ag-grid-react'; + +import 'ag-grid-community/styles/ag-grid.css'; // Mandatory CSS required by the Data Grid +import 'ag-grid-community/styles/ag-theme-quartz.css'; // Optional Theme applied to the Data Grid + +export default function ReportsTable({ isLoading }) { + if (isLoading) { + return ( +
    + Loading... +
    + ); + } + + const colDefs = [ + { field: 'reportName', width: 300, headerName: 'Report Name' }, + { field: 'createdBy', width: 200, headerName: 'Created By' }, + { field: 'createdOn', width: 180, headerName: 'Created On' }, + { field: 'download', width: 180, headerName: 'Download' } + ]; + + const gridOptions = { + domLayout: 'autoHeight' + }; + + return ( +
    +
    + +
    +
    + ); +} diff --git a/templates/reports.tpl b/templates/reports.tpl index 623542a7..271fac72 100644 --- a/templates/reports.tpl +++ b/templates/reports.tpl @@ -1 +1,4 @@ -

    Reports

    \ No newline at end of file +
    + + + \ No newline at end of file