Skip to content

Commit

Permalink
Merge pull request #50 from JamesHabben/heap
Browse files Browse the repository at this point in the history
Heap Analytics
  • Loading branch information
JamesHabben authored Nov 10, 2023
2 parents 88fbd6f + 5eaf088 commit afeae47
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 29 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REACT_APP_HEAP_ID=123_replace_456
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
# misc
.DS_Store
.env.local
.env.development
.env.development.local
.env.test.local
.env.production
.env.production.local

npm-debug.log*
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"antd": "^5.9.4",
"fast-json-patch": "^3.1.1",
"js-base64": "^3.7.5",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^9.0.0",
Expand Down
2 changes: 1 addition & 1 deletion public/version-build.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"buildDate": "2023-11-02"
"buildDate": "2023-11-09"
}
35 changes: 33 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,43 @@ import { AuthProvider } from './AuthContext';

import './App.css';

/* global heap */

function App() {
const [showScroll, setShowScroll] = useState(false);

const loadHeap = (heapId) => {
window.heap = window.heap || [];
window.heap.load = function (e, t) {
window.heap.appid = e;
window.heap.config = t = t || {};
const r = document.createElement("script");
r.type = "text/javascript";
r.async = true;
r.src = `https://cdn.heapanalytics.com/js/heap-${e}.js`;
const a = document.getElementsByTagName("script")[0];
a.parentNode.insertBefore(r, a);
for (const o of ["addEventProperties", "addUserProperties", "clearEventProperties", "identify", "resetIdentity", "removeEventProperty", "setEventProperties", "track", "unsetEventProperty"]) {
window.heap[o] = (...args) => {
window.heap.push([o].concat(args));
};
}
};
window.heap.load(heapId);
};

useEffect(() => {
if (process.env.NODE_ENV === 'development') {
document.title = document.title + ' (Dev Mode)';
const heapId = process.env.NODE_ENV === 'development'
? process.env.REACT_APP_HEAP_ID
: process.env.REACT_APP_HEAP_ID;

if (document.title && process.env.NODE_ENV === 'development') {
document.title += ' (Dev Mode)';
}

if (heapId) {
console.log('Heap ID:', heapId);
loadHeap(heapId);
}
}, []);

Expand Down
5 changes: 5 additions & 0 deletions src/components/AppDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ function AppDetails({ app, tools }) {
const [artifacts, setArtifacts] = useState([]);
const toolRefs = ({});



useEffect(() => {
//console.log("Tools in AppDetails:", tools);
window.heap.track('App View', { appName: app.appName })

if (tools && apps && tools.length > 0) {
//console.log("Fetching artifacts for app:", app.appName, "with tools:", tools);
Expand All @@ -43,6 +46,7 @@ function AppDetails({ app, tools }) {

const handleIconClick = (toolShortName) => {
//console.log(toolRefs)
window.heap.track('App Tool Jump', { toolName: toolShortName })
const ref = toolRefs.current[toolShortName];
if (ref && ref.current) {
ref.current.scrollIntoView({ behavior: 'smooth' });
Expand Down Expand Up @@ -77,6 +81,7 @@ function AppDetails({ app, tools }) {

return (
<div className='AppDetails'>
{}
<div className='appIcon'>
<img className='appIcon'
src={app.icon ? `/app-icons/${app.icon}` : '/logo192.png'}
Expand Down
77 changes: 64 additions & 13 deletions src/components/PageSearch.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useMemo, useRef, useContext } from 'react';
import { Input, Card, Row, Col, Modal, AutoComplete } from 'antd';
import { CloseCircleOutlined } from '@ant-design/icons';
import React, { useState, useEffect, useMemo, useRef, useContext, useCallback } from 'react';
import { Input, Card, Row, Col, Modal, AutoComplete, } from 'antd';
import { CloseCircleOutlined, LoadingOutlined } from '@ant-design/icons';
import { debounce } from 'lodash';

//import { useDataFetching } from 'services/useDataFetching';
import { DataContext } from 'services/DataContext';
Expand Down Expand Up @@ -63,9 +64,6 @@ function PageSearch() {
}
}

useEffect(() => {
setSuggestionValues();
}, [searchTerm, apps]);

function parseSearchTerms(term) {
const result = {
Expand Down Expand Up @@ -102,9 +100,42 @@ function PageSearch() {
return result;
}

const [filteredApps, setFilteredApps] = useState([]);
const [isFiltering, setIsFiltering] = useState(false); // New state to track if we are currently filtering
const debouncedFilterAppsRef = useRef();

const filteredApps = useMemo(() => {
if (!searchTerm) return [];
useEffect(() => {
debouncedFilterAppsRef.current = debounce((search) => {
const { operator, property, value } = parseSearchTerms(search);

const filtered = apps.filter(app => {
// Initial filter based on '-no:' operator
let matchesOperator = true;
if (operator === '-no:' && property) {
matchesOperator = !app[property]; // Check if the property value is falsy
}

// Further filter the reduced set based on the search term
if (matchesOperator && value) {
const lowerValue = value.toLowerCase();
return (
app.appName.toLowerCase().includes(lowerValue) ||
(app.alternateNames && app.alternateNames.some(name => name.toLowerCase().includes(lowerValue)))
);
}

return matchesOperator; // If there's no value, return the result of the operator check
});

setFilteredApps(filtered);
setIsFiltering(false); // Set filtering to false once done
window.heap.track('Search', { searchTerm: value }); // Track the search term with Heap here
}, 300);
}, [apps]);

// const filteredApps = useMemo(() => {
const filteredAppsold = () => {
if (!searchTerm) return [];

const { operator, property, value } = parseSearchTerms(searchTerm);

Expand All @@ -126,7 +157,7 @@ function PageSearch() {

return matchesOperator; // If there's no value, return the result of the operator check
});
}, [searchTerm, apps]);
}; // () [searchTerm, apps];



Expand All @@ -140,6 +171,18 @@ function PageSearch() {
onClick={clearSearch}
/>
);

useEffect(() => {
setSuggestionValues();
if (searchTerm) {
setIsFiltering(true);
debouncedFilterAppsRef.current(searchTerm);
} else {
setIsFiltering(false);
setFilteredApps([]);
}
}, [searchTerm, debouncedFilterAppsRef]);


return (
<div style={{ padding: '5vh 1rem' }}>
Expand Down Expand Up @@ -168,10 +211,18 @@ function PageSearch() {
/>
</AutoComplete>
<div className='searchCount'>
{searchTerm
? `${filteredApps.length} matching apps`
: `${apps.length} apps and ${tools.length} forensic tools in the database. You can `}
{!searchTerm && <a href="https://github.com/JamesHabben/4n6-app-finder" target="_blank" rel="noopener noreferrer">contribute</a>}!
{isFiltering ? (
<span>
<LoadingOutlined /> Searching...
</span>
) : searchTerm ? (
`${filteredApps.length} matching apps`
) : (
<span>
{`${apps.length} apps and ${tools.length} forensic tools in the database. You can `}
<a href="https://github.com/JamesHabben/4n6-app-finder" target="_blank" rel="noopener noreferrer">contribute</a>!
</span>
)}
</div>
{!searchTerm && (
<>
Expand Down
12 changes: 10 additions & 2 deletions src/components/searchCompnents/RecentAppsCard.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React, { useMemo, useCallback } from 'react';
import { Card, Row, Col } from 'antd';

import AppTile from 'components/searchCompnents/AppTile';
Expand All @@ -16,13 +16,21 @@ function RecentAppsCard({ apps, tools, onAppClick }) {
return sortedApps.slice(0, 6); // Get the six most recent apps
}, [sortedApps]);

const handleTileClick = useCallback((app) => {
window.heap.track('Recent App Clicked', { appName: app.name });

if (onAppClick) {
onAppClick(app);
}
}, [onAppClick]);

return (
<div>
<h2>Recent App Updates</h2>
<Row gutter={[16, 16]} justify={'center'}>
{recentApps.map((app, index) => (
<Col key={index} xs={24} sm={12} md={8} lg={6} xl={4}>
<AppTile app={app} tools={tools} onClick={onAppClick} />
<AppTile app={app} tools={tools} onClick={() => handleTileClick(app)} />
</Col>
))}
</Row>
Expand Down
1 change: 1 addition & 0 deletions src/components/searchCompnents/WhatsNewTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function WhatsNewTile() {
}, []);

const showModal = () => {
window.heap.track('Whats New More', { })
setIsModalVisible(true);
};

Expand Down
22 changes: 11 additions & 11 deletions src/services/githubService.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ export const githubService = (token, username) => {
});
terminal(prevOutput => [...prevOutput, `Blob created: ${blobSha}`]);

terminal(prevOutput => [...prevOutput, 'Fetching latest commit SHA from events...']);
// terminal(prevOutput => [...prevOutput, 'Fetching latest commit SHA from events...']);
// const { data: { object: { sha: latestCommitSha } } } = await octokit.git.getRef({
// owner: username,
// repo: repo,
Expand Down Expand Up @@ -366,16 +366,16 @@ export const githubService = (token, username) => {
latestCommitSha = latestCommitCache.sha; // Use cached SHA if it's within the last minute
terminal(prevOutput => [...prevOutput, `Using session last commit SHA: ${latestCommitSha}`]);
} else {
try {
const response = await octokit.activity.listRepoEvents({
owner: username,
repo: repo,
per_page: 1
});
latestCommitSha = response.data[0]?.payload?.head; // Assuming the latest event is a push event
} catch (error) {
terminal(prevOutput => [...prevOutput, `Error fetching latest commit SHA from Events API: ${error.message}`]);
}
// try {
// const response = await octokit.activity.listRepoEvents({
// owner: username,
// repo: repo,
// per_page: 1
// });
// latestCommitSha = response.data[0]?.payload?.head; // Assuming the latest event is a push event
// } catch (error) {
// terminal(prevOutput => [...prevOutput, `Error fetching latest commit SHA from Events API: ${error.message}`]);
// }


if (!latestCommitSha) {
Expand Down

0 comments on commit afeae47

Please sign in to comment.