Skip to content

Commit 249e3a6

Browse files
Link existing document to KB without page reload (#24365)
1 parent 30a54e5 commit 249e3a6

5 files changed

Lines changed: 73 additions & 10 deletions

File tree

js/modules/Knowbase/ArticleController.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,8 +629,22 @@ export class GlpiKnowbaseArticleController
629629
const badge = this.#container.querySelector(
630630
`[data-glpi-document-assoc-id="${assoc_id}"]`
631631
);
632-
if (badge) {
633-
badge.remove();
632+
const document_id = parseInt(badge.dataset.glpiDocumentId);
633+
badge.remove();
634+
635+
// Make the document available again in the link dropdown
636+
if (this.#document_link_controller) {
637+
// Controller exist, call dedicated method
638+
this.#document_link_controller.removeFromUsed(document_id);
639+
} else {
640+
// Controller has not yet been initialized, modify its dataset
641+
const link_pane = document.getElementById('kb-modal-link-pane');
642+
const used = JSON.parse(link_pane.dataset.glpiKbLinkUsedIds);
643+
const idx = used.indexOf(document_id);
644+
if (idx !== -1) {
645+
used.splice(idx, 1);
646+
link_pane.dataset.glpiKbLinkUsedIds = JSON.stringify(used);
647+
}
634648
}
635649

636650
this.#updateDocumentCount(-1);

js/modules/Knowbase/DocumentLinkController.js

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export class DocumentLinkController
274274
});
275275
const result = await response.json();
276276

277-
this.#onSuccess(result.linked_count);
277+
this.#onSuccess(result.documents ?? []);
278278
} catch (error) {
279279
glpi_toast_error(__('Linking failed'));
280280
throw error;
@@ -284,10 +284,15 @@ export class DocumentLinkController
284284
}
285285

286286
/**
287-
* @param {number} count
287+
* @param {Array<{html: string}>} documents
288288
*/
289-
#onSuccess(count)
289+
#onSuccess(documents)
290290
{
291+
const count = documents.length;
292+
293+
// Persist newly linked IDs so the dropdown stays correct after reset
294+
this.#container.dataset.glpiKbLinkUsedIds = JSON.stringify(this.#usedIds);
295+
291296
if (this.#modal) {
292297
const modalInstance = bootstrap.Modal.getInstance(this.#modal);
293298
if (modalInstance) {
@@ -301,7 +306,10 @@ export class DocumentLinkController
301306
: __('%d documents linked successfully').replace('%d', count)
302307
);
303308

304-
window.location.reload();
309+
this.#container.dispatchEvent(new CustomEvent('documents:uploaded', {
310+
bubbles: true,
311+
detail: { count, documents },
312+
}));
305313
}
306314

307315
/**
@@ -325,6 +333,20 @@ export class DocumentLinkController
325333
}
326334
}
327335

336+
/**
337+
* Remove a document ID from the used list so it reappears in the dropdown.
338+
* Called by ArticleController after a document is unlinked from the article.
339+
* @param {number} documentId
340+
*/
341+
removeFromUsed(documentId)
342+
{
343+
const idx = this.#usedIds.indexOf(documentId);
344+
if (idx !== -1) {
345+
this.#usedIds.splice(idx, 1);
346+
}
347+
this.#container.dataset.glpiKbLinkUsedIds = JSON.stringify(this.#usedIds);
348+
}
349+
328350
#reset()
329351
{
330352
this.#selectedDocuments.clear();

src/Glpi/Controller/AbstractDocumentUploadController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ final protected function createDocuments(
113113

114114
$created[] = [
115115
'assoc_id' => $doc_item->getID(),
116+
'id' => $doc_id,
116117
'filename' => $filename,
117118
'download_url' => $document->getDownloadUrl(),
118119
'extension' => $extension,

src/Glpi/Controller/Knowbase/LinkDocumentController.php

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434

3535
namespace Glpi\Controller\Knowbase;
3636

37+
use Document;
3738
use Document_Item;
39+
use Glpi\Application\View\TemplateRenderer;
3840
use Glpi\Controller\AbstractController;
3941
use Glpi\Controller\CrudControllerTrait;
4042
use Glpi\Exception\Http\AccessDeniedHttpException;
@@ -73,7 +75,8 @@ public function __invoke(int $id, Request $request): JsonResponse
7375
throw new BadRequestHttpException();
7476
}
7577

76-
$linked_count = 0;
78+
$linked = [];
79+
$twig = TemplateRenderer::getInstance();
7780

7881
foreach ($documents_ids as $doc_id) {
7982
$doc_id = (int) $doc_id;
@@ -82,18 +85,40 @@ public function __invoke(int $id, Request $request): JsonResponse
8285
}
8386

8487
try {
85-
$this->add(Document_Item::class, [
88+
$doc_item = $this->add(Document_Item::class, [
8689
'documents_id' => $doc_id,
8790
'itemtype' => KnowbaseItem::class,
8891
'items_id' => $id,
8992
]);
90-
$linked_count++;
9193
} catch (\RuntimeException) {
9294
// Skip documents that fail (duplicates, permission issues, etc.)
9395
continue;
9496
}
97+
98+
$document = new Document();
99+
if (!$document->getFromDB($doc_id)) {
100+
continue;
101+
}
102+
103+
$filename = (string) ($document->fields['filename'] ?? '');
104+
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
105+
$styles = KnowbaseItem::getDocumentIconAndColor($extension);
106+
107+
$linked[] = [
108+
'html' => $twig->render('pages/tools/kb/document_badge.html.twig', [
109+
'doc' => [
110+
'assoc_id' => $doc_item->getID(),
111+
'id' => $doc_id,
112+
'filename' => $filename,
113+
'download_url' => $document->getDownloadUrl(),
114+
'icon_class' => $styles['icon_class'],
115+
'color_class' => $styles['color_class'],
116+
],
117+
'can_edit' => true,
118+
]),
119+
];
95120
}
96121

97-
return new JsonResponse(['linked_count' => $linked_count]);
122+
return new JsonResponse(['documents' => $linked]);
98123
}
99124
}

templates/pages/tools/kb/document_badge.html.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<span
3434
class="kb-item-badge badge bg-light text-dark d-flex align-items-center gap-2"
3535
data-glpi-document-assoc-id="{{ doc.assoc_id }}"
36+
data-glpi-document-id="{{ doc.id }}"
3637
data-testid="document-chip"
3738
>
3839
<a

0 commit comments

Comments
 (0)