From 1d691d1f4b4b457349660e2936cb9f25a65656b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Mon, 4 Nov 2024 15:28:01 +0100 Subject: [PATCH 1/9] Draft: feat: show match context #396 --- src/mqueryfront/src/App.css | 17 ++++ .../src/components/ActionShowMatchContext.js | 78 +++++++++++++++++++ src/mqueryfront/src/query/QueryMatchesItem.js | 20 ++++- 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/mqueryfront/src/components/ActionShowMatchContext.js diff --git a/src/mqueryfront/src/App.css b/src/mqueryfront/src/App.css index 1d67e328..361a8bc4 100644 --- a/src/mqueryfront/src/App.css +++ b/src/mqueryfront/src/App.css @@ -87,3 +87,20 @@ .cursor-pointer { cursor: pointer; } + +.modal-container { + position: fixed; + display: flex; + justify-content: center; + align-items: center; +} + +.modal-block { + position: relative; +} + +.modal-table { + max-height: 40vh; + max-width: 50vw; + overflow: scroll; +} diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js new file mode 100644 index 00000000..3b2953eb --- /dev/null +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -0,0 +1,78 @@ +import React, { useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faLightbulb } from "@fortawesome/free-solid-svg-icons"; + +const ActionShowMatchContext = (props) => { + const [showModal, setShowModal] = useState(false); + + const modalHeader = ( +
+
Match context
+ +
+ ); + + const tableRows = Object.entries(props.context).map( + (contextItem, index) => ( + + + + {contextItem[0]} + + + {contextItem[1]} + + ) + ); + + const modalBody = ( +
+ {!props.context ? ( + "No context available" + ) : ( + + {tableRows} +
+ )} +
+ ); + + return ( + <> + +
+
+
+
+ {modalHeader} + {modalBody} +
+
+
+
+ + ); +}; + +export default ActionShowMatchContext; diff --git a/src/mqueryfront/src/query/QueryMatchesItem.js b/src/mqueryfront/src/query/QueryMatchesItem.js index 1cbf4525..1f03ed37 100644 --- a/src/mqueryfront/src/query/QueryMatchesItem.js +++ b/src/mqueryfront/src/query/QueryMatchesItem.js @@ -2,10 +2,22 @@ import React from "react"; import path from "path-browserify"; import ActionDownload from "../components/ActionDownload"; import ActionCopyToClipboard from "../components/ActionCopyToClipboard"; +import ActionShowMatchContext from "../components/ActionShowMatchContext"; const QueryMatchesItem = (props) => { const { match, download_url } = props; - const { matches, meta, file } = match; + const { matches, meta, file, context } = match; // NOTE: presuming new field in Match schema context which would be dict with 'matches' as keys + + const stubContext = context + ? context + : { + key1: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + key2: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + key3: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + }; const fileBasename = path.basename(file); @@ -68,6 +80,12 @@ const QueryMatchesItem = (props) => { tooltipMessage="Copy file name to clipboard" /> + + + {matchBadges} {metadataBadges} From 7853efce22e105d78448d51b38b75b89e38020c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Tue, 3 Dec 2024 15:53:51 +0100 Subject: [PATCH 2/9] fix: multiple modals are now properly indexed and draggable --- src/mqueryfront/package.json | 1 + src/mqueryfront/src/App.css | 16 +++-- .../src/components/ActionShowMatchContext.js | 69 +++++++++++++------ src/mqueryfront/yarn.lock | 13 ++++ 4 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/mqueryfront/package.json b/src/mqueryfront/package.json index 804e0bb8..49097e4a 100644 --- a/src/mqueryfront/package.json +++ b/src/mqueryfront/package.json @@ -23,6 +23,7 @@ "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", + "react-draggable": "^4.4.6", "react-router-dom": "^6.26.2", "react-select": "^5.8.1", "replace-js-pagination": "^1.0.5", diff --git a/src/mqueryfront/src/App.css b/src/mqueryfront/src/App.css index 361a8bc4..377d9dd0 100644 --- a/src/mqueryfront/src/App.css +++ b/src/mqueryfront/src/App.css @@ -90,17 +90,21 @@ .modal-container { position: fixed; - display: flex; - justify-content: center; - align-items: center; + z-index: auto; + max-width: 50vw; +} + +.modal-dialog { + margin: 0; } .modal-block { position: relative; + block-size: "fit-content"; + position: "center"; } .modal-table { - max-height: 40vh; - max-width: 50vw; - overflow: scroll; + overflow-y: scroll; + max-height: 50vh; } diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index 3b2953eb..8c257542 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -1,13 +1,38 @@ -import React, { useState } from "react"; +import React, { useState, useRef, useEffect } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faLightbulb } from "@fortawesome/free-solid-svg-icons"; +import Draggable from "react-draggable"; + +const useClickOutside = (ref, callback) => { + const handleClick = (event) => { + if (ref.current && !ref.current.contains(event.target)) { + // lose focus (higher z-index) only if other modal was clicked + const modals = document.querySelectorAll(".modal"); + const wasClicked = (modal) => modal.contains(event.target); + if (Array.from(modals).some(wasClicked)) { + callback(); + } + } + }; + + useEffect(() => { + document.addEventListener("click", handleClick); + + return () => { + document.removeEventListener("click", handleClick); + }; + }); +}; const ActionShowMatchContext = (props) => { + const ref = useRef(null); const [showModal, setShowModal] = useState(false); + const [focus, setFocus] = useState(true); + useClickOutside(ref, () => setFocus(false)); const modalHeader = (
-
Match context
+
{`Match context for ${props.filename}`}
-
-
-
-
- {modalHeader} - {modalBody} + {showModal && ( + +
setFocus(true)} + > +
+
+
+ {modalHeader} + {modalBody} +
+
-
-
- + + )} +
); }; diff --git a/src/mqueryfront/yarn.lock b/src/mqueryfront/yarn.lock index 51cf021b..9462f3ea 100644 --- a/src/mqueryfront/yarn.lock +++ b/src/mqueryfront/yarn.lock @@ -1033,6 +1033,11 @@ classnames@^2.2.5: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== +clsx@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -2119,6 +2124,14 @@ react-dom@^18.3.1: loose-envify "^1.1.0" scheduler "^0.23.2" +react-draggable@^4.4.6: + version "4.4.6" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.6.tgz#63343ee945770881ca1256a5b6fa5c9f5983fe1e" + integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw== + dependencies: + clsx "^1.1.1" + prop-types "^15.8.1" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" From ba54a3a68a3214144a02b5513e9d82eda77c8022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Wed, 4 Dec 2024 12:39:32 +0100 Subject: [PATCH 3/9] feat: show both string and binary data with new structured data --- src/mqueryfront/src/App.css | 14 +++-- .../src/components/ActionShowMatchContext.js | 62 +++++++++++++++---- src/mqueryfront/src/query/QueryMatchesItem.js | 30 +++++++-- 3 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/mqueryfront/src/App.css b/src/mqueryfront/src/App.css index 377d9dd0..4623cc31 100644 --- a/src/mqueryfront/src/App.css +++ b/src/mqueryfront/src/App.css @@ -90,18 +90,24 @@ .modal-container { position: fixed; + offset-distance: 10px; z-index: auto; max-width: 50vw; + right: 5vw; +} + +.modal-block { + position: relative; + block-size: "fit-content"; + right: 5vw; } .modal-dialog { margin: 0; } -.modal-block { - position: relative; - block-size: "fit-content"; - position: "center"; +.modal-header:hover { + cursor: grab; } .modal-table { diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index 8c257542..c6a57184 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -24,6 +24,16 @@ const useClickOutside = (ref, callback) => { }); }; +function base64ToHex(str64) { + return atob(str64) + .split("") + .map(function (aChar) { + return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); + }) + .join("") + .toUpperCase(); // Per your example output +} + const ActionShowMatchContext = (props) => { const ref = useRef(null); const [showModal, setShowModal] = useState(false); @@ -42,23 +52,49 @@ const ActionShowMatchContext = (props) => {
); + // Buffer.from(rawData, 'base64'); - const tableRows = Object.entries(props.context).map( - (contextItem, index) => ( - - - - {contextItem[0]} - - - {contextItem[1]} - - ) - ); + const tableRows = Object.keys(props.context).map((rulename, index) => { + const rulenameRows = props.context[rulename].map((foundSample) => { + return ( + <> + + {atob(foundSample["before"])} + {{atob(foundSample["matching"])}} + {atob(foundSample["after"])} + + + {base64ToHex(foundSample["before"])} + {{base64ToHex(foundSample["matching"])}} + {base64ToHex(foundSample["after"])} + + + ); + }); + + return ( + <> + + + + {rulename} + + + {rulenameRows[0]} + + {rulenameRows.slice(1).map((row) => ( + {row} + ))} + + ); + }); const modalBody = (
- {!props.context ? ( + {!Object.keys(props.context).length ? ( "No context available" ) : ( diff --git a/src/mqueryfront/src/query/QueryMatchesItem.js b/src/mqueryfront/src/query/QueryMatchesItem.js index 1f03ed37..8a62ae74 100644 --- a/src/mqueryfront/src/query/QueryMatchesItem.js +++ b/src/mqueryfront/src/query/QueryMatchesItem.js @@ -11,12 +11,30 @@ const QueryMatchesItem = (props) => { const stubContext = context ? context : { - key1: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - key2: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - key3: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + Multiple_Strings_Match: [ + { + before: "", + matching: "ZGVm", + after: "IHRlc3RfcHl0aG9uMygpOgogICAgcHJpbnQoImhlbGw=", + }, + ], + mquery_exceptions4: [ + { + before: "", + matching: "ZGVm", + after: "IHRlc3RfcHl0aG9uMygpOgogICAgcHJpbnQoImhlbGw=", + }, + { + before: "", + matching: "dGVzdA==", + after: "X3B5dGhvbjMoKToKICAgIHByaW50KCJoZWxsbyEiKQo=", + }, + { + before: "ZWxsbyEiKQogICAgYSA9IDQKICAgIHJldHVybiBhCgo=", + matching: "dGVzdA==", + after: "X3B5dGhvbjMoKQoK", + }, + ], }; const fileBasename = path.basename(file); From a4855754d68f2dd7bf9db6a832c1e0d60d166f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Thu, 19 Dec 2024 15:58:32 +0100 Subject: [PATCH 4/9] fix: implement new API structure --- src/mqueryfront/src/App.css | 3 +- .../src/components/ActionShowMatchContext.js | 54 ++++++++++++------- src/mqueryfront/src/query/QueryMatchesItem.js | 33 +----------- 3 files changed, 38 insertions(+), 52 deletions(-) diff --git a/src/mqueryfront/src/App.css b/src/mqueryfront/src/App.css index 4623cc31..1184edcf 100644 --- a/src/mqueryfront/src/App.css +++ b/src/mqueryfront/src/App.css @@ -89,10 +89,9 @@ } .modal-container { - position: fixed; + position: absolute; offset-distance: 10px; z-index: auto; - max-width: 50vw; right: 5vw; } diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index c6a57184..9518f922 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -52,32 +52,48 @@ const ActionShowMatchContext = (props) => { ); - // Buffer.from(rawData, 'base64'); const tableRows = Object.keys(props.context).map((rulename, index) => { - const rulenameRows = props.context[rulename].map((foundSample) => { - return ( - <> - - - - ); - }); + const rulenameRows = Object.keys(props.context[rulename]).map( + (identifier) => { + const foundSample = props.context[rulename][identifier]; + return ( + <> + + + + + ); + } + ); return ( <> ); From 7d08b6de5ae2ee887dae84b2a78a563ec9b08472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Thu, 2 Jan 2025 12:58:22 +0100 Subject: [PATCH 6/9] fix: html breaklines introduced to cell content --- src/mqueryfront/package.json | 1 + .../src/components/ActionShowMatchContext.js | 52 +++++++++------ src/mqueryfront/yarn.lock | 64 ++++++++++++++++++- 3 files changed, 96 insertions(+), 21 deletions(-) diff --git a/src/mqueryfront/package.json b/src/mqueryfront/package.json index 49097e4a..50d4ddc3 100644 --- a/src/mqueryfront/package.json +++ b/src/mqueryfront/package.json @@ -24,6 +24,7 @@ "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", "react-draggable": "^4.4.6", + "react-html-parser": "^2.0.2", "react-router-dom": "^6.26.2", "react-select": "^5.8.1", "replace-js-pagination": "^1.0.5", diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index 9297d26e..f51f8aa5 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -2,8 +2,9 @@ import React, { useState, useRef, useEffect } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faLightbulb } from "@fortawesome/free-solid-svg-icons"; import Draggable from "react-draggable"; +import ReactHtmlParser from "react-html-parser"; -const useClickOutside = (ref, callback) => { +const useClickOutsideModal = (ref, callback) => { const handleClick = (event) => { if (ref.current && !ref.current.contains(event.target)) { // lose focus (higher z-index) only if other modal was clicked @@ -31,12 +32,12 @@ function base64ToHex(str64) { .map(function (aChar) { return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); }) - .join(" ") - .toUpperCase() + " " + .join("") + .toUpperCase() ); } -function base64ToUtf8(str64) { +function base64ToSanitizedUtf8(str64) { return ( atob(str64) .split("") @@ -46,26 +47,43 @@ function base64ToUtf8(str64) { } return "."; }) - .join(" ") + " " + .join("") ); } +function insertEveryNChars (str, insert, n) { + return str.split(new RegExp(`(.{${n}})`)).filter(x=>x).join(insert) +} + +function cellHTML(foundSample, lineLength, transformFunc) { + const hexBefore = transformFunc(foundSample["before"]); + const hexMatching = transformFunc(foundSample["matching"]); + const hexAfter = transformFunc(foundSample["after"]); + const basicStr = hexBefore + hexMatching + hexAfter; + const strWithBreakLines = insertEveryNChars(basicStr, '
', lineLength); + const breaksInBefore = Math.floor(hexBefore.length / lineLength); + const breaksInBeforeAndMatching = Math.floor((hexBefore.length + hexMatching.length) / lineLength); + const BoldOpeningTagIndex = hexBefore.length + 4*breaksInBefore; + const BoldClosingTagIndex = hexBefore.length + hexMatching.length + 4*breaksInBeforeAndMatching; + let boldedStr = strWithBreakLines.slice(0, BoldClosingTagIndex) + '' + strWithBreakLines.slice(BoldClosingTagIndex); + boldedStr = boldedStr.slice(0, BoldOpeningTagIndex) + '' + boldedStr.slice(BoldOpeningTagIndex); + return boldedStr +} + const ActionShowMatchContext = (props) => { const ref = useRef(null); const [showModal, setShowModal] = useState(false); const [focus, setFocus] = useState(true); - useClickOutside(ref, () => setFocus(false)); + useClickOutsideModal(ref, () => setFocus(false)); const modalHeader = (
{`Match context for ${props.filename}`}
+ />
); @@ -82,21 +100,15 @@ const ActionShowMatchContext = (props) => {
); diff --git a/src/mqueryfront/yarn.lock b/src/mqueryfront/yarn.lock index 9462f3ea..3d76482e 100644 --- a/src/mqueryfront/yarn.lock +++ b/src/mqueryfront/yarn.lock @@ -1238,6 +1238,39 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +domelementtype@1, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -1266,6 +1299,16 @@ encodeurl@~2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + entities@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" @@ -1572,6 +1615,18 @@ html-entities@^2.4.0: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== +htmlparser2@^3.9.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -2132,6 +2187,13 @@ react-draggable@^4.4.6: clsx "^1.1.1" prop-types "^15.8.1" +react-html-parser@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-html-parser/-/react-html-parser-2.0.2.tgz#6dbe1ddd2cebc1b34ca15215158021db5fc5685e" + integrity sha512-XeerLwCVjTs3njZcgCOeDUqLgNIt/t+6Jgi5/qPsO/krUWl76kWKXMeVs2LhY2gwM6X378DkhLjur0zUQdpz0g== + dependencies: + htmlparser2 "^3.9.0" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -2202,7 +2264,7 @@ readable-stream@^2.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6: +readable-stream@^3.0.6, readable-stream@^3.1.1: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== From 368c7338494a698d41dbf44a8ee7843a6b42213a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Thu, 2 Jan 2025 13:14:35 +0100 Subject: [PATCH 7/9] prettier: styling --- .../src/components/ActionShowMatchContext.js | 84 ++++++++++--------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index f51f8aa5..68e89552 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -26,33 +26,32 @@ const useClickOutsideModal = (ref, callback) => { }; function base64ToHex(str64) { - return ( - atob(str64) - .split("") - .map(function (aChar) { - return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); - }) - .join("") - .toUpperCase() - ); + return atob(str64) + .split("") + .map(function (aChar) { + return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); + }) + .join("") + .toUpperCase(); } function base64ToSanitizedUtf8(str64) { - return ( - atob(str64) - .split("") - .map(function (aChar) { - if (32 <= aChar.charCodeAt(0) && aChar.charCodeAt(0) < 127) { - return aChar; - } - return "."; - }) - .join("") - ); + return atob(str64) + .split("") + .map(function (aChar) { + if (32 <= aChar.charCodeAt(0) && aChar.charCodeAt(0) < 127) { + return aChar; + } + return "."; + }) + .join(""); } -function insertEveryNChars (str, insert, n) { - return str.split(new RegExp(`(.{${n}})`)).filter(x=>x).join(insert) +function insertEveryNChars(str, insert, n) { + return str + .split(new RegExp(`(.{${n}})`)) + .filter((x) => x) + .join(insert); } function cellHTML(foundSample, lineLength, transformFunc) { @@ -60,14 +59,23 @@ function cellHTML(foundSample, lineLength, transformFunc) { const hexMatching = transformFunc(foundSample["matching"]); const hexAfter = transformFunc(foundSample["after"]); const basicStr = hexBefore + hexMatching + hexAfter; - const strWithBreakLines = insertEveryNChars(basicStr, '
', lineLength); + const strWithBreakLines = insertEveryNChars(basicStr, "
", lineLength); const breaksInBefore = Math.floor(hexBefore.length / lineLength); - const breaksInBeforeAndMatching = Math.floor((hexBefore.length + hexMatching.length) / lineLength); - const BoldOpeningTagIndex = hexBefore.length + 4*breaksInBefore; - const BoldClosingTagIndex = hexBefore.length + hexMatching.length + 4*breaksInBeforeAndMatching; - let boldedStr = strWithBreakLines.slice(0, BoldClosingTagIndex) + '
' + strWithBreakLines.slice(BoldClosingTagIndex); - boldedStr = boldedStr.slice(0, BoldOpeningTagIndex) + '' + boldedStr.slice(BoldOpeningTagIndex); - return boldedStr + const breaksInBeforeAndMatching = Math.floor( + (hexBefore.length + hexMatching.length) / lineLength + ); + const BoldOpeningTagIndex = hexBefore.length + 4 * breaksInBefore; + const BoldClosingTagIndex = + hexBefore.length + hexMatching.length + 4 * breaksInBeforeAndMatching; + let boldedStr = + strWithBreakLines.slice(0, BoldClosingTagIndex) + + "" + + strWithBreakLines.slice(BoldClosingTagIndex); + boldedStr = + boldedStr.slice(0, BoldOpeningTagIndex) + + "" + + boldedStr.slice(BoldOpeningTagIndex); + return boldedStr; } const ActionShowMatchContext = (props) => { @@ -98,17 +106,15 @@ const ActionShowMatchContext = (props) => { {identifier} - - ); From 2326e80afc212356cb2f1933d89af37cae4e9247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Thu, 9 Jan 2025 15:33:54 +0100 Subject: [PATCH 8/9] fix: normalized cell sizes to hexdump standard & function namechange --- .../src/components/ActionShowMatchContext.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index 68e89552..9a60b666 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -31,11 +31,11 @@ function base64ToHex(str64) { .map(function (aChar) { return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); }) - .join("") - .toUpperCase(); + .join(" ") + .toUpperCase() + ' '; } -function base64ToSanitizedUtf8(str64) { +function base64ToSanitizedString(str64) { return atob(str64) .split("") .map(function (aChar) { @@ -101,19 +101,19 @@ const ActionShowMatchContext = (props) => { const foundSample = props.context[rulename][identifier]; return ( <> - @@ -127,7 +127,6 @@ const ActionShowMatchContext = (props) => {
- {atob(foundSample["before"])} - {{atob(foundSample["matching"])}} - {atob(foundSample["after"])} - - {base64ToHex(foundSample["before"])} - {{base64ToHex(foundSample["matching"])}} - {base64ToHex(foundSample["after"])} - + + {identifier} + + + {atob(foundSample["before"])} + {{atob(foundSample["matching"])}} + {atob(foundSample["after"])} + + {base64ToHex(foundSample["before"])} + {{base64ToHex(foundSample["matching"])}} + {base64ToHex(foundSample["after"])} +
{rulename} @@ -97,7 +113,7 @@ const ActionShowMatchContext = (props) => { {!Object.keys(props.context).length ? ( "No context available" ) : ( - +
{tableRows}
)} diff --git a/src/mqueryfront/src/query/QueryMatchesItem.js b/src/mqueryfront/src/query/QueryMatchesItem.js index 8a62ae74..719ecdd3 100644 --- a/src/mqueryfront/src/query/QueryMatchesItem.js +++ b/src/mqueryfront/src/query/QueryMatchesItem.js @@ -6,36 +6,7 @@ import ActionShowMatchContext from "../components/ActionShowMatchContext"; const QueryMatchesItem = (props) => { const { match, download_url } = props; - const { matches, meta, file, context } = match; // NOTE: presuming new field in Match schema context which would be dict with 'matches' as keys - - const stubContext = context - ? context - : { - Multiple_Strings_Match: [ - { - before: "", - matching: "ZGVm", - after: "IHRlc3RfcHl0aG9uMygpOgogICAgcHJpbnQoImhlbGw=", - }, - ], - mquery_exceptions4: [ - { - before: "", - matching: "ZGVm", - after: "IHRlc3RfcHl0aG9uMygpOgogICAgcHJpbnQoImhlbGw=", - }, - { - before: "", - matching: "dGVzdA==", - after: "X3B5dGhvbjMoKToKICAgIHByaW50KCJoZWxsbyEiKQo=", - }, - { - before: "ZWxsbyEiKQogICAgYSA9IDQKICAgIHJldHVybiBhCgo=", - matching: "dGVzdA==", - after: "X3B5dGhvbjMoKQoK", - }, - ], - }; + const { matches, meta, file, context } = match; const fileBasename = path.basename(file); @@ -101,7 +72,7 @@ const QueryMatchesItem = (props) => { {matchBadges} From 8dd430546cd4cfed8942ffb0422f1a7a70604899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Thu, 19 Dec 2024 16:45:00 +0100 Subject: [PATCH 5/9] fix: styling issues --- .../src/components/ActionShowMatchContext.js | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index 9518f922..9297d26e 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -25,13 +25,29 @@ const useClickOutside = (ref, callback) => { }; function base64ToHex(str64) { - return atob(str64) - .split("") - .map(function (aChar) { - return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); - }) - .join("") - .toUpperCase(); // Per your example output + return ( + atob(str64) + .split("") + .map(function (aChar) { + return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); + }) + .join(" ") + .toUpperCase() + " " + ); +} + +function base64ToUtf8(str64) { + return ( + atob(str64) + .split("") + .map(function (aChar) { + if (32 <= aChar.charCodeAt(0) && aChar.charCodeAt(0) < 127) { + return aChar; + } + return "."; + }) + .join(" ") + " " + ); } const ActionShowMatchContext = (props) => { @@ -66,21 +82,21 @@ const ActionShowMatchContext = (props) => {
- {atob(foundSample["before"])} - {{atob(foundSample["matching"])}} - {atob(foundSample["after"])} + {base64ToHex(foundSample["before"])} + {{base64ToHex(foundSample["matching"])}} + {base64ToHex(foundSample["after"])} - {base64ToHex(foundSample["before"])} - {{base64ToHex(foundSample["matching"])}} - {base64ToHex(foundSample["after"])} + {base64ToUtf8(foundSample["before"])} + {{base64ToUtf8(foundSample["matching"])}} + {base64ToUtf8(foundSample["after"])} - {base64ToHex(foundSample["before"])} - {{base64ToHex(foundSample["matching"])}} - {base64ToHex(foundSample["after"])} + {ReactHtmlParser(cellHTML(foundSample, 20, base64ToHex))} - {base64ToUtf8(foundSample["before"])} - {{base64ToUtf8(foundSample["matching"])}} - {base64ToUtf8(foundSample["after"])} + {ReactHtmlParser(cellHTML(foundSample, 10, base64ToSanitizedUtf8))} - {ReactHtmlParser(cellHTML(foundSample, 20, base64ToHex))} + + {ReactHtmlParser( + cellHTML(foundSample, 20, base64ToHex) + )} - {ReactHtmlParser(cellHTML(foundSample, 10, base64ToSanitizedUtf8))} + + {ReactHtmlParser( + cellHTML(foundSample, 10, base64ToSanitizedUtf8) + )} + {identifier} {ReactHtmlParser( - cellHTML(foundSample, 20, base64ToHex) + cellHTML(foundSample, 24, base64ToHex) )} {ReactHtmlParser( - cellHTML(foundSample, 10, base64ToSanitizedUtf8) + cellHTML(foundSample, 8, base64ToSanitizedString) )} {rulename} @@ -176,7 +175,7 @@ const ActionShowMatchContext = (props) => { className="modal modal-block" style={{ display: showModal ? "block" : "none" }} > -
+
{modalHeader} {modalBody} From c5edd0022d1362996327ef264a4b7750faf65e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kolankiewicz?= Date: Thu, 9 Jan 2025 15:35:12 +0100 Subject: [PATCH 9/9] lint: prettier --- .../src/components/ActionShowMatchContext.js | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/mqueryfront/src/components/ActionShowMatchContext.js b/src/mqueryfront/src/components/ActionShowMatchContext.js index 9a60b666..019847bc 100644 --- a/src/mqueryfront/src/components/ActionShowMatchContext.js +++ b/src/mqueryfront/src/components/ActionShowMatchContext.js @@ -26,13 +26,15 @@ const useClickOutsideModal = (ref, callback) => { }; function base64ToHex(str64) { - return atob(str64) - .split("") - .map(function (aChar) { - return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); - }) - .join(" ") - .toUpperCase() + ' '; + return ( + atob(str64) + .split("") + .map(function (aChar) { + return ("0" + aChar.charCodeAt(0).toString(16)).slice(-2); + }) + .join(" ") + .toUpperCase() + " " + ); } function base64ToSanitizedString(str64) { @@ -113,7 +115,11 @@ const ActionShowMatchContext = (props) => {
{ReactHtmlParser( - cellHTML(foundSample, 8, base64ToSanitizedString) + cellHTML( + foundSample, + 8, + base64ToSanitizedString + ) )}