Files
itflow/includes/footer.php
johnnyq 359851c876 Security sweep of the 26.11 work: API contact lookup by phone or mobile kept to the key's clients; API credentials refuse a wrong decrypt password instead of saving unreadable usernames and passwords, link credential_vendor_id and credential_software_id, and drop another client's contact or asset; Products Receive window lists expenses only with Financial access and only for clients the agent can open; account ledger, reconcile page and ledger export show lines for clients the agent can't open as Another client with only date, kind and amount, with search and the client filter kept to reachable clients; Tax Collected folds unreachable exempt clients into one line; client-limited agents no longer see other clients' names in the export window client filters, Transfer to Client, company vendor expense lists, My Activity or the New Client duplicate check; Stripe switched off stops guest pay links and saving cards, and the Stripe return never books a payment twice; Admin > Cron job window is admins only; records per page needs the CSRF token and takes only the listed sizes; uploads/canned_responses closed to direct access; Admin > Debug no longer stops at the footer; report export audit log no longer double-escapes names; bulk interface network refuses a deleted network; API assets/update keeps the primary interface IP, MAC and network, tickets/resolve reports success, software/read by name works, clients/create takes the company currency, certificates/create returns its error, clients/archive logs as Client, and the 405 response no longer echoes the method; changelog database step count corrected to sixty
2026-10-23 12:09:07 -04:00

112 lines
4.9 KiB
PHP

<?php
?>
</div><!-- /.container-fluid -->
</div> <!-- /.app-content -->
</main> <!-- /.app-main -->
<?php /* AdminLTE 4's .app-wrapper is a three row grid - header, main, footer -
and the footer row is already reserved (grid-template-rows:
min-content 1fr min-content). Sitting in that row is what pins this to
the bottom: the 1fr main row absorbs the leftover height, so on a short
page the bar lands on the bottom edge of the viewport instead of
floating directly under the content.
It has to be a direct child of .app-wrapper - inside .app-main it is
just content again. */ ?>
<?php if (basename(dirname($_SERVER['REQUEST_URI'])) === 'admin') { ?>
<footer class="app-footer py-2 d-flex align-items-center">
<div class="w-100 text-end fw-light">ITFlow <?= APP_VERSION ?> &nbsp; · &nbsp; <a target="_blank" href="https://docs.itflow.org">Docs</a> &nbsp; · &nbsp; <a target="_blank" href="https://forum.itflow.org">Forum</a> &nbsp; · &nbsp; <a target="_blank" href="https://services.itflow.org">Services</a></div>
</footer>
<?php } ?>
<?php /* The guest portal shares this file and the same .app-wrapper grid (its
own guest_header.php opens it), so its footer goes in the same row.
guest_header.php renders no .app-header and no .app-sidebar, which the
grid handles on its own - the sidebar column is `auto` and the header
row is min-content, so both collapse to zero and .app-main still takes
the 1fr. */ ?>
<?php if (basename(dirname($_SERVER['REQUEST_URI'])) === 'guest') { ?>
<footer class="app-footer py-2 text-center">
<?php
echo escapeHtml($session_company_name);
if (!$config_whitelabel_enabled) {
echo '<br><small class="text-muted">Powered by ITFlow</small>';
}
?>
</footer>
<?php } ?>
</div> <!-- /.app-wrapper -->
<!-- Set the browser window title to the clients name -->
<script>document.title = <?= json_encode("$tab_title - $page_title") ?>;</script>
<!-- REQUIRED SCRIPTS -->
<?php /* The select picker goes FIRST, ahead of Bootstrap itself. Order is
load-bearing: until js/itflow_select.js runs, the browser is showing
the raw <select> controls it painted while parsing the body, so every
byte in front of it is time spent looking at the wrong widget. It
needs nothing else on the page, so nothing goes in front of it.
includes/header.php preloads it.
Bootstrap moving down is safe: it has always loaded in the footer, so
no markup above this point could ever have used the `bootstrap` global
at parse time. Every call site is inside an event handler or waits for
DOMContentLoaded - includes/inc_alert_feedback.php says so in its own
comment - and all of those still run well after this block. */ ?>
<script src="/js/itflow_select.js"></script>
<!-- Bootstrap 5 -->
<script src="/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="/js/http.js"></script>
<!-- Custom js-->
<script src="/libs/chart.js/chart.umd.min.js"></script>
<script src="/libs/flatpickr/js/flatpickr.min.js"></script>
<script src="/libs/imask/js/imask.min.js"></script>
<script src="/libs/tinymce/tinymce.min.js" referrerpolicy="origin"></script>
<script src="/js/keepalive.js"></script>
<script src="/libs/DataTables/datatables.min.js"></script>
<script src="/libs/intl-tel-input/js/intlTelInputWithUtils.min.js"></script>
<script src="/js/phone_inputs.js"></script>
<!-- AdminLTE App -->
<script src="/libs/adminlte/js/adminlte.min.js"></script>
<script src="/libs/sweetalert2/js/sweetalert2.min.js"></script>
<script src="/js/autocomplete.js"></script>
<?php /* What the editors' Reword button needs - false when AI isn't set up or the role may not use it (aiClientConfig(), functions/ai.php) */ ?>
<?php
// A page that closed the database before its footer (admin/debug.php does) gets no Reword, rather than a fatal error
try {
$itflow_ai_config = function_exists('aiClientConfig') ? aiClientConfig() : false;
} catch (Throwable $e) {
$itflow_ai_config = false;
}
?>
<script>window.itflowAi = <?= json_encode($itflow_ai_config) ?>;</script>
<script src="/js/app.js"></script>
<script src="/js/credentials.js"></script>
<script src="/js/tag_picker.js"></script>
<script src="/js/quick_pick.js"></script>
<script src="/js/ajax_modal.js"></script>
<script src="/js/confirm_modal.js"></script>
<script src="/js/date_filter.js"></script>
<script src="/js/global_search.js"></script>
<script src="/js/notifications.js"></script>
<?php if (basename(dirname($_SERVER['REQUEST_URI'])) === 'admin') { ?>
<script src="/js/settings.js"></script>
<?php } ?>
</body>
</html>
<?php
// Calculate Execution time Uncomment for test
//$time_end = microtime(true);
//$execution_time = ($time_end - $time_start);
//echo '<h2>Total Execution Time: '.number_format((float) $execution_time, 10) .' seconds</h2>';