This is the final website: KQLSearch.com
You can find the full code here on GitHub: KQL-Search
Overall Architecture of the Web Application:
Motivation for this project
I have long thought about how I could combine these two interests and develop myself. It had to be a project which should also be fun so that I don’t lose any motivation to keep pushing. Then I had the idea to create this website.
This web page searches in real time for KQL queries in three given GitHub repositories.
What have I learned
- Using React to display this data in a UI.
- Using Postman to test API queries and authorization with GitHub.
- Using Vercel to Deploy the Application and assign the domain.
What was my approach?
I am by nature not one to learn with videos or from blogs alone. I learn best with my own projects and the troubleshooting that will come with it. But be careful: It can also become demotivating very quickly if too many things don’t work and you have to search the internet for every error message.
I started working on this web application without any great planning. This had a big disadvantage: The features of the website became more and more during the implementation. Instead of reaching a status quo in time X the project got bigger and bigger until I decided to postpone new features into the future.
So that I don’t forget any ideas, I always had a notepad open in which I also wrote my to-dos. This helped me a lot in organizing my thoughts. I can only recommend such an approach.
The beginning was much easier for me because of the create-react-app function. With that, I already had a working foundation for my project. Now I had to venture to the GitHub API, with which I can display the data from the repositories. For this I used axios. The first time I tried it, the authentication failed. However, I was able to solve this quickly with an .env file. I also used variables in the link to the GitHub API for the extensibility of the web application so that I can use it for other repositories in the future:
It was also important that I could filter the data in the response, because I didn’t need all the files in the GitHub repositories. I was only interested in files with the extensions .kql and .txt. For this I created a filter in a separate file (Filelist.js):
In addition to displaying the file names on the web page, the content of the files should also be displayed. In the first attempt, I had only referred to the GitHub link of the individual files, which I did not find intuitive. To be able to display the content I wrote the following:
To round out the features, I added a search box and a way to filter different categories:
The appearance of the buttons I have adjusted in CSS and added a small animation. In addition, I have adapted the content of the site so that parts such as the footer, the flex box wide to the display size of the user is adapted. Some things I had to hide for clarity if the display was too small. Example:
After I was happy with the web app, it was time to clean up the code. For this I used Prettier. It’s very easy to install as an add-on in VS Code and apply Shift+Alt+F. This helped extremely because the code suddenly became more readable. I now learned to write readable code in the first place, because I didn’t know where anything was anymore and lost a lot of time searching. I didn’t have any time pressure in general, but it annoyed me to waste time on such trifles, which I could have used just as well for a new project.
This code defines a React functional component called
App that fetches a list of files from three different repositories on GitHub and displays them in a list. The component has several state variables:
intuneFiles: an array of files from the “ugurkocde/KQL_Intune” repository.
sentinelFiles: an array of files from the “reprise99/Sentinel-Queries” repository.
otherFiles: an array of files from the “rod-trent/SentinelKQL” repository.
query: a string representing the current search query.
filter: a string representing the current prefix filter applied to the list of files.
The component also has several functions:
handleSearch: a function that updates the
querystate variable with a new search query.
handleFilter: a function that updates the
filterstate variable with a new prefix filter.
The component makes use of the
useEffect hook to perform an initial fetch of the files from the three repositories when the component mounts. The fetched files are stored in the appropriate state variables depending on the repository they come from. The
useEffect hook is passed an empty array as its second argument to ensure that the fetch is only performed once when the component mounts.
The component also makes use of several child components:
Footer. These child components are responsible for rendering different parts of the UI.
App component renders a search bar and a list of files, and it allows the user to filter the list of files by prefix and to search for a specific file by name. When the user submits a search query or selects a prefix filter, the relevant state variables are updated, which triggers a re-render of the component and updates the list of displayed files accordingly.
This code is a functional component in a React application. The component accepts several props:
files: an array of file objects
query: a string representing the current search query
prefix: a string representing the prefix of the file name
filter: a string representing the current filter applied to the files
The component initializes several state variables using the
selectedFile: a file object representing the currently selected file
fileContents: a string containing the contents of the currently selected file
The component defines a
handleFileClick function that is called when a file is clicked. If the clicked file is already the selected file, the function sets
null to close the file. Otherwise, the function makes an API call to retrieve the contents of the file and sets
fileContents to the file and its contents, respectively.
The component then filters the
files array based on the
filter props. If the
filter prop is not equal to “All”, the resulting filtered array will contain only those files with names that include the
query string and end with either the “.kql” or “.txt” extension. If the
filter prop is equal to “All”, the resulting filtered array will contain all files with names that include the
query string. If the
prefix prop is equal to “Other”, the resulting filtered array will contain only those files with names that include the
query string and end with the “.txt” extension.
The component then displays the filtered list of files as a list of list items. Each list item contains the file name and a button that allows the user to copy the file path to the clipboard. When a file is clicked, the
handleFileClick function is called and the file contents are displayed below the list of files.
This code defines a
SearchBar component in a React functional component. The component has two state variables,
filter, which are initialized using the
The component renders a search input field and a dropdown menu for selecting a filter value. The component also defines two event handlers,
handleFilter, which are passed as props to the input field and dropdown menu respectively. These event handlers update the component’s state variables when the input field or dropdown menu are changed by the user.
The component also receives two props,
onFilter, which are functions passed down from the parent component. These functions are called with the updated
filter values as arguments whenever the input field or dropdown menu are changed by the user. This allows the parent component to react to these changes and perform some action, such as updating a list of files being displayed based on the search query or filter value.
Finally, the component returns JSX that renders the search input field and dropdown menu, along with some styling applied to the elements.
What I would like to add in the future
Caching Server / Database:
A possible improvement would be to introduce a database that is filled once a day with the answers from GitHub. Currently, every visit to the website means a new query with the GitHub API. I could avoid that with a database. The frontend would then fetch the data from the database. The use of MongoDB would possibly make sense here.
Thank you for reading and until next time.