PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.5
4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 All 203 releases
betterdocs / react-src / admin / dashboard / components / AllDocsListTable.js

AllDocsListTable.js in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.5, at react-src/admin/dashboard/components/AllDocsListTable.js

358 lines 21.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { useState, useRef, useEffect } from "react";
2 import { decodeEntities } from "@wordpress/html-entities";
3 import {
4 IconSort,
5 IconSmilingFace,
6 IconNeutralFace,
7 IconDisappointedFace
8 } from "../../../icons/index";
9 import { __ } from "@wordpress/i18n";
10 import DocAuthor from "./DocAuthor.js";
11 import DocCategory from "./DocCategory.js";
12 import DocTags from "./DocTags.js";
13 import Pagination from "../../doc-categories/components/Pagination";
14 import NoDocsBody from "./NoDocsBody.js";
15 import ContextMenu from "./ContextMenu.js";
16 import { gutenbergEditScreenUrl } from "../helpers/Helpers";
17 import { useDashboardContext } from "../DashboardContext.js";
18 import ListLoader from "../loaders/ListLoader.js";
19 import KnowledgeBase from "./KnowledgeBase.js";
20 import NoDocsFound from "./NoDocsFound.js";
21
22 import { applyFilters } from "@wordpress/hooks";
23
24 const AllDocsListTable = ({ restoreIDS, setLoaderIDS, setLoading, status, onFilterSelect, docs, isLoading, totalItems, totalPages, setCurrentPage, currentPage, perPage = 20, bulkData, setBulkData, loaderIDS }) => {
25 const { data: quickEdit, setData: setQuickEdit } = useDashboardContext();
26 return (
27 <>
28 <table className="betterdocs-dashboard-list-table">
29 <thead>
30 <tr>
31 <th className="title">
32 <span className="betterdocs-dashboard-custom-checkbox">
33 <input id="check-all" type="checkbox" readOnly checked={bulkData?.length > 0 && !isLoading ? true : false} onClick={(e) => {
34 if( bulkData?.length == 0 ) {
35 docs?.map((doc) => {
36 if( ! bulkData?.includes(doc?.id) ) {
37 bulkData?.push(doc?.id);
38 }
39 })
40 setBulkData([...bulkData]);
41 } else {
42 setBulkData([]);
43 }
44 }}></input>
45 <label htmlFor="check-all"></label>
46 </span>
47 <span className="betterdocs-dashboard-list-header-title">
48 <button
49 onClick={() => {
50 onFilterSelect((state) => {
51 if( state == undefined ){
52 let state = {};
53 state['order'] = 'asc';
54 state['orderby'] = 'title';
55 } else {
56 state['order'] = state['order'] == 'asc' ? 'desc' :'asc';
57 state['orderby'] = 'title';
58 }
59 return {...state};
60 });
61 }}
62 >
63 {__("Title", "betterdocs")}
64 <span className="betterdocs-dashboard-list-header-icon">
65 <IconSort />
66 </span>
67 </button>
68 </span>
69 </th>
70 <th className="author">
71 <span className="betterdocs-dashboard-list-header-title">
72 {__("Author", "betterdocs")}
73 </span>
74 </th>
75 {betterdocs_admin?.multiple_kb == 1 && applyFilters('mkb_table_header', '')}
76 <th className="doc-category">
77 <span className="betterdocs-dashboard-list-header-title">
78 {__("Doc Category", "betterdocs")}
79 </span>
80 </th>
81 <th className="doc-tag">
82 <span className="betterdocs-dashboard-list-header-title">
83 {__("Doc Tag", "betterdocs")}
84 </span>
85 </th>
86 <th className="views">
87 <span className="betterdocs-dashboard-list-header-title">
88 {__("Views", "betterdocs")}
89 </span>
90 </th>
91 <th className="reaction">
92 <span className="betterdocs-dashboard-list-header-title">
93 {__("Reaction", "betterdocs")}
94 </span>
95 </th>
96 <th className="date">
97 <span className="betterdocs-dashboard-list-header-title">
98 <button
99 onClick={() => {
100 onFilterSelect((state) => {
101 if( state == undefined ){
102 let state = {};
103 state['order'] = 'asc';
104 state['orderby'] = 'date';
105 } else {
106 state['order'] = state['order'] == 'asc' ? 'desc' :'asc';
107 state['orderby'] = 'date';
108 }
109 return {...state};
110 });
111 }}
112 >
113 {__("Date", "betterdocs")}
114 <span className="betterdocs-dashboard-list-header-icon">
115 <IconSort />
116 </span>
117 </button>
118 </span>
119 </th>
120 <th className="action">
121 <span className="betterdocs-dashboard-list-header-title">
122 {__("Action", "betterdocs")}
123 </span>
124 </th>
125 </tr>
126 </thead>
127 <tbody>
128 {!isLoading && docs?.length > 0 &&
129 docs.map((doc, index) => {
130 let authorInfo = doc?.author_info;
131 let docCategoryInfo = doc?.doc_category_info;
132 let doctagInfo = doc?.doc_tag_info;
133 let wordCount = doc?.word_count;
134 let status = doc?.status;
135 let totalViews = doc?.total_views ?? 0;
136 let dateString = new Date(doc.date).toLocaleDateString();
137 let reactions = doc?.reactions;
138 let happy = reactions?.happy == null ? 0 : parseInt(reactions?.happy);
139 let sad = reactions?.sad == null ? 0 : parseInt(reactions?.sad);
140 let normal = reactions?.normal == null ? 0 : parseInt(reactions?.normal);
141 let total_reaction = ( happy + sad + normal );
142 let max_reaction = ( happy > sad && happy > normal ) ? 'happy' : ( ( sad > happy && sad > normal ) ? 'sad' : ( ( normal > sad && normal > happy ) ? 'normal' : ( ( happy == sad || happy == normal ) ? 'happy' : ( ( normal == sad || normal == happy ) ? 'normal' : ( ( sad == normal || sad == happy ) ? 'sad' : 'all-equal' ) ) ) ) );
143 let knowledgebaseInfo = doc?.knowledge_base_info;
144
145 return <tr
146 className={
147 ( doc.id === quickEdit.docId && quickEdit?.isOpen )
148 ? "quickEdit-open"
149 : ""
150 }
151 key={index}
152 onClick={(e) => {
153 // handleTRClick(doc, quickEdit);
154 if( quickEdit?.isListMenuOpen ) {
155 setQuickEdit((state) => ({...state, isListMenuOpen:false, docId: doc.id }));
156 }
157 }}
158 >
159 <td>
160 <span className="betterdocs-dashboard-list-item-title-wrap">
161 <span className="betterdocs-dashboard-custom-checkbox">
162 <input
163 id={`dashboard-list-item-${doc.id}`}
164 type="checkbox"
165 checked={bulkData?.includes(doc?.id) ? true : false}
166 onClick={(e) => {
167 if( ! bulkData?.includes(doc?.id) ) {
168 bulkData?.push(doc?.id);
169 setBulkData([...bulkData]);
170 } else {
171 let filteredData = bulkData?.filter((docID) => {
172 return docID != doc?.id;
173 });
174 setBulkData([...filteredData]);
175 }
176 }}
177 readOnly
178 ></input>
179 <label
180 htmlFor={`dashboard-list-item-${doc.id}`}
181 ></label>
182 </span>
183 <span className="betterdocs-dashboard-list-item-title">
184 <a target="_blank" href={gutenbergEditScreenUrl(doc?.id)}>
185 {(doc.title?.rendered == null || doc?.title?.rendered == undefined || doc?.title?.rendered?.length == 0 ) ? '(no title) ' : decodeEntities(doc.title.rendered)}
186 </a>
187 {status != 'publish' && <span className="status">
188 {`- ${status?.charAt(0).toUpperCase()}${status?.slice(1)}`}
189 </span>}
190 <span className="word-count">
191 | {wordCount}&nbsp;
192 <span className="word-count-tooltip">{__("Word Count", "betterdocs")}</span>
193 </span>
194 </span>
195 </span>
196 </td>
197 <td>
198 <DocAuthor authorInfo={authorInfo} />
199 </td>
200 {betterdocs_admin?.multiple_kb == 1 && applyFilters('mkb_table_data', '', [KnowledgeBase, knowledgebaseInfo])}
201 <td>
202 <DocCategory categories={docCategoryInfo} />
203 </td>
204 <td>
205 <DocTags tags={doctagInfo} />
206 </td>
207 <td>
208 <span className="betterdocs-dashboard-list-item-views">
209 <span>{totalViews}</span>
210 </span>
211 </td>
212 <td>
213 <span className="betterdocs-dashboard-list-item-views">
214 <span className="betterdocs-reactions">
215 <span className="betterdocs-all-reactions">
216 {max_reaction == 'happy' && <IconSmilingFace/>}
217 {max_reaction == 'normal' && <IconNeutralFace/>}
218 {max_reaction == 'sad' && <IconDisappointedFace />}
219 {max_reaction == 'all-equal' && <>
220 <IconSmilingFace />
221 </>}
222 </span>
223 <span>{total_reaction}</span>
224 <ul className="betterdocs-reactions-tooltip">
225 {max_reaction == 'happy' &&
226 <>
227 <li>
228 <IconSmilingFace />
229 <span>{happy}</span>
230 </li>
231 <li>
232 <IconNeutralFace />
233 <span>
234 {normal}
235 </span>
236 </li>
237 <li>
238 <IconDisappointedFace />
239 <span>
240 {sad}
241 </span>
242 </li>
243 </>
244 }
245 {max_reaction == 'normal' &&
246 <>
247 <li>
248 <IconSmilingFace />
249 <span>{happy}</span>
250 </li>
251 <li>
252 <IconNeutralFace />
253 <span>
254 {normal}
255 </span>
256 </li>
257 <li>
258 <IconDisappointedFace />
259 <span>
260 {sad}
261 </span>
262 </li>
263 </>
264 }
265 {max_reaction == 'sad' &&
266 <>
267 <li>
268 <IconSmilingFace />
269 <span>{happy}</span>
270 </li>
271 <li>
272 <IconNeutralFace />
273 <span>
274 {normal}
275 </span>
276 </li>
277 <li>
278 <IconDisappointedFace />
279 <span>
280 {sad}
281 </span>
282 </li>
283 </>
284 }
285 {max_reaction == 'all-equal' &&
286 <>
287 <li>
288 <IconSmilingFace />
289 <span>{happy}</span>
290 </li>
291 <li>
292 <IconNeutralFace />
293 <span>{normal}</span>
294 </li>
295 <li>
296 <IconDisappointedFace />
297 <span>{sad}</span>
298 </li>
299 </>
300 }
301 </ul>
302 </span>
303 </span>
304 </td>
305 <td>
306 <span className="betterdocs-dashboard-list-item-date">
307 <span>
308 {dateString}
309 </span>
310 </span>
311 </td>
312 <td>
313 <ContextMenu key={doc.id} doc={doc} status={status}/>
314 </td>
315 {loaderIDS.includes(doc?.id) && <div className="delete-row"></div>}
316 {restoreIDS.includes(doc?.id) && <div className="restore-row"></div>}
317 </tr>
318 })}
319 {isLoading && <ListLoader/>}
320 {docs?.length === 0 && !isLoading && (
321 <tr className="no-docs-found">
322 <td colSpan="100%">
323 <NoDocsFound />
324 </td>
325 </tr>
326 )}
327 </tbody>
328 </table>
329 {/* Pagination — shared custom bd-dc-pagination component (no rc-pagination). */}
330 <Pagination
331 total={Number(totalItems)}
332 page={currentPage}
333 perPage={perPage}
334 onPageChange={(pageNumber) => {
335 if (bulkData?.length > 0) {
336 setBulkData([]);
337 }
338 setLoading(true);
339 setCurrentPage((prevState) => {
340 return { ...prevState, page: pageNumber };
341 });
342 }}
343 onPerPageChange={(newPerPage) => {
344 if (bulkData?.length > 0) {
345 setBulkData([]);
346 }
347 setLoading(true);
348 setCurrentPage((prevState) => {
349 return { ...prevState, per_page: newPerPage };
350 });
351 }}
352 />
353 </>
354 );
355 };
356
357 export default AllDocsListTable;
358