diff --git a/content/src/scripts/components/Pane/Pane.jsx b/content/src/scripts/components/Pane/Pane.jsx
index 050b233..244c031 100644
--- a/content/src/scripts/components/Pane/Pane.jsx
+++ b/content/src/scripts/components/Pane/Pane.jsx
@@ -3,6 +3,7 @@ import { TabIdentifierClient } from "chrome-tab-identifier";
import SVG from "../SVG";
import TreeList from "../../containers/TreeList/TreeList";
+import Filter from "../../containers/Filter/Filter";
import Resizer from "../../containers/Resizer";
import { OptionsContext } from "../../contexts/OptionsContext";
import { fetchURLDetails } from "../../utils/url";
@@ -109,10 +110,11 @@ function Pane({
tabId={tabId}
/>
) : null}
+
-
+
-
+
);
}
diff --git a/content/src/scripts/components/Toggler/styles.css b/content/src/scripts/components/Toggler/styles.css
index 3a49fce..1c4fba8 100644
--- a/content/src/scripts/components/Toggler/styles.css
+++ b/content/src/scripts/components/Toggler/styles.css
@@ -6,7 +6,7 @@
transform-origin: top left;
border-radius: 0px 0px 4px 4px;
cursor: pointer;
- z-index: 10;
+ z-index: 1000;
box-shadow: 0px 0px 5px #000000d9;
color: white;
background: rgb(77, 61, 146);
diff --git a/content/src/scripts/components/TreeItem/TreeItem.jsx b/content/src/scripts/components/TreeItem/TreeItem.jsx
index 10c91f3..35db51a 100644
--- a/content/src/scripts/components/TreeItem/TreeItem.jsx
+++ b/content/src/scripts/components/TreeItem/TreeItem.jsx
@@ -5,6 +5,8 @@ import { fetchURLDetails } from "../../utils/url";
import fileIcons from "../../utils/file-icons";
import "./styles.css";
+import { isMergeRequestShown, isRepositoryShown, grabMergeRequestIdFromCurrentUrl } from "../../../../../event/src/actions/API";
+import { sha1 } from ".";
function TreeItem({
width,
@@ -34,14 +36,23 @@ function TreeItem({
} else {
setClicked(true);
const URLDetails = fetchURLDetails();
- if ("compatibility-mode" in options && options["compatibility-mode"]) {
- window.location.href = `${window.location.origin}/${
- URLDetails.dirFormatted
- }/blob/${URLDetails.branchName}/${path.join("/")}`;
- } else {
- window.location.href = `${window.location.origin}/${
- URLDetails.dirFormatted
- }/-/blob/${URLDetails.branchName}/${path.join("/")}`;
+ if (isRepositoryShown()) {
+ if ("compatibility-mode" in options && options["compatibility-mode"]) {
+ window.location.href = `${window.location.origin}/${URLDetails.dirFormatted
+ }/blob/${URLDetails.branchName}/${path.join("/")}`;
+ } else {
+ window.location.href = `${window.location.origin}/${URLDetails.dirFormatted
+ }/-/blob/${URLDetails.branchName}/${path.join("/")}`;
+ }
+ } else if (isMergeRequestShown()) {
+ let hash = sha1(path);
+ let mergeRequestId = grabMergeRequestIdFromCurrentUrl();
+ if (!window.location.href.includes('diffs')) {
+ window.location.href = (window.location.origin + "/" + URLDetails.dirFormatted + "/-/merge_requests/" + mergeRequestId + "/diffs#" + hash);
+ } else {
+ window.location.hash = hash;
+ window.location.reload();
+ }
}
}
};
diff --git a/content/src/scripts/components/TreeItem/index.js b/content/src/scripts/components/TreeItem/index.js
index 4fdcf6d..c579521 100644
--- a/content/src/scripts/components/TreeItem/index.js
+++ b/content/src/scripts/components/TreeItem/index.js
@@ -1 +1,142 @@
export { default } from "./TreeItem";
+
+
+function rotate_left(n, s) {
+ var t4 = (n << s) | (n >>> (32 - s));
+ return t4;
+};
+function lsb_hex(val) {
+ var str = '';
+ var i;
+ var vh;
+ var vl;
+ for (i = 0; i <= 6; i += 2) {
+ vh = (val >>> (i * 4 + 4)) & 0x0f;
+ vl = (val >>> (i * 4)) & 0x0f;
+ str += vh.toString(16) + vl.toString(16);
+ }
+ return str;
+};
+function cvt_hex(val) {
+ var str = '';
+ var i;
+ var v;
+ for (i = 7; i >= 0; i--) {
+ v = (val >>> (i * 4)) & 0x0f;
+ str += v.toString(16);
+ }
+ return str;
+};
+function Utf8Encode(string) {
+ string = string.replace(/\r\n/g, '\n');
+ var utftext = '';
+ for (var n = 0; n < string.length; n++) {
+ var c = string.charCodeAt(n);
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if ((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ }
+ return utftext;
+};
+
+/**
+* Secure Hash Algorithm (SHA1)
+* http://www.webtoolkit.info/
+**/
+export const sha1 = (msg) => {
+
+ var blockstart;
+ var i, j;
+ var W = new Array(80);
+ var H0 = 0x67452301;
+ var H1 = 0xEFCDAB89;
+ var H2 = 0x98BADCFE;
+ var H3 = 0x10325476;
+ var H4 = 0xC3D2E1F0;
+ var A, B, C, D, E;
+ var temp;
+ msg = Utf8Encode(msg);
+ var msg_len = msg.length;
+ var word_array = new Array();
+ for (i = 0; i < msg_len - 3; i += 4) {
+ j = msg.charCodeAt(i) << 24 | msg.charCodeAt(i + 1) << 16 |
+ msg.charCodeAt(i + 2) << 8 | msg.charCodeAt(i + 3);
+ word_array.push(j);
+ }
+ switch (msg_len % 4) {
+ case 0:
+ i = 0x080000000;
+ break;
+ case 1:
+ i = msg.charCodeAt(msg_len - 1) << 24 | 0x0800000;
+ break;
+ case 2:
+ i = msg.charCodeAt(msg_len - 2) << 24 | msg.charCodeAt(msg_len - 1) << 16 | 0x08000;
+ break;
+ case 3:
+ i = msg.charCodeAt(msg_len - 3) << 24 | msg.charCodeAt(msg_len - 2) << 16 | msg.charCodeAt(msg_len - 1) << 8 | 0x80;
+ break;
+ }
+ word_array.push(i);
+ while ((word_array.length % 16) != 14) word_array.push(0);
+ word_array.push(msg_len >>> 29);
+ word_array.push((msg_len << 3) & 0x0ffffffff);
+ for (blockstart = 0; blockstart < word_array.length; blockstart += 16) {
+ for (i = 0; i < 16; i++) W[i] = word_array[blockstart + i];
+ for (i = 16; i <= 79; i++) W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
+ A = H0;
+ B = H1;
+ C = H2;
+ D = H3;
+ E = H4;
+ for (i = 0; i <= 19; i++) {
+ temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+ for (i = 20; i <= 39; i++) {
+ temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+ for (i = 40; i <= 59; i++) {
+ temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+ for (i = 60; i <= 79; i++) {
+ temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+ H0 = (H0 + A) & 0x0ffffffff;
+ H1 = (H1 + B) & 0x0ffffffff;
+ H2 = (H2 + C) & 0x0ffffffff;
+ H3 = (H3 + D) & 0x0ffffffff;
+ H4 = (H4 + E) & 0x0ffffffff;
+ }
+ var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
+
+ return temp.toLowerCase();
+}
\ No newline at end of file
diff --git a/content/src/scripts/containers/Filter/Filter.jsx b/content/src/scripts/containers/Filter/Filter.jsx
new file mode 100644
index 0000000..bbadaf5
--- /dev/null
+++ b/content/src/scripts/containers/Filter/Filter.jsx
@@ -0,0 +1,49 @@
+import React, { useState, useEffect } from "react";
+import {
+ isMergeRequestShown
+} from "../../../../../event/src/actions/API";
+
+import "./styles.css";
+
+
+function Filter({
+
+}) {
+
+ // const [checkedTests, setCheckedTest] = useState();
+ // useEffect(() => {
+ // handleChange = () => {
+ // setCheckedTest(!checkedTests, () => {
+ // window.location.reload();
+ // });
+ // };
+ // }, []);
+
+ return (
+
+ );
+}
+
+export default Filter;
diff --git a/content/src/scripts/containers/Filter/index.js b/content/src/scripts/containers/Filter/index.js
new file mode 100644
index 0000000..84ae2e8
--- /dev/null
+++ b/content/src/scripts/containers/Filter/index.js
@@ -0,0 +1 @@
+export { default } from "./Filter";
diff --git a/content/src/scripts/containers/Filter/styles.css b/content/src/scripts/containers/Filter/styles.css
new file mode 100644
index 0000000..09390b5
--- /dev/null
+++ b/content/src/scripts/containers/Filter/styles.css
@@ -0,0 +1,7 @@
+.spantree-filter-header {
+ height: 50px;
+ background-color: rgb(77, 61, 146);
+ border-bottom: 1px #404040 solid;
+ color: white;
+ padding: 5px;
+}
diff --git a/content/src/scripts/containers/TreeList/TreeList.jsx b/content/src/scripts/containers/TreeList/TreeList.jsx
index 746eaab..009e706 100644
--- a/content/src/scripts/containers/TreeList/TreeList.jsx
+++ b/content/src/scripts/containers/TreeList/TreeList.jsx
@@ -62,6 +62,7 @@ function TreeList({
setClicked,
getInitialTree,
closeDir,
+ filtersEnabled,
}) {
const [loading, setLoading] = useState(true);
const [rendering, setRendering] = useState(false);
@@ -80,6 +81,16 @@ function TreeList({
return firstPageLoad;
};
+ const buildFilterMap = () => {
+ let map = new Map();
+ map['test'] = document.getElementById('filterTests').checked;
+ map['removed'] = document.getElementById('filterRemoved').checked;
+ map['renamed'] = document.getElementById('filterRenamed').checked;
+ map['imports'] = document.getElementById('filteredImports').checked;
+ map['newFile'] = document.getElementById('filteredNewFiles').checked;
+ return map;
+ }
+
useEffect(() => {
if (URLDetails.baseRemovedURL.length === 0) {
setRendering(false);
@@ -99,6 +110,7 @@ function TreeList({
branchName: URLDetails.branchName,
tabId,
},
+ buildFilterMap(),
);
}
setFirstPageLoad(false);
diff --git a/content/src/scripts/containers/TreeList/styles.css b/content/src/scripts/containers/TreeList/styles.css
index e8b918a..38f8b19 100644
--- a/content/src/scripts/containers/TreeList/styles.css
+++ b/content/src/scripts/containers/TreeList/styles.css
@@ -9,7 +9,7 @@
.spantree-tree-list {
scroll-behavior: smooth;
overflow-y: auto;
- height: calc(100vh - 40px);
+ height: calc(100vh - 90px);
}
.spantree-tree-list::-webkit-scrollbar-track {
diff --git a/content/src/scripts/containers/app/App.jsx b/content/src/scripts/containers/app/App.jsx
index 2230eaa..2cb4d3c 100644
--- a/content/src/scripts/containers/app/App.jsx
+++ b/content/src/scripts/containers/app/App.jsx
@@ -15,6 +15,11 @@ import { browserKey } from "../../utils/browser";
import searchBarWorkerJS from "../../utils/searchBarWorker";
import WebWorker from "./WebWorker";
+import {
+ isRepositoryShown,
+ isMergeRequestShown
+} from "../../../../../event/src/actions/API";
+
import "./App.css";
const importFileIconCSS = `${browserKey()}-extension://${chrome.i18n.getMessage(
@@ -45,7 +50,7 @@ class App extends Component {
};
this.shouldShowSpanTree = () => {
return (
- document.querySelector(".qa-branches-select") !== null &&
+ (isRepositoryShown() || isMergeRequestShown()) &&
document.querySelector(".nav-sidebar") !== null
);
};
@@ -96,24 +101,24 @@ class App extends Component {
{this.props.opened[tabId]
? ReactDOM.createPortal(
- this.setShowSearchbar(true)}
- />,
- parentDiv,
- )
+ this.setShowSearchbar(true)}
+ />,
+ parentDiv,
+ )
: ReactDOM.createPortal(
- ,
- document.getElementById("rcr-anchor"),
- )}
+ ,
+ document.getElementById("rcr-anchor"),
+ )}
{
- let url = `${id}/repository/tree`;
- url += "?per_page=10000";
+export const isRepositoryShown = () => {
+ return document.querySelector(".qa-branches-select") !== null;
+};
+export const isMergeRequestShown = () => {
+ return document.querySelector(".diffs-tab") !== null;
+};
+
+export const grabMergeRequestIdFromCurrentUrl = () => {
+ const pathName = window.location.pathname;
+ const mergeRequest = '/merge_requests/';
+ let start = pathName.indexOf(mergeRequest);
+ if (start == -1) {
+ return null;
+ }
+ let path = pathName.substring(start + mergeRequest.length);
+ if (path.includes('/')) {
+ return path.substring(0, path.indexOf('/'));
+ }
+ return path;
+};
+
+export const getUrl = (id) => {
+ if (isRepositoryShown()) {
+ return `${id}/repository/tree?per_page=10000`;
+ } else if (isMergeRequestShown()) {
+ let mergeRequestId = grabMergeRequestIdFromCurrentUrl();
+ return `${id}/merge_requests/${mergeRequestId}/changes?access_raw_diffs=false`;
+ }
+};
+
+export const getInitialTree = (id, params, reducerDetails, filtersEnabled) => {
+ let url = getUrl(id);
for (let param in params) {
url += `&${param}=${params[param]}`;
}
@@ -15,11 +44,13 @@ export const getInitialTree = (id, params, reducerDetails) => {
.then((res) => {
store.dispatch({
type: types.FETCH_TREE,
+ dataUrl: res.request.responseURL,
payload: res.data,
reducerDetails,
+ filtersEnabled,
});
})
- .catch((_err) => {});
+ .catch((_err) => { });
};
export const openDir = (id, path, params, reducerDetails) => {
@@ -42,7 +73,7 @@ export const openDir = (id, path, params, reducerDetails) => {
reducerDetails,
});
})
- .catch((_err) => {});
+ .catch((_err) => { });
};
export const closeDir = (path, reducerDetails) => {
@@ -69,5 +100,5 @@ export const getSearchTerms = (reducerDetails) => {
reducerDetails,
});
})
- .catch((_err) => {});
+ .catch((_err) => { });
};
diff --git a/event/src/reducers/API/tree.js b/event/src/reducers/API/tree.js
index 79976a7..045c038 100644
--- a/event/src/reducers/API/tree.js
+++ b/event/src/reducers/API/tree.js
@@ -9,26 +9,7 @@ export default (state = initialState, action) => {
case FETCH_TREE:
return {
...state,
- [action.reducerDetails.tabId]: action.payload
- .map((node) => {
- return {
- name: node.name,
- path: node.path
- .split("/")
- .filter((pathSub) => pathSub.length !== 0),
- isTree:
- node.type === "tree"
- ? {
- isOpen: false,
- }
- : false,
- children: node.type === "tree" ? {} : undefined,
- };
- })
- .reduce((map, obj) => {
- map[obj.name] = obj;
- return map;
- }, {}),
+ [action.reducerDetails.tabId]: mapNodesFromResult(action),
};
case OPEN_DIR:
let objectPath = [action.reducerDetails.tabId];
@@ -67,8 +48,8 @@ export default (state = initialState, action) => {
isTree:
node.type === "tree"
? {
- isOpen: false,
- }
+ isOpen: false,
+ }
: false,
children: node.type === "tree" ? {} : undefined,
};
@@ -106,3 +87,72 @@ export default (state = initialState, action) => {
return state;
}
};
+function mapNodesFromResult(action) {
+ if (action.dataUrl.toString().includes('/merge_requests/')) {
+ return filterData(action)
+ .map((node) => {
+ return {
+ name: node.new_path,
+ path: node.new_path,
+ isTree: false,
+ children: false,
+ };
+ })
+ .reduce((map, obj) => {
+ map[obj.name] = obj;
+ return map;
+ }, {});
+ } else {
+ return action.payload
+ .map((node) => {
+ return {
+ name: node.name,
+ path: node.path
+ .split("/")
+ .filter((pathSub) => pathSub.length !== 0),
+ isTree: node.type === "tree"
+ ? {
+ isOpen: false,
+ }
+ : false,
+ children: node.type === "tree" ? {} : undefined,
+ };
+ })
+ .reduce((map, obj) => {
+ map[obj.name] = obj;
+ return map;
+ }, {});
+ }
+
+};
+
+function filterData(action) {
+ let data = action.payload['changes'];
+ if (action.filtersEnabled['test']) {
+ data = data.filter((node) => {
+ return !node.new_path.includes('src/test/');
+ })
+ }
+ if (action.filtersEnabled['renamed']) {
+ data = data.filter((node) => {
+ return !node.renamed_file;
+ })
+ }
+ if (action.filtersEnabled['removed']) {
+ data = data.filter((node) => {
+ return !node.deleted_file;
+ })
+ }
+ if (action.filtersEnabled['newFile']) {
+ data = data.filter((node) => {
+ return !node.new_file;
+ })
+ }
+ if (action.filtersEnabled['imports']) {
+ data = data.filter((node) => {
+ return !node.new_file;
+ })
+ }
+ return data;
+};
+
diff --git a/event/src/reducers/UI/width.js b/event/src/reducers/UI/width.js
index 96b3267..c42cd83 100644
--- a/event/src/reducers/UI/width.js
+++ b/event/src/reducers/UI/width.js
@@ -1,6 +1,6 @@
import { SET_WIDTH } from "../../types/UI";
-const initialWidth = 250;
+const initialWidth = 300;
export default (state = initialWidth, action) => {
switch (action.type) {
diff --git a/package-lock.json b/package-lock.json
index aba01a9..f8a90fe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
+ "name": "span-tree",
"version": "0.0.1",
"dependencies": {
"axios": "^0.21.1",