Files and documents everywhere else: asset and contact quick looks list their documents and files with the same tiles and rows as the document page, files opening their quick look instead of a raw download; client overview share links show document and file tiles and open the document page or file quick look; service quick look shows linked documents as tiles and leaves out archived ones, service add and edit document pickers carry an icon and summary; global search shows file and document type tiles in the palette and on the results page, and a file result opens its folder narrowed to that file; quote attachments show their tile and size, open the file quick look and download through file.php instead of linking straight into the uploads folder; ticket attachments show their file type tile; client portal documents list shows the document tile, folder and summary with the last updated date; removed unused modals/asset/asset_documents.php

This commit is contained in:
johnnyq
2026-10-14 20:47:30 -04:00
parent 1a613eab7b
commit 6ff9dbe9a4
15 changed files with 124 additions and 145 deletions

View File

@@ -354,14 +354,25 @@ $money_format = function ($amount) use ($currency_format, $client_currency_code,
</div>
<div class="list-group list-group-flush">
<?php foreach ($shared_items as $item) {
$item_icon = ['Credential' => 'key', 'Document' => 'file-alt', 'File' => 'paperclip'][$item['item_type']] ?? 'share-square';
$item_views = intval($item['item_views']);
$item_limit = intval($item['item_view_limit']);
$item_related_id = intval($item['item_related_id']);
$item_label = escapeHtml($item['item_name'] ?: $item['item_type']);
// Documents and files look and open as they do everywhere else
if ($item['item_type'] === 'Document') {
$item_tile = documentTile('sm');
$item_label = "<a href=\"document.php?client_id=$client_id&amp;document_id=$item_related_id\">$item_label</a>";
} elseif ($item['item_type'] === 'File') {
$item_tile = fileTypeTile($item['file_ext'], 'sm');
$item_label = "<a class=\"ajax-modal\" href=\"#\" data-modal-size=\"lg\" data-modal-url=\"modals/file/file.php?id=$item_related_id\">$item_label</a>";
} else {
$item_tile = '<span class="itflow-link-icon" title="' . escapeHtml($item['item_type']) . '" aria-hidden="true"><i class="fas fa-fw fa-' . ($item['item_type'] === 'Credential' ? 'key' : 'share-square') . '"></i></span>';
}
?>
<div class="list-group-item d-flex align-items-center gap-2 py-2">
<i class="fas fa-fw fa-<?= $item_icon ?> text-body-secondary" title="<?= escapeHtml($item['item_type']) ?>"></i>
<?= $item_tile ?>
<span class="flex-grow-1 overflow-hidden">
<span class="d-block text-truncate"><?= escapeHtml($item['item_name'] ?: $item['item_type']) ?></span>
<span class="d-block text-truncate"><?= $item_label ?></span>
<span class="d-block small text-body-secondary text-truncate">
<?= $item['item_recipient'] ? escapeHtml($item['item_recipient']) . ', ' : '' ?><?= $item_views ?><?= $item_limit ? " of $item_limit" : '' ?> view<?= ($item_limit ?: $item_views) === 1 ? '' : 's' ?>, expires <?= escapeHtml(timeAgo($item['item_expire_at'])) ?>
</span>

View File

@@ -163,6 +163,9 @@ function searchResultBadge($badge) {
$item_url = escapeHtml($item['url']);
?>
<div class="list-group-item d-flex align-items-center gap-3 py-2">
<?php if (!empty($item['tile']) && preg_match('/^[a-z]+$/', $item['tile']['tone']) && preg_match('/^[a-z0-9-]+$/', $item['tile']['icon'])) { ?>
<span class="itflow-file-icon itflow-file-icon-sm itflow-file-tone-<?= $item['tile']['tone'] ?>" title="<?= escapeHtml($item['tile']['label']) ?>" aria-hidden="true"><i class="fas fa-fw fa-<?= $item['tile']['icon'] ?>"></i></span>
<?php } ?>
<?php if (!empty($item['avatar'])) {
// A contact - their avatar, as everywhere else they appear
$avatar = $item['avatar'];

View File

@@ -154,24 +154,12 @@ $sql_related_software = mysqli_query($mysqli, "SELECT software_assets.software_i
$software_count = mysqli_num_rows($sql_related_software);
// Documents
$sql_related_documents = mysqli_query($mysqli, "SELECT documents.document_id, document_name, document_created_at, document_updated_at
FROM asset_documents
JOIN documents ON asset_documents.document_id = documents.document_id
WHERE asset_documents.asset_id = $asset_id
AND document_archived_at IS NULL
ORDER BY document_name ASC"
);
$document_count = mysqli_num_rows($sql_related_documents);
$linked_documents = linkedRecords('asset', $asset_id, 'document');
$document_count = count($linked_documents);
// Files
$sql_related_files = mysqli_query($mysqli, "SELECT files.file_id, file_name, file_ext, file_created_at
FROM asset_files
JOIN files ON asset_files.file_id = files.file_id
WHERE asset_files.asset_id = $asset_id
AND file_archived_at IS NULL
ORDER BY file_name ASC"
);
$file_count = mysqli_num_rows($sql_related_files);
$linked_files = linkedRecords('asset', $asset_id, 'file');
$file_count = count($linked_files);
// Notes
$sql_related_notes = mysqli_query($mysqli, "SELECT asset_note, asset_note_created_at, asset_note_type, user_name FROM asset_notes
@@ -476,13 +464,10 @@ ob_start();
<?php if ($document_count) { ?>
<div class="tab-pane fade <?= $first_tab === 'documents' ? 'show active' : '' ?>" id="asset-quick-<?= $asset_id ?>-documents" role="tabpanel">
<ul class="list-group list-group-flush">
<?php while ($row = mysqli_fetch_assoc($sql_related_documents)) {
$document_last = $row['document_updated_at'] ?: $row['document_created_at']; ?>
<li class="list-group-item px-0 d-flex justify-content-between gap-3">
<a class="ajax-modal" href="#" data-modal-size="lg" data-modal-url="modals/document/document_view.php?id=<?= intval($row['document_id']) ?>"><i class="fas fa-fw fa-file-alt text-secondary me-2"></i><?= escapeHtml($row['document_name']) ?></a>
<span class="small text-body-secondary text-nowrap" title="<?= escapeHtml($document_last) ?>"><?= timeAgo($document_last) ?></span>
</li>
<!-- The same rows as a document's Linked card - tile, name, when it changed -->
<ul class="list-unstyled mb-0 itflow-links">
<?php foreach ($linked_documents as $row) { ?>
<li class="itflow-link-row"><?= linkRowHtml('document', $row, $client_id) ?></li>
<?php } ?>
</ul>
</div>
@@ -490,12 +475,10 @@ ob_start();
<?php if ($file_count) { ?>
<div class="tab-pane fade <?= $first_tab === 'files' ? 'show active' : '' ?>" id="asset-quick-<?= $asset_id ?>-files" role="tabpanel">
<ul class="list-group list-group-flush">
<?php while ($row = mysqli_fetch_assoc($sql_related_files)) { ?>
<li class="list-group-item px-0 d-flex justify-content-between gap-3">
<a href="file.php?file_id=<?= intval($row['file_id']) ?>&action=view" target="_blank" rel="noopener"><i class="fas fa-fw fa-<?= getFileIcon((string) $row['file_ext']) ?> text-secondary me-2"></i><?= escapeHtml($row['file_name']) ?></a>
<span class="small text-body-secondary text-nowrap" title="<?= escapeHtml($row['file_created_at']) ?>"><?= timeAgo($row['file_created_at']) ?></span>
</li>
<!-- Each opens its quick look - preview, details, what else it is linked to -->
<ul class="list-unstyled mb-0 itflow-links">
<?php foreach ($linked_files as $row) { ?>
<li class="itflow-link-row"><?= linkRowHtml('file', $row, $client_id) ?></li>
<?php } ?>
</ul>
</div>

View File

@@ -1,27 +0,0 @@
<div class="modal" id="assetDocumentsModal<?= $asset_id ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-<?= $device_icon ?> me-2"></i><?= $asset_name ?> Documents</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<?php
while ($row = mysqli_fetch_assoc($sql_related_documents)) {
$related_document_id = intval($row['document_id']);
$related_document_name = escapeHtml($row['document_name']);
?>
<p>
<i class="fas fa-fw fa-document text-secondary"></i>
<?= $related_document_name ?> <a href="client_documents.php?q=<?= $related_document_name ?>"><?= $related_document_name ?></a>
</p>
<?php } ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Cancel</button>
</div>
</div>
</div>
</div>

View File

@@ -124,24 +124,12 @@ $sql_linked_software = mysqli_query($mysqli, "SELECT software.software_id, softw
$software_count = mysqli_num_rows($sql_linked_software);
// Documents
$sql_linked_documents = mysqli_query($mysqli, "SELECT documents.document_id, document_name, document_created_at, document_updated_at
FROM contact_documents
JOIN documents ON documents.document_id = contact_documents.document_id
WHERE contact_documents.contact_id = $contact_id
AND document_archived_at IS NULL
ORDER BY document_name ASC"
);
$document_count = mysqli_num_rows($sql_linked_documents);
$linked_documents = linkedRecords('contact', $contact_id, 'document');
$document_count = count($linked_documents);
// Files
$sql_linked_files = mysqli_query($mysqli, "SELECT files.file_id, file_name, file_ext, file_created_at
FROM contact_files
JOIN files ON files.file_id = contact_files.file_id
WHERE contact_files.contact_id = $contact_id
AND file_archived_at IS NULL
ORDER BY file_name ASC"
);
$file_count = mysqli_num_rows($sql_linked_files);
$linked_files = linkedRecords('contact', $contact_id, 'file');
$file_count = count($linked_files);
// Notes
$sql_related_notes = mysqli_query($mysqli, "SELECT contact_note, contact_note_created_at, contact_note_type, user_name FROM contact_notes
@@ -399,13 +387,10 @@ ob_start();
<?php if ($document_count) { ?>
<div class="tab-pane fade <?= $first_tab === 'documents' ? 'show active' : '' ?>" id="contact-quick-<?= $contact_id ?>-documents" role="tabpanel">
<ul class="list-group list-group-flush">
<?php while ($row = mysqli_fetch_assoc($sql_linked_documents)) {
$document_last = $row['document_updated_at'] ?: $row['document_created_at']; ?>
<li class="list-group-item px-0 d-flex justify-content-between gap-3">
<a class="ajax-modal" href="#" data-modal-size="lg" data-modal-url="modals/document/document_view.php?id=<?= intval($row['document_id']) ?>"><i class="fas fa-fw fa-file-alt text-secondary me-2"></i><?= escapeHtml($row['document_name']) ?></a>
<span class="small text-body-secondary text-nowrap" title="<?= escapeHtml($document_last) ?>"><?= timeAgo($document_last) ?></span>
</li>
<!-- The same rows as a document's Linked card - tile, name, when it changed -->
<ul class="list-unstyled mb-0 itflow-links">
<?php foreach ($linked_documents as $row) { ?>
<li class="itflow-link-row"><?= linkRowHtml('document', $row, $client_id) ?></li>
<?php } ?>
</ul>
</div>
@@ -413,12 +398,10 @@ ob_start();
<?php if ($file_count) { ?>
<div class="tab-pane fade <?= $first_tab === 'files' ? 'show active' : '' ?>" id="contact-quick-<?= $contact_id ?>-files" role="tabpanel">
<ul class="list-group list-group-flush">
<?php while ($row = mysqli_fetch_assoc($sql_linked_files)) { ?>
<li class="list-group-item px-0 d-flex justify-content-between gap-3">
<a href="file.php?file_id=<?= intval($row['file_id']) ?>&action=view" target="_blank" rel="noopener"><i class="fas fa-fw fa-<?= getFileIcon((string) $row['file_ext']) ?> text-secondary me-2"></i><?= escapeHtml($row['file_name']) ?></a>
<span class="small text-body-secondary text-nowrap" title="<?= escapeHtml($row['file_created_at']) ?>"><?= timeAgo($row['file_created_at']) ?></span>
</li>
<!-- Each opens its quick look - preview, details, what else it is linked to -->
<ul class="list-unstyled mb-0 itflow-links">
<?php foreach ($linked_files as $row) { ?>
<li class="itflow-link-row"><?= linkRowHtml('file', $row, $client_id) ?></li>
<?php } ?>
</ul>
</div>

View File

@@ -89,9 +89,11 @@ $sql_contacts = mysqli_query(
// Associated Documents
$sql_docs = mysqli_query(
$mysqli,
"SELECT documents.document_id, document_name FROM service_documents
LEFT JOIN documents ON service_documents.document_id = documents.document_id
WHERE service_id = $service_id"
"SELECT documents.document_id AS id, document_name AS name, document_description, document_created_at, document_updated_at
FROM service_documents
JOIN documents ON service_documents.document_id = documents.document_id
WHERE service_id = $service_id AND document_archived_at IS NULL
ORDER BY document_name ASC"
);
ob_start();
@@ -297,12 +299,11 @@ ob_start();
<!-- Documents -->
<?php
if (mysqli_num_rows($sql_docs) > 0) {
echo "<h5><i class='fas fa-fw fa-file-alt me-2'></i>Documents</h5><ul>";
// The same rows as a document's Linked card
echo "<h5><i class='fas fa-fw fa-file-alt me-2'></i>Documents</h5><ul class='list-unstyled itflow-links'>";
mysqli_data_seek($sql_docs, 0);
while ($row = mysqli_fetch_assoc($sql_docs)) {
$document_id = intval($row['document_id']);
$document_name = escapeHtml($row['document_name']);
echo "<li><a class='ajax-modal' href='#' data-modal-size='lg' data-modal-url='modals/document/document_view.php?id=$document_id'>$document_name</a></li>";
echo '<li class="itflow-link-row">' . linkRowHtml('document', $row, $client_id) . '</li>';
}
echo "</ul>";
}

View File

@@ -152,11 +152,11 @@ ob_start();
<label for="documents">Select related documents</label>
<select class="form-select select2" id="documents" name="documents[]" multiple>
<?php
$sql = mysqli_query($mysqli, "SELECT document_id, document_name FROM documents WHERE document_archived_at IS NULL AND document_client_id = $client_id");
$sql = mysqli_query($mysqli, "SELECT document_id, document_name, document_description FROM documents WHERE document_archived_at IS NULL AND document_client_id = $client_id ORDER BY document_name ASC");
while ($row = mysqli_fetch_assoc($sql)) {
$document_id = intval($row['document_id']);
$document_name = escapeHtml($row['document_name']);
echo "<option value=\"$document_id\">$document_name</option>";
echo "<option value=\"$document_id\"" . selectOptionData(['icon' => 'fas fa-file-alt', 'description' => $row['document_description']]) . ">$document_name</option>";
}
?>
</select>

View File

@@ -224,18 +224,12 @@ ob_start();
<?php
$selected_ids = array_column(mysqli_fetch_all($sql_docs, MYSQLI_ASSOC), "document_id");
$sql_all = mysqli_query($mysqli, "SELECT document_id, document_name FROM documents WHERE document_archived_at IS NULL AND document_client_id = $client_id");
$sql_all = mysqli_query($mysqli, "SELECT document_id, document_name, document_description FROM documents WHERE document_archived_at IS NULL AND document_client_id = $client_id ORDER BY document_name ASC");
while ($row_all = mysqli_fetch_assoc($sql_all)) {
$document_id = intval($row_all['document_id']);
$document_name = escapeHtml($row_all['document_name']);
if (in_array($document_id, $selected_ids)) {
echo "<option value=\"$document_id\" selected>$document_name</option>";
}
else{
echo "<option value=\"$document_id\">$document_name</option>";
}
$document_selected = in_array($document_id, $selected_ids) ? ' selected' : '';
echo "<option value=\"$document_id\"$document_selected" . selectOptionData(['icon' => 'fas fa-file-alt', 'description' => $row_all['document_description']]) . ">$document_name</option>";
}
?>
</select>

View File

@@ -133,7 +133,7 @@ if (isset($_GET['quote_id'])) {
// Quote File Attachments
$sql_quote_files = mysqli_query(
$mysqli,
"SELECT file_reference_name, file_name, file_created_at FROM quote_files LEFT JOIN files ON quote_files.file_id = files.file_id WHERE quote_id = $quote_id"
"SELECT files.file_id, file_name, file_ext, file_size, file_created_at FROM quote_files JOIN files ON quote_files.file_id = files.file_id WHERE quote_id = $quote_id AND file_archived_at IS NULL ORDER BY file_name ASC"
);
?>
@@ -526,30 +526,31 @@ if (isset($_GET['quote_id'])) {
</div>
</div>
<div class="card-body">
<table class="table">
<thead>
<?php /* Through the file quick look and agent/file.php, which check access -
not a link straight into the uploads folder */ ?>
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th>File Name</th>
<th>Upload date</th>
<th>File</th>
<th>Uploaded</th>
<th></th>
</tr>
</thead>
<tbody>
<?php
while ($quote_file = mysqli_fetch_assoc($sql_quote_files)) {
$name = escapeHtml($quote_file['file_name']);
$ref_name = escapeHtml($quote_file['file_reference_name']);
$created = escapeHtml($quote_file['file_created_at']);
?>
<?php while ($quote_file = mysqli_fetch_assoc($sql_quote_files)) {
$quote_file_id = intval($quote_file['file_id']); ?>
<tr>
<td><a target="_blank" href="../uploads/clients/<?= $client_id ?>/<?= $ref_name ?>"><?= $name ?></a></td>
<td><?= $created ?></td>
<td>
<div class="d-flex align-items-center gap-2">
<?= fileTypeTile($quote_file['file_ext'], 'sm') ?>
<a class="ajax-modal text-break" href="#" data-modal-size="lg" data-modal-url="modals/file/file.php?id=<?= $quote_file_id ?>"><?= escapeHtml($quote_file['file_name']) ?></a>
<span class="small text-body-secondary text-nowrap"><?= formatBytes(intval($quote_file['file_size'])) ?></span>
</div>
</td>
<td class="small text-nowrap" title="<?= escapeHtml($quote_file['file_created_at']) ?>"><?= timeAgo($quote_file['file_created_at']) ?></td>
<td class="text-end"><a class="btn btn-sm btn-light" href="file.php?file_id=<?= $quote_file_id ?>" title="Download"><i class="fas fa-fw fa-download"></i></a></td>
</tr>
<?php
}
?>
<?php } ?>
</tbody>
</table>
</div>

View File

@@ -639,7 +639,7 @@ if (isset($_GET['ticket_id'])) {
$ticket_attachment_name = escapeHtml($ticket_attachment['ticket_attachment_name']);
?>
<div class="mt-1">
<i class="fas fa-fw fa-paperclip text-secondary me-1"></i><?= $ticket_attachment_name ?>
<span class="me-1 align-middle"><?= fileTypeTile(pathinfo($ticket_attachment['ticket_attachment_name'], PATHINFO_EXTENSION), 'xs') ?></span><?= $ticket_attachment_name ?>
<a target="_blank" class="ms-2 small" href="ticket_attachment.php?attachment_id=<?= $ticket_attachment_id ?>&action=view">View</a>
<a class="ms-2 small" href="ticket_attachment.php?attachment_id=<?= $ticket_attachment_id ?>">Download</a>
<?php if (lookupUserPermission("module_support") >= 3) { ?>
@@ -932,7 +932,7 @@ if (isset($_GET['ticket_id'])) {
$ticket_attachment_name = escapeHtml($ticket_attachment['ticket_attachment_name']);
?>
<div class="mt-1">
<i class="fas fa-fw fa-paperclip text-secondary me-1"></i><?= $ticket_attachment_name ?>
<span class="me-1 align-middle"><?= fileTypeTile(pathinfo($ticket_attachment['ticket_attachment_name'], PATHINFO_EXTENSION), 'xs') ?></span><?= $ticket_attachment_name ?>
<a target="_blank" class="ms-2 small" href="ticket_attachment.php?attachment_id=<?= $ticket_attachment_id ?>&action=view">View</a>
<a class="ms-2 small" href="ticket_attachment.php?attachment_id=<?= $ticket_attachment_id ?>">Download</a>
<?php if (lookupUserPermission("module_support") >= 3) { ?>

View File

@@ -10,7 +10,7 @@ require_once "includes/inc_all.php";
enforceContactCan('itdoc');
$documents_sql = mysqli_query($mysqli, "SELECT document_id, document_name, document_created_at, folder_name FROM documents LEFT JOIN folders ON document_folder_id = folder_id WHERE document_client_visible = 1 AND document_client_id = $session_client_id AND document_archived_at IS NULL ORDER BY folder_id, document_name DESC");
$documents_sql = mysqli_query($mysqli, "SELECT document_id, document_name, document_description, document_created_at, document_updated_at, folder_name FROM documents LEFT JOIN folders ON document_folder_id = folder_id WHERE document_client_visible = 1 AND document_client_id = $session_client_id AND document_archived_at IS NULL ORDER BY folder_id, document_name DESC");
?>
<div class="row">
@@ -34,11 +34,11 @@ $documents_sql = mysqli_query($mysqli, "SELECT document_id, document_name, docum
<?php if (mysqli_num_rows($documents_sql) == 0) { ?>
<?= portalEmptyState('There are no documents shared with you yet.') ?>
<?php } else { ?>
<table class="table table-bordered border border-dark">
<table class="table table-hover align-middle border">
<thead class="table-dark">
<tr>
<th>Name</th>
<th>Created</th>
<th>Updated</th>
<th class="text-center">Actions</th>
</tr>
</thead>
@@ -49,23 +49,25 @@ $documents_sql = mysqli_query($mysqli, "SELECT document_id, document_name, docum
$document_id = intval($row['document_id']);
$folder_name = escapeHtml($row['folder_name']);
$document_name = escapeHtml($row['document_name']);
$document_created_at = escapeHtml($row['document_created_at']);
$document_updated_at = $row['document_updated_at'] ?: $row['document_created_at'];
?>
<tr>
<td>
<a href="document.php?id=<?= $document_id ?>">
<i class="fas fa-file-alt me-2"></i>
<?php
if (!empty($folder_name)) {
echo "$folder_name / ";
}
echo $document_name;
?>
</a>
<div class="d-flex align-items-center gap-3">
<?= documentTile() ?>
<div class="min-w-0">
<a class="fw-semibold" href="document.php?id=<?= $document_id ?>"><?= $document_name ?></a>
<div class="small text-body-secondary">
<?php if ($folder_name) { ?><i class="fas fa-folder me-1"></i><?= $folder_name ?><?php } ?>
<?php if ($folder_name && $row['document_description']) { ?> &middot; <?php } ?>
<?= escapeHtml($row['document_description']) ?>
</div>
</div>
</div>
</td>
<td><?= date('M j, Y', strtotime($document_created_at)) ?></td>
<td class="text-nowrap"><?= date('M j, Y', strtotime($document_updated_at)) ?></td>
<td class="text-center">
<a href="document.php?id=<?= $document_id ?>" class="btn btn-sm btn-outline-primary" title="View document">
<i class="fas fa-eye"></i>

View File

@@ -4017,6 +4017,12 @@ img.itflow-contact-avatar {
border-radius: var(--bs-border-radius);
font-size: .8rem;
}
.itflow-file-icon-xs {
width: 1.25rem;
height: 1.25rem;
border-radius: var(--bs-border-radius-sm);
font-size: .65rem;
}
.itflow-file-icon-lg {
width: 3.5rem;
height: 3.5rem;
@@ -4451,3 +4457,9 @@ img.itflow-contact-avatar {
box-shadow: none;
}
}
/* In a quick look's tabs the rows sit flush with the pane, like its other lists */
.itflow-asset-quick-related .itflow-link-row {
margin: 0;
padding-left: 0;
padding-right: 0;
}

View File

@@ -340,7 +340,7 @@ function clientOverviewSharedItems($client_id) {
global $mysqli;
$sql = mysqli_query($mysqli, "SELECT item_id, item_type, item_related_id, item_recipient, item_views, item_view_limit, item_expire_at,
COALESCE(credential_name, document_name, file_name) AS item_name
COALESCE(credential_name, document_name, file_name) AS item_name, file_ext
FROM shared_items
LEFT JOIN credentials ON item_type = 'Credential' AND credential_id = item_related_id AND credential_client_id = $client_id
LEFT JOIN documents ON item_type = 'Document' AND document_id = item_related_id AND document_client_id = $client_id

View File

@@ -271,13 +271,14 @@ function globalSearchGroups($terms, $deep) {
'subtitle' => $row['document_description'],
'context' => $row['client_name'],
'url' => globalSearchClientUrl('document.php', $row['document_client_id'], ['document_id' => intval($row['document_id'])]),
'tile' => ['tone' => 'document', 'icon' => 'file-alt', 'label' => 'Document'],
];
},
];
$groups[] = [
'key' => 'files', 'label' => 'Files', 'icon' => 'paperclip', 'module' => 'module_support',
'select' => 'file_id, file_name, file_description, file_client_id, file_folder_id, client_name, folder_name',
'select' => 'file_id, file_name, file_ext, file_description, file_client_id, file_folder_id, client_name, folder_name',
'from' => 'files
LEFT JOIN clients ON file_client_id = client_id
LEFT JOIN folders ON file_folder_id = folder_id',
@@ -290,7 +291,9 @@ function globalSearchGroups($terms, $deep) {
'title' => $row['file_name'],
'subtitle' => implode(' · ', array_filter([$row['folder_name'], $row['file_description']])),
'context' => $row['client_name'],
'url' => globalSearchClientUrl('files.php', $row['file_client_id'], ['folder_id' => intval($row['file_folder_id'])]),
// Its folder, narrowed to it - one click from its quick look
'url' => globalSearchClientUrl('files.php', $row['file_client_id'], ['folder_id' => intval($row['file_folder_id']), 'q' => $row['file_name']]),
'tile' => ['tone' => fileTypeInfo($row['file_ext'])['tone'], 'icon' => fileTypeInfo($row['file_ext'])['icon'], 'label' => fileTypeInfo($row['file_ext'])['label']],
];
},
];

View File

@@ -36,6 +36,7 @@
const CACHE_SIZE = 50;
const BADGE_VARIANTS = ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'];
const AVATAR_TONES = ['primary', 'success', 'info', 'warning', 'secondary'];
const FILE_TONES = ['pdf', 'word', 'excel', 'slides', 'image', 'media', 'archive', 'text', 'code', 'drawing', 'cert', 'other', 'document'];
const MOD_KEY = /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || '') ? '⌘' : 'Ctrl';
let modalEl = null;
@@ -138,6 +139,18 @@
return node;
}
// A file's type tile, or a document's - fileTypeTile() draws the same server side
function tile(spec) {
if (!spec || FILE_TONES.indexOf(spec.tone) === -1 || !/^[a-z0-9-]+$/.test(spec.icon || '')) {
return null;
}
const node = el('span', 'itflow-file-icon itflow-file-icon-xs itflow-file-tone-' + spec.tone);
node.title = spec.label || '';
node.setAttribute('aria-hidden', 'true');
node.appendChild(el('i', 'fas fa-fw fa-' + spec.icon));
return node;
}
function badge(spec) {
if (!spec || !spec.text) {
return null;
@@ -178,7 +191,7 @@
body.append(sub);
}
link.append(avatar(parts.avatar) || icon(iconName, 'itflow-search-item-icon'), body);
link.append(avatar(parts.avatar) || tile(parts.tile) || icon(iconName, 'itflow-search-item-icon'), body);
const status = badge(parts.badge);
if (status || parts.context) {