From bb48f9e5cfca028eb555b58b0987c7516a54d84f Mon Sep 17 00:00:00 2001
From: Shaun Struwig <41984034+Blargian@users.noreply.github.com>
Date: Mon, 27 Jan 2025 11:25:46 +0100
Subject: [PATCH 01/36] introduce tags functionality to KB search
---
.gitignore | 1 +
docusaurus.config.js | 1 +
package.json | 5 +-
plugins/custom-loaders/index.js | 28 +
plugins/custom-loaders/package.json | 5 +
.../KBArticleSearch/KBArticleSearch.js | 59 +-
src/hooks/fetchKnowledgebaseArticles.js | 27 +
src/theme/BlogSidebar/Desktop/index.js | 49 +-
static/kb_toc.json | 1277 +++++++++++++++++
9 files changed, 1441 insertions(+), 11 deletions(-)
create mode 100644 plugins/custom-loaders/index.js
create mode 100644 plugins/custom-loaders/package.json
create mode 100644 src/hooks/fetchKnowledgebaseArticles.js
create mode 100644 static/kb_toc.json
diff --git a/.gitignore b/.gitignore
index 588d210235f..8833ba509e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ clickhouse-docs.code-workspace
yarn.lock
yarn.error-log
.comments
+yarn-error.log
# Output files used by scripts to verify links
sidebar_links.txt
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 4a563897802..fdfce20de5a 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -311,6 +311,7 @@ const config = {
}),
plugins: [
+ 'custom-loaders',
'docusaurus-plugin-sass',
function (context, options) {
return {
diff --git a/package.json b/package.json
index a41824371a6..647a85cf9a6 100644
--- a/package.json
+++ b/package.json
@@ -28,8 +28,10 @@
"@docusaurus/theme-mermaid": "3.7.0",
"@mdx-js/react": "^3.1.0",
"@radix-ui/react-navigation-menu": "^1.2.3",
+ "@yaireo/tagify": "^4.33.2",
"axios": "^1.7.9",
"clsx": "^2.1.0",
+ "custom-loaders": "file:plugins/custom-loaders",
"docusaurus-plugin-sass": "^0.2.6",
"esbuild": "^0.20.1",
"esbuild-loader": "^4.0.3",
@@ -45,7 +47,8 @@
"remark-docusaurus-tabs": "^0.2.0",
"remark-link-rewrite": "^1.0.7",
"remark-math": "^6.0.0",
- "sass": "^1.83.1"
+ "sass": "^1.83.1",
+ "custom-loaders": "file:plugins/custom-loaders"
},
"devDependencies": {
"@argos-ci/cli": "^2.5.3",
diff --git a/plugins/custom-loaders/index.js b/plugins/custom-loaders/index.js
new file mode 100644
index 00000000000..4949c65e8e7
--- /dev/null
+++ b/plugins/custom-loaders/index.js
@@ -0,0 +1,28 @@
+module.exports = function (context, options) {
+ return {
+ name: 'custom-loaders',
+ configureWebpack(config, isServer) {
+ return {
+ module: {
+ rules: [
+ {
+ test: /\.jsx$/,
+ // Exclude node_modules to avoid conflicts
+ exclude: /node_modules\/(?!(@yaireo\/tagify)\/)/,
+ use: {
+ loader: 'babel-loader',
+ options: {
+ "presets": [
+ ["@babel/preset-react", {
+ "runtime": "automatic"
+ }]
+ ]
+ },
+ },
+ },
+ ],
+ },
+ };
+ },
+ };
+};
\ No newline at end of file
diff --git a/plugins/custom-loaders/package.json b/plugins/custom-loaders/package.json
new file mode 100644
index 00000000000..1f9b4954bfc
--- /dev/null
+++ b/plugins/custom-loaders/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "custom-loaders",
+ "version": "0.0.0",
+ "private": true
+}
\ No newline at end of file
diff --git a/src/components/KBArticleSearch/KBArticleSearch.js b/src/components/KBArticleSearch/KBArticleSearch.js
index 2892b83933a..6d33ce1aaaf 100644
--- a/src/components/KBArticleSearch/KBArticleSearch.js
+++ b/src/components/KBArticleSearch/KBArticleSearch.js
@@ -1,17 +1,55 @@
import React from 'react';
import styles from './styles.module.css'
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
-import {useState, useEffect} from "react";
+import {useState, useCallback, useEffect} from "react";
+import Tags, {MixedTags} from '@yaireo/tagify/react' // React-wrapper file
+import '@yaireo/tagify/dist/tagify.css'
+import {tags} from "../../../static/js/docsearch"; // Tagify CSS
+import {useBlogPost} from "@docusaurus/theme-common";
-const KBArticleSearch = ({kb_articles, onUpdateResults}) => {
+const KBArticleSearch = ({kb_articles, onUpdateResults, allowed_tags, kb_articles_and_tags}) => {
const [searchTerm, setSearchTerm] = useState('');
+ const [searchTags, setSearchTags] = useState([]);
+
+ // Settings for Tagify
+ const settings = {
+ maxTags: 3,
+ dropdown: {
+ enabled: 0,
+ position: "input"
+ },
+ whitelist: allowed_tags.map((value, index) => ({
+ id: index+1,
+ value: value
+ }))
+ };
+
+ const articleTagsFromTitle = (title, kb_articles_and_tags) => {
+ const match = kb_articles_and_tags.find(article => article.title === title)
+ return match ? match.tags : null;
+ }
+
const handleSearch = (event) => {
setSearchTerm(event.target.value);
};
+ const handleTags = (event) => {
+ let tags_raw = []
+ let tags_cleaned = []
+ if (event.detail.value !== '')
+ {
+ tags_raw = JSON.parse(event.detail.value)
+ tags_cleaned = tags_raw.map((tag)=>tag.value)
+ }
+ setSearchTags(tags_cleaned)
+ }
+
const filteredArticles = searchTerm ? kb_articles.filter((article) =>
- searchTerm && article.title.match(new RegExp(searchTerm, 'i')) // Case-insensitive search
+ {
+ const tags = articleTagsFromTitle(article.title, kb_articles_and_tags)
+ return searchTerm && article.title.match(new RegExp(searchTerm, 'i'))
+ } // Case-insensitive search
) : kb_articles;
useEffect(() => {
@@ -19,12 +57,13 @@ const KBArticleSearch = ({kb_articles, onUpdateResults}) => {
}, [filteredArticles, onUpdateResults]); // Update on filter changes
return (
+
+)
}
export default KBArticleSearch;
\ No newline at end of file
diff --git a/src/hooks/fetchKnowledgebaseArticles.js b/src/hooks/fetchKnowledgebaseArticles.js
new file mode 100644
index 00000000000..525b54c65cc
--- /dev/null
+++ b/src/hooks/fetchKnowledgebaseArticles.js
@@ -0,0 +1,27 @@
+import { useState, useEffect } from 'react';
+
+export const useFetchKnowledgebaseArticles = (filepath) => {
+
+ const [articlesWithTags, setArticles] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ const fetchArticles = async () => {
+ try {
+ const response = await fetch(filepath);
+ const jsonData = await response.json();
+ setArticles(jsonData);
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setIsLoading(false);
+ }
+ }
+ fetchArticles();
+ }, [filepath]) // re-fetch the articles only if the URL changes (intended to be used once)
+
+ return {articlesWithTags, isLoading, error}
+}
+
+export default useFetchKnowledgebaseArticles;
\ No newline at end of file
diff --git a/src/theme/BlogSidebar/Desktop/index.js b/src/theme/BlogSidebar/Desktop/index.js
index 375aa37ea9f..7da01c678ff 100644
--- a/src/theme/BlogSidebar/Desktop/index.js
+++ b/src/theme/BlogSidebar/Desktop/index.js
@@ -7,15 +7,51 @@ import SearchBar from "../../SearchBar";
import KBArticleSearch from "../../../components/KBArticleSearch/KBArticleSearch";
import {DocSearchButton} from "@docsearch/react";
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
-import {useState} from "react";
+import {useCallback, useRef, useState} from "react";
+import {useFetchKnowledgebaseArticles} from "../../../hooks/fetchKnowledgebaseArticles";
+const allowed_tags = [
+ 'Concepts',
+ 'Migrations',
+ 'Use Cases',
+ 'Best Practices',
+ 'Managing Cloud',
+ 'Security and Authentication',
+ 'Cloud Migration',
+ 'Core Data Concepts',
+ 'Managing Data',
+ 'Updating Data',
+ 'Data Modelling',
+ 'Deleting Data',
+ 'Performance and Optimizations',
+ 'Server Admin',
+ 'Deployments and Scaling',
+ 'Settings',
+ 'Tools and Utilities',
+ 'System Tables',
+ 'Functions',
+ 'Engines',
+ 'Language Clients',
+ 'ClickPipes',
+ 'Native Clients and Interfaces',
+ 'Data Sources',
+ 'Data Visualization',
+ 'Data Formats',
+ 'Data Ingestion',
+ 'Data Export',
+ 'chDB',
+ 'Errors and Exceptions',
+ 'Community',
+]
export default function BlogSidebarDesktop({sidebar}) {
- const { siteConfig } = useDocusaurusContext();
+ const { siteConfig } = useDocusaurusContext();
+ const { articlesWithTags, isLoading, error} = useFetchKnowledgebaseArticles('./kb_toc.json'); // stored in /static
const [filteredArticles, setFilteredArticles] = useState(sidebar.items);
const updateResults = (filteredArticlesFromSearch) => {
setFilteredArticles(filteredArticlesFromSearch);
}
+
return (