Skip to content

Commit

Permalink
[#27] Initial regex filters structure
Browse files Browse the repository at this point in the history
  • Loading branch information
ivancea committed Feb 14, 2021
1 parent de4a71a commit 40da6b3
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 70 deletions.
4 changes: 3 additions & 1 deletion Frontend/src/components/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import { Alert } from "reactstrap";
import { useChanges } from "../hooks/useChanges";
import { ChangesList } from "./changes/ChangesList";
import { ChangesFilters } from "./changes/filters/ChangesFilters";
import { RepositoryErrors } from "./RepositoryErrors";
import "./styles/global.scss";

Expand All @@ -12,6 +13,7 @@ export function Home(): React.ReactElement {
changes,
setChanges,
errors,
filter,
setFilter,
isHidden,
notifyHiddenChanges,
Expand All @@ -26,10 +28,10 @@ export function Home(): React.ReactElement {
{connectionError}
</Alert>
<RepositoryErrors errors={errors} />
<ChangesFilters changes={changes} filter={filter} setFilter={setFilter} />
<ChangesList
changes={changes}
setChanges={setChanges}
setFilter={setFilter}
isHidden={isHidden}
notifyHiddenChanges={notifyHiddenChanges}
setNotifyHiddenChanges={setNotifyHiddenChanges}
Expand Down
72 changes: 6 additions & 66 deletions Frontend/src/components/changes/ChangesList.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,24 @@
import { cloneDeep } from "lodash";
import React, { Dispatch, SetStateAction, useCallback } from "react";
import { useId } from "react-id-generator";
import { Button, ButtonGroup, Col, Container, ListGroup, Row, UncontrolledCollapse } from "reactstrap";
import { Filter } from "../../hooks/useChanges";
import { ChangeObjectType, ChangeType, ChangeWrapper } from "../../types/changes";
import React, { Dispatch, SetStateAction } from "react";
import { Button, ButtonGroup, ListGroup } from "reactstrap";
import { ChangeWrapper } from "../../types/changes";
import { Change } from "./Change";
import { ChangeFilterSelector } from "./ChangeFilterSelector";

type Props = {
changes: ChangeWrapper[];
setChanges: Dispatch<SetStateAction<ChangeWrapper[]>>;
setFilter: Dispatch<SetStateAction<Filter>>;
isHidden: (change: ChangeWrapper) => boolean;
notifyHiddenChanges: boolean;
setNotifyHiddenChanges: Dispatch<SetStateAction<boolean>>;
};

const changeTypes = Object.keys(ChangeType).filter((t) => typeof t === "string");
const changeObjectTypes = Object.keys(ChangeObjectType).filter((t) => typeof t === "string");

export function ChangesList({
changes,
setChanges,
setFilter,
isHidden,
notifyHiddenChanges,
setNotifyHiddenChanges,
}: Props): React.ReactElement {
const [filtersTogglerId] = useId();
const useFilterChanged = (filterType: keyof Filter): ((elements: Map<string | undefined, boolean>) => void) =>
useCallback(
(filter: Map<string | undefined, boolean>) =>
setFilter((f) => ({
...f,
[filterType]: filter,
})),
[filterType],
);

const onRepositoriesFilterChanged = useFilterChanged("repositories");
const onUsersFilterChanged = useFilterChanged("users");
const onTypesFilterChanged = useFilterChanged("types");
const onObjectTypesFilterChanged = useFilterChanged("objectTypes");

const markAllAsRead = React.useCallback(() => {
setChanges((oldChanges) => oldChanges.map((change) => ({ ...cloneDeep(change), seen: true })));
}, [setChanges]);
Expand Down Expand Up @@ -73,45 +49,9 @@ export function ChangesList({
>
{notifyHiddenChanges ? "✅" : "❌"} Notify hidden changes
</Button>
<Container>
<Row>
<Col xs="1">
<span id={filtersTogglerId}>Filters</span>
</Col>
<Col>
<UncontrolledCollapse toggler={`#${filtersTogglerId}`}>
<ChangeFilterSelector
name="Repositories"
changes={changes}
accessor={useCallback((c) => c.repository, [])}
onChanged={onRepositoriesFilterChanged}
/>
<ChangeFilterSelector
name="Users"
changes={changes}
accessor={useCallback((c) => (c.change.user ? c.change.user.name : ""), [])}
textSelector={useCallback((o) => (o === "" ? <i>No user</i> : o), [])}
onChanged={onUsersFilterChanged}
/>
<ChangeFilterSelector
name="Types"
changes={changes}
defaultOptions={changeTypes}
accessor={useCallback((c) => c.change.type, [])}
onChanged={onTypesFilterChanged}
/>
<ChangeFilterSelector
name="Object types"
changes={changes}
defaultOptions={changeObjectTypes}
accessor={useCallback((c) => c.change.objectType, [])}
onChanged={onObjectTypesFilterChanged}
/>
</UncontrolledCollapse>
</Col>
</Row>
</Container>
Total: {changes.length}, Visible: {changes.filter((c) => !isHidden(c)).length}
<div>
Total: {changes.length}, Visible: {changes.filter((c) => !isHidden(c)).length}
</div>
<ListGroup>
{changes
.map((change) => <Change key={change.id} change={change} hidden={isHidden(change)} />)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isNil } from "lodash";
import React, { useCallback, useEffect, useState } from "react";
import { Button, Col, Row } from "reactstrap";
import { ChangeWrapper } from "../../types/changes";
import { ChangeWrapper } from "../../../types/changes";

type Props = {
name: string;
Expand Down Expand Up @@ -71,7 +71,7 @@ export function ChangeFilterSelector({
return (
<Row>
<Col className="text-right" xs="2">
{name}:{" "}
{name}:
</Col>
<Col xs="10">
{Array.from(options.keys())
Expand Down
89 changes: 89 additions & 0 deletions Frontend/src/components/changes/filters/ChangesFilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { Dispatch, SetStateAction, useCallback } from "react";
import { useId } from "react-id-generator";
import { Button, Col, Container, Row, UncontrolledCollapse } from "reactstrap";
import { Filter } from "../../../hooks/useChanges";
import { ChangeObjectType, ChangeType, ChangeWrapper } from "../../../types/changes";
import { ChangeFilterSelector } from "./ChangeFilterSelector";

type Props = {
changes: ChangeWrapper[];
filter: Filter;
setFilter: Dispatch<SetStateAction<Filter>>;
};

const changeTypes = Object.keys(ChangeType).filter((t) => typeof t === "string");
const changeObjectTypes = Object.keys(ChangeObjectType).filter((t) => typeof t === "string");

export function ChangesFilters({ changes, filter, setFilter }: Props): React.ReactElement {
const [filtersTogglerId] = useId();

const useFilterChanged = (
filterType: keyof Filter,
): ((elements: Map<string | undefined, boolean> | RegExp) => void) =>
useCallback(
(filter: Map<string | undefined, boolean> | RegExp) =>
setFilter((f) => ({
...f,
[filterType]: filter,
})),
[filterType],
);

const onRepositoriesFilterChanged = useFilterChanged("repositories");
const onUsersFilterChanged = useFilterChanged("users");
const onTypesFilterChanged = useFilterChanged("types");
const onObjectTypesFilterChanged = useFilterChanged("objectTypes");

const onBranchFilterChanged = useFilterChanged("branch");
const onTagFilterChanged = useFilterChanged("tag");
const onCommitFilterChanged = useFilterChanged("commit");

return (
<Container>
<Row>
<Col xs="1">
<Button id={filtersTogglerId} outline color="info">
Filters
</Button>
</Col>
<Col>
<UncontrolledCollapse
defaultOpen={true}
toggler={`#${filtersTogglerId}`}
style={{
borderLeft: "1px solid black",
}}
>
<ChangeFilterSelector
name="Repositories"
changes={changes}
accessor={useCallback((c) => c.repository, [])}
onChanged={onRepositoriesFilterChanged}
/>
<ChangeFilterSelector
name="Users"
changes={changes}
accessor={useCallback((c) => (c.change.user ? c.change.user.name : ""), [])}
textSelector={useCallback((o) => (o === "" ? <i>No user</i> : o), [])}
onChanged={onUsersFilterChanged}
/>
<ChangeFilterSelector
name="Types"
changes={changes}
defaultOptions={changeTypes}
accessor={useCallback((c) => c.change.type, [])}
onChanged={onTypesFilterChanged}
/>
<ChangeFilterSelector
name="Object types"
changes={changes}
defaultOptions={changeObjectTypes}
accessor={useCallback((c) => c.change.objectType, [])}
onChanged={onObjectTypesFilterChanged}
/>
</UncontrolledCollapse>
</Col>
</Row>
</Container>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { Modal, ModalBody, ModalHeader } from "reactstrap";
import { ChangeWrapper } from "../../../types/changes";

type Props = {
onAddFilter: (accessor: (change: ChangeWrapper) => string, regex: RegExp) => void;
onClose: () => void;
};

export default function CustomFilterCreationModal({ onAddFilter, onClose }: Props): React.ReactElement {
return (
<Modal isOpen={true} toggle={onClose} size="xs">
<ModalHeader></ModalHeader>
<ModalBody></ModalBody>
</Modal>
);
}
18 changes: 17 additions & 1 deletion Frontend/src/hooks/useChanges.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
import * as uuid from "uuid";
import { config } from "../Config";
import { ChangesNotification, ChangeWrapper } from "../types/changes";
import { ChangeObjectType, ChangesNotification, ChangeWrapper } from "../types/changes";
import { useLocalStorage } from "./useLocalStorage";
import { useSignalR } from "./useSignalR";

Expand All @@ -10,6 +10,14 @@ export type Filter = {
users: Map<string, boolean>;
types: Map<string, boolean>;
objectTypes: Map<string, boolean>;
branch: RegExp;
tag: RegExp;
commit: RegExp;
};

export type CustomFilter = {
accessor: (change: ChangeWrapper) => string;
regex: RegExp;
};

export type ChangesData = {
Expand All @@ -35,6 +43,9 @@ export function useChanges(): ChangesData {
users: new Map(),
types: new Map(),
objectTypes: new Map(),
branch: /.*/,
tag: /.*/,
commit: /.*/,
});
const [notifyHiddenChanges, setNotifyHiddenChanges] = useState(true);

Expand All @@ -48,6 +59,11 @@ export function useChanges(): ChangesData {
return true;
} else if (!filter.objectTypes.get(change.change.objectType)) {
return true;
} else if (
change.change.objectType === ChangeObjectType.Branch &&
!filter.branch.test(change.change.objectName)
) {
return true;
}

return false;
Expand Down

0 comments on commit 40da6b3

Please sign in to comment.