diff --git a/ui/.eslintrc b/ui/.eslintrc.js similarity index 68% rename from ui/.eslintrc rename to ui/.eslintrc.js index edc41d5..0b3e26b 100644 --- a/ui/.eslintrc +++ b/ui/.eslintrc.js @@ -8,20 +8,24 @@ module.exports = { }, extends: ["eslint:recommended", "plugin:react/recommended"], globals: {}, - parser: "babel-eslint", + parser: "@babel/eslint-parser", parserOptions: { ecmaFeatures: { jsx: true, }, ecmaVersion: 2018, sourceType: "module", + requireConfigFile: false }, plugins: ["react", "import", "react-hooks"], ignorePatterns: ["node_modules/"], - rules: {}, + rules: { + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + }, settings: { react: { - version: "latest", // "detect" automatically picks the version you have installed. + version: "detect", // "detect" automatically picks the version you have installed. }, }, -}; \ No newline at end of file +}; diff --git a/ui/package-lock.json b/ui/package-lock.json index b68a7aa..549ae7f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,6 +8,7 @@ "name": "ui", "version": "0.1.0", "dependencies": { + "@babel/eslint-parser": "^7.19.1", "@lhci/cli": "^0.9.0", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", @@ -21,7 +22,6 @@ }, "devDependencies": { "autoprefixer": "^10.4.7", - "babel-eslint": "^10.1.0", "postcss": "^8.4.14", "sinon": "^14.0.0", "tailwindcss": "^3.0.24" @@ -108,11 +108,11 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz", - "integrity": "sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dependencies": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" }, @@ -124,18 +124,6 @@ "eslint": "^7.5.0 || ^8.0.0" } }, - "node_modules/@babel/eslint-parser/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", @@ -144,14 +132,6 @@ "node": ">=10" } }, - "node_modules/@babel/eslint-parser/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@babel/eslint-parser/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -2827,6 +2807,34 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4496,27 +4504,6 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" }, - "node_modules/babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "eslint": ">= 4.12.1" - } - }, "node_modules/babel-jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", @@ -7271,15 +7258,6 @@ "node": ">=10" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-webpack-plugin": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", @@ -16749,34 +16727,20 @@ } }, "@babel/eslint-parser": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz", - "integrity": "sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "requires": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" }, "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, "eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -18619,6 +18583,30 @@ } } }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -19845,20 +19833,6 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - } - }, "babel-jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", @@ -21923,12 +21897,6 @@ } } }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, "eslint-webpack-plugin": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", diff --git a/ui/package.json b/ui/package.json index 2bd3e77..ffdd469 100644 --- a/ui/package.json +++ b/ui/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@babel/eslint-parser": "^7.19.1", "@lhci/cli": "^0.9.0", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", @@ -42,7 +43,6 @@ }, "devDependencies": { "autoprefixer": "^10.4.7", - "babel-eslint": "^10.1.0", "postcss": "^8.4.14", "sinon": "^14.0.0", "tailwindcss": "^3.0.24" diff --git a/ui/src/Components/Dashboard/Dashboard.js b/ui/src/Components/Dashboard/Dashboard.js index 4d8b779..6fde6fc 100644 --- a/ui/src/Components/Dashboard/Dashboard.js +++ b/ui/src/Components/Dashboard/Dashboard.js @@ -1,10 +1,7 @@ -import Table from "./Table/Table" +import Table from "./Table/Table"; -export default function Dashboard({ featureFlags, headers }) { - return ( - - )} - \ No newline at end of file + const Dashboard = ({ featureFlags, headers }) => { +
; +} + +export default Dashboard; \ No newline at end of file diff --git a/ui/src/Components/Dashboard/Table/Table.js b/ui/src/Components/Dashboard/Table/Table.js index bdf61ea..580fe5e 100644 --- a/ui/src/Components/Dashboard/Table/Table.js +++ b/ui/src/Components/Dashboard/Table/Table.js @@ -1,39 +1,30 @@ -import {useState} from "react" -import TableHeader from "./TableHeader/TableHeader" -import TableRow from "./TableRow/TableRow" -import { compareValues } from "../../../Utils/helpers" +import { useState } from "react"; +import TableHeader from "./TableHeader/TableHeader"; +import TableRow from "./TableRow/TableRow"; +import { compareValues } from "../../../Utils/helpers"; export default function Table({ featureFlags, headers }) { + const [rowData, setRowData] = useState(featureFlags); -const [rowData,setRowData] = useState(featureFlags) - -const handleSorting = (type,onColumn) => { - - let rows = rowData; - rows.sort(compareValues(onColumn,type)) - setRowData([...rows]) - -} + const handleSorting = (type, onColumn) => { + let rows = rowData; + rows.sort(compareValues(onColumn, type)); + setRowData([...rows]); + }; return ( - -
- +
+ - {rowData.map(featureFlag => + {rowData.map((featureFlag) => ( - )} + /> + ))}
- ) -} \ No newline at end of file + ); +} diff --git a/ui/src/Components/Dashboard/Table/TableHeader/SortCursor.js b/ui/src/Components/Dashboard/Table/TableHeader/SortCursor.js index 8b4c6b7..bc77077 100644 --- a/ui/src/Components/Dashboard/Table/TableHeader/SortCursor.js +++ b/ui/src/Components/Dashboard/Table/TableHeader/SortCursor.js @@ -1,33 +1,21 @@ -import { useState } from "react"; import { TABLE } from "../../../../Constant/constant"; -export default function SortCursor({ header, handleSorting }) { - const [currentClickedCursor, setCurrentClickedCursor] = useState(null); - - const onCursorClick = (clickedCursorType, headerName) => { - setCurrentClickedCursor(clickedCursorType); - handleSorting(clickedCursorType, headerName); - }; - +export default function SortCursor({ currentClickedCursor }) { return (
{ - onCursorClick(TABLE.ASCENDING, header); - }} >
{ - onCursorClick(TABLE.DESCENDING, header); - }} >
); diff --git a/ui/src/Components/Dashboard/Table/TableHeader/TableHeader.js b/ui/src/Components/Dashboard/Table/TableHeader/TableHeader.js index 36a2c29..6f509a2 100644 --- a/ui/src/Components/Dashboard/Table/TableHeader/TableHeader.js +++ b/ui/src/Components/Dashboard/Table/TableHeader/TableHeader.js @@ -1,27 +1,48 @@ -import PreviousMap from "postcss/lib/previous-map"; +import { useState } from "react"; + import { camelCaseToNormal } from "../../../../Utils/helpers"; import SortCursor from "./SortCursor"; import { TABLE } from "../../../../Constant/constant"; export default function TableHeader({ headers, handleSorting }) { + const [currentClickedCursor, setCurrentClickedCursor] = useState(null); + const [currentSortedColumn, setCurrentSortedColumn] = useState(null); + + const onCursorClick = (headerName, isSortConfigured) => { + if (!isSortConfigured) return; + let clickedCursorType = + currentClickedCursor == TABLE.ASCENDING + ? TABLE.DESCENDING + : TABLE.ASCENDING; + setCurrentClickedCursor(clickedCursorType); + setCurrentSortedColumn(headerName); + handleSorting(clickedCursorType, headerName); + }; return ( {headers.map((heading, index) => ( - - - - {camelCaseToNormal(heading.headerName)} - - - {heading.sortable ? ( - - ) : null} - - + { + onCursorClick(heading.headerName, heading.sortable); + }} + > +
+ {camelCaseToNormal(heading.headerName)} + + {heading.sortable ? ( + + ) : null} +
))} diff --git a/ui/src/Utils/helpers.js b/ui/src/Utils/helpers.js index de68c97..5a402c6 100644 --- a/ui/src/Utils/helpers.js +++ b/ui/src/Utils/helpers.js @@ -1,15 +1,18 @@ -import {TABLE} from "../Constant/constant" +/* eslint-disable no-prototype-builtins */ +import { TABLE } from "../Constant/constant"; export function camelCaseToNormal(string) { - return string - // insert a space before all caps - .replace(/([A-Z])/g, ' $1') - // uppercase the first character - .replace(/^./, (str) => str.toUpperCase()) + return ( + string + // insert a space before all caps + .replace(/([A-Z])/g, " $1") + // uppercase the first character + .replace(/^./, (str) => str.toUpperCase()) + ); } /**** - * + * * Currying * https://javascript.info/currying-partials */ @@ -19,19 +22,15 @@ export function compareValues(key, order = TABLE.ASCENDING) { return 0; } - const varA = (typeof a[key] === 'string') - ? a[key].toUpperCase() : a[key]; - const varB = (typeof b[key] === 'string') - ? b[key].toUpperCase() : b[key]; + const value1 = typeof a[key] === "string" ? a[key].toUpperCase() : a[key]; + const value2 = typeof b[key] === "string" ? b[key].toUpperCase() : b[key]; let comparison = 0; - if (varA > varB) { + if (value1 > value2) { comparison = 1; - } else if (varA < varB) { + } else if (value1 < value2) { comparison = -1; } - return ( - (order === TABLE.DESCENDING) ? (comparison * -1) : comparison - ); + return order === TABLE.DESCENDING ? comparison * -1 : comparison; }; -} \ No newline at end of file +} diff --git a/ui/src/index.css b/ui/src/index.css index dd99768..7e4ed3f 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -4,15 +4,15 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } @@ -21,26 +21,20 @@ code { background: transparent; border-bottom: solid 7px black; border-top-width: 0; - cursor: pointer; } -.clicked-u{ +.clicked-u { border-bottom: solid 7px #ad9f9f; } -.down-arrow{ +.down-arrow { border: solid 6px transparent; background: transparent; border-top: solid 7px black; border-bottom-width: 0; - margin-top:1px; - cursor: pointer; + margin-top: 1px; } -.clicked-d{ +.clicked-d { border-top: solid 7px #ad9f9f; } - - - - diff --git a/ui/src/test/SortCursor.test.js b/ui/src/test/SortCursor.test.js index 1ce8f78..03048b1 100644 --- a/ui/src/test/SortCursor.test.js +++ b/ui/src/test/SortCursor.test.js @@ -1,45 +1,19 @@ -import { fireEvent, render, screen } from "@testing-library/react"; +import {render, screen } from "@testing-library/react"; import SortCursor from "../Components/Dashboard/Table/TableHeader/SortCursor"; import { TABLE } from "../Constant/constant"; describe("SortCursor Component", () => { + it("Should render the SortCursor Component, which includes Ascending cursor", () => { + render(); - it("Should render the SortCursor Component with Ascending cursor", () => { - render() + const cursor = screen.getByTitle(TABLE.ASCENDING); + expect(cursor).toBeInTheDocument(); + }); - const cursor = screen.getByTitle(TABLE.ASCENDING) - expect(cursor).toBeInTheDocument(); - }) - - it("Should render the SortCursor Component with Descending cursor", () => { - render() - - const cursor = screen.getByTitle(TABLE.DESCENDING) - expect(cursor).toBeInTheDocument(); - - }) - - it("Should fire event on click ascending", async () => { - //const mockFn = sinon.spy(); - - const mockFn = jest.fn(); - render() - - const cursor = screen.getByTitle(TABLE.ASCENDING) - await fireEvent.click(cursor); - - - }) - - it("Should fire event on click descending", async () => { - const mockFn = jest.fn(); - render() - - const cursor = screen.getByTitle(TABLE.DESCENDING) - await fireEvent.click(cursor); - expect(mockFn.mock.calls.length).toEqual(1); - - }) - - }) + it("Should render the SortCursor Component, which includes Descending cursor", () => { + render(); + const cursor = screen.getByTitle(TABLE.DESCENDING); + expect(cursor).toBeInTheDocument(); + }); +});