resolve dependency issues

This commit is contained in:
Collin M. Barrett 2019-07-26 21:01:10 -05:00
parent 410004fa8a
commit 03153cd595
32 changed files with 454 additions and 399 deletions

Binary file not shown.

View file

@ -7,9 +7,19 @@
"@types/node": "12.6.8",
"@types/react": "16.8.23",
"@types/react-dom": "16.8.5",
"@types/react-router-dom": "^4.3.4",
"@types/react-table": "^6.8.5",
"bootstrap": "^4.3.1",
"es6-promise": "^4.2.8",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.4.1",
"moment": "^2.24.0",
"popper.js": "^1.15.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1",
"react-table": "^6.10.0",
"typescript": "3.5.3"
},
"scripts": {

View file

@ -1,33 +1,3 @@
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin;
pointer-events: none;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
body, h2, h3, h4, h5, blockquote { font-size: 16px; }
.container{ max-width:98vw!important;padding-left:7px!important }
.w-100{ padding-left:7px!important }

View file

@ -1,25 +1,12 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter } from "react-router-dom";
import * as RoutesModule from "./Routes";
const App: React.FC = () => {
// const baseUrl = document.getElementsByTagName("base")[0].getAttribute("href")!;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
<BrowserRouter children={RoutesModule.Routes} />
);
}

61
src/web/src/Layout.tsx Normal file
View file

@ -0,0 +1,61 @@
import * as React from "react";
import "bootstrap";
interface IProps {
children?: React.ReactNode;
};
export const Layout = (props: IProps) =>
<div className="container">
<Header/>
<div className="row">
<div className="w-100">
{ props.children }
</div>
</div>
<Footer/>
</div>;
const Header = () =>
<header className="row">
<h1>
<a href="./">
<img src="logo_filterlists.png" alt="FilterLists" className="img-fluid"/>
</a>
</h1>
</header>;
const Footer = () =>
<footer className="row justify-content-center">
<p className="mt-2 ml-1 mr-1">
<HubLink/> | <GitHubLink/> | <ApiLink/> | <DonateLink/> | By <OwnerLink/>
</p>
</footer>;
const HubLink = () =>
<a href="https://hub.filterlists.com"
title="Discourse community forum">
Hub
</a>;
const GitHubLink = () =>
<a href="https://github.com/collinbarrett/FilterLists">
GitHub
</a>;
const ApiLink = () =>
<a href="/api/v1/lists"
title="API lists endpoint">
API
</a>;
const DonateLink = () =>
<a href="https://beerpay.io/collinbarrett/FilterLists"
title="Support with Beerpay">
Donate
</a>;
const OwnerLink = () =>
<a href="https://collinmbarrett.com/">
Collin M. Barrett
</a>;

13
src/web/src/Routes.tsx Normal file
View file

@ -0,0 +1,13 @@
import * as React from "react";
import { Layout } from "./Layout";
import { Route, Redirect, Switch } from "react-router-dom";
import { Home } from "./modules";
export const Routes = <Layout>
<Switch>
<Route exact path="/" component={Home}/>
<Route>
<Redirect to="/"/>
</Route>
</Switch>
</Layout>;

View file

@ -1,5 +1,12 @@
import * as React from "react";
import { IColumnVisibility, ILanguage, ILicense, IList, IMaintainer, ISoftware, ISyntax, ITag } from "./interfaces";
import { IColumnVisibility } from "./interfaces/IColumnVisibility";
import { ILanguage } from "./interfaces/ILanguage";
import { ILicense } from "./interfaces/ILicense";
import { IList } from "./interfaces/IList";
import { IMaintainer } from "./interfaces/IMaintainer";
import { ISoftware } from "./interfaces/ISoftware";
import { ISyntax } from "./interfaces/ISyntax";
import { ITag } from "./interfaces/ITag";
import { ListsTable, Oneliner } from "./components";
const columnVisibilityDefaults: IColumnVisibility[] = [
@ -60,33 +67,33 @@ export class Home extends React.Component<IProps, IState> {
render() {
return <div>
<Oneliner listCount={this.props.lists.length}/* ruleCount={this.props.ruleCount}*//>
<ListsTable {...this.props} {...this.state}/>
{this.renderColumnVisibilityCheckboxes()}
</div>;
<Oneliner listCount={this.props.lists.length}/* ruleCount={this.props.ruleCount}*/ />
<ListsTable {...this.props} {...this.state} />
{this.renderColumnVisibilityCheckboxes()}
</div>;
};
renderColumnVisibilityCheckboxes() {
return this.props.lists.length > 0
? <div className="d-none d-md-block text-right">
Visible:&nbsp;&nbsp;{this.state.columnVisibility.map(
(c: IColumnVisibility, i: number) => this.renderColumnVisibilityCheckbox(c, i))}
</div>
: null;
? <div className="d-none d-md-block text-right">
Visible:&nbsp;&nbsp;{this.state.columnVisibility.map(
(c: IColumnVisibility, i: number) => this.renderColumnVisibilityCheckbox(c, i))}
</div>
: null;
};
renderColumnVisibilityCheckbox(props: IColumnVisibility, key: number) {
return <div className="form-check form-check-inline" key={key}>
<input className="form-check-input"
type="checkbox"
id={`checkbox${props.column.replace(/\s+/g, "")}`}
defaultChecked={props.visible}
onChange={() => this.checkColumn(props)}/>
<label className="form-check-label"
htmlFor={`checkbox${props.column.replace(/\s+/g, "")}`}>
{props.column}
</label>
</div>;
<input className="form-check-input"
type="checkbox"
id={`checkbox${props.column.replace(/\s+/g, "")}`}
defaultChecked={props.visible}
onChange={() => this.checkColumn(props)} />
<label className="form-check-label"
htmlFor={`checkbox${props.column.replace(/\s+/g, "")}`}>
{props.column}
</label>
</div>;
};
checkColumn(props: IColumnVisibility) {

View file

@ -1,6 +1,12 @@
import * as React from "react";
import "isomorphic-fetch";
import { ILanguage, ILicense, IList, IMaintainer, ISoftware, ISyntax, ITag } from "./interfaces";
import { ILanguage } from "./interfaces/ILanguage";
import { ILicense } from "./interfaces/ILicense";
import { IList } from "./interfaces/IList";
import { IMaintainer } from "./interfaces/IMaintainer";
import { ISoftware } from "./interfaces/ISoftware";
import { ISyntax } from "./interfaces/ISyntax";
import { ITag } from "./interfaces/ITag";
import { Home } from "./Home";
interface IState {
@ -89,6 +95,6 @@ export class HomeContainer extends React.Component<{}, IState> {
};
render() {
return <Home {...this.state}/>;
return <Home {...this.state} />;
};
};

View file

@ -1,4 +1,8 @@
import { ILanguage, ILicense, IMaintainer, ISyntax, ITag } from "../../interfaces";
import { ILanguage } from "../interfaces/ILanguage";
import { ILicense } from "../interfaces/ILicense";
import { IMaintainer } from "../interfaces/IMaintainer";
import { ISyntax } from "../interfaces/ISyntax";
import { ITag } from "../interfaces/ITag";
export interface IListDetails {
id: number;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { ITag } from "../interfaces";
import { ITag } from "../interfaces/ITag";
import { getContrast } from "../../../utils";
interface IProps {

View file

@ -1,6 +1,7 @@
import * as React from "react";
import { IColumnVisibility, ISoftware } from "../../interfaces";
import { IListDetails } from "./IListDetails";
import { ISoftware } from "../../interfaces/ISoftware";
import { IColumnVisibility } from "../../interfaces/IColumnVisibility";
import { IListDetails } from "../IListDetails";
import { InfoCard } from "./infoCard";
import { LinkButtonGroup } from "./LinkButtonGroup";
import { MaintainersInfoCard } from "./maintainersInfoCard";
@ -16,11 +17,11 @@ export const DetailsExpander = (props: IProps) =>
<div className="card-body p-2">
<div className="container m-0">
<div className="row">
<InfoCard columnVisibility={props.columnVisibility} software={props.software} {...props.list}/>
<LinkButtonGroup {...props.list}/>
<InfoCard columnVisibility={props.columnVisibility} software={props.software} {...props.list} />
<LinkButtonGroup {...props.list} />
</div>
<div className="row">
<MaintainersInfoCard maintainers={props.list.maintainers}/>
<MaintainersInfoCard maintainers={props.list.maintainers} />
</div>
</div>
</div>

View file

@ -1,7 +1,5 @@
import { DetailsExpander } from "./DetailsExpander";
import { IListDetails } from "./IListDetails";
export {
DetailsExpander,
IListDetails
};
DetailsExpander
};

View file

@ -1,15 +1,19 @@
import * as React from "react";
import { IColumnVisibility } from "../../../interfaces";
import { ILanguage, ILicense, ISoftware, ISyntax, ITag } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { ILanguage } from "../../../interfaces/ILanguage";
import { ILicense, } from "../../../interfaces/ILicense";
import { ISoftware, } from "../../../interfaces/ISoftware";
import { ISyntax, } from "../../../interfaces/ISyntax";
import { ITag } from "../../../interfaces/ITag";
import { Description } from "./Description";
import { Languages } from "./Languages";
import { License } from "./License";
import { PublishedDate } from "./PublishedDate";
import { RuleCount } from "./RuleCount";
// import { RuleCount } from "./RuleCount";
import { SoftwareIcon } from "../../softwareIcon";
import { Syntax } from "./Syntax";
import { TagGroup } from "../../TagGroup"
import { UpdatedDate } from "./UpdatedDate";
// import { UpdatedDate } from "./UpdatedDate";
interface IProps {
columnVisibility: IColumnVisibility[];
@ -29,26 +33,26 @@ interface IProps {
export const InfoCard = (props: IProps) =>
<div className="col-9">
{props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Tags")[0].visible
? null
: <TagGroup tags={props.tags}/>}
? null
: <TagGroup tags={props.tags} />}
<div>
{props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Software")[0].visible
? null
: props.syntax
? props.software.filter((s: ISoftware) => s.syntaxIds.indexOf(props.syntax.id) > -1)
.map((s: ISoftware, i: number) => <SoftwareIcon id={s.id} key={i}/>)
: null}
? null
: props.syntax
? props.software.filter((s: ISoftware) => s.syntaxIds.indexOf(props.syntax.id) > -1)
.map((s: ISoftware, i: number) => <SoftwareIcon id={s.id} key={i} />)
: null}
</div>
<Description {...props} url={props.descriptionSourceUrl}/>
<Description {...props} url={props.descriptionSourceUrl} />
<ul className="list-group list-group-flush">
<Languages {...props}/>
<Languages {...props} />
{/*{props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Rules")[0].visible
? null
: <RuleCount {...props}/>}
{props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Updated")[0].visible
? null
: <UpdatedDate {...props}/>}*/}
<PublishedDate date={props.publishedDate}/>
<PublishedDate date={props.publishedDate} />
<Syntax {...props} />
{props.columnVisibility.filter((c: IColumnVisibility) => c.column === "License")[0].visible
? null

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { ILanguage } from "../../../interfaces";
import { ILanguage } from "../../../interfaces/ILanguage";
interface IProps {
languages: ILanguage[];
@ -7,14 +7,14 @@ interface IProps {
export const Languages = (props: IProps) =>
props.languages && props.languages.length > 0
? props.languages.length > 1
? <li className="list-group-item">
<p className="m-0">Languages:</p>
<ul>
{props.languages.map((language: ILanguage, i: number) => <li key={i}>{language.name}</li>)}
</ul>
</li>
: <li className="list-group-item">
<p>Language: {props.languages[0].name}</p>
</li>
: null;
? props.languages.length > 1
? <li className="list-group-item">
<p className="m-0">Languages:</p>
<ul>
{props.languages.map((language: ILanguage, i: number) => <li key={i}>{language.name}</li>)}
</ul>
</li>
: <li className="list-group-item">
<p>Language: {props.languages[0].name}</p>
</li>
: null;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { ILicense } from "../../../interfaces";
import { ILicense } from "../../../interfaces/ILicense";
interface IProps {
license: ILicense;
@ -7,11 +7,11 @@ interface IProps {
export const License = (props: IProps) =>
props.license.name
? (props.license.descriptionUrl
? <li className="list-group-item">
<p>License: <a href={props.license.descriptionUrl}>{props.license.name}</a></p>
</li>
: <li className="list-group-item">
<p>License: {props.license.name}</p>
</li>)
: null;
? (props.license.descriptionUrl
? <li className="list-group-item">
<p>License: <a href={props.license.descriptionUrl}>{props.license.name}</a></p>
</li>
: <li className="list-group-item">
<p>License: {props.license.name}</p>
</li>)
: null;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import * as moment from "moment";
import moment from 'moment';
interface IProps {
date: string;
@ -7,7 +7,7 @@ interface IProps {
export const PublishedDate = (props: IProps) =>
props.date
? <li className="list-group-item">
<p>Published: {moment(props.date).format("l")}</p>
</li>
: null;
? <li className="list-group-item">
<p>Published: {moment(props.date).format("l")}</p>
</li>
: null;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { ISyntax } from "../../../interfaces";
import { ISyntax } from "../../../interfaces/ISyntax";
interface IProps {
syntax: ISyntax;
@ -7,11 +7,11 @@ interface IProps {
export const Syntax = (props: IProps) =>
props.syntax
? (props.syntax.definitionUrl
? <li className="list-group-item">
<p>Syntax: <a href={props.syntax.definitionUrl}>{props.syntax.name}</a></p>
</li>
: <li className="list-group-item">
<p>Syntax: {props.syntax.name}</p>
</li>)
: null;
? (props.syntax.definitionUrl
? <li className="list-group-item">
<p>Syntax: <a href={props.syntax.definitionUrl}>{props.syntax.name}</a></p>
</li>
: <li className="list-group-item">
<p>Syntax: {props.syntax.name}</p>
</li>)
: null;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import * as moment from "moment";
import moment from 'moment';
interface IProps {
updatedDate: string;
@ -7,9 +7,9 @@ interface IProps {
export const UpdatedDate = (props: IProps) =>
props.updatedDate
? <li className="list-group-item">
<p>Updated: {moment(props.updatedDate).isValid()
? moment(props.updatedDate).format("l")
: "N/A"}</p>
</li>
: null;
? <li className="list-group-item">
<p>Updated: {moment(props.updatedDate).isValid()
? moment(props.updatedDate).format("l")
: "N/A"}</p>
</li>
: null;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { IMaintainer } from "../../../interfaces";
import { IMaintainer } from "../../../interfaces/IMaintainer";
import { MaintainerAdditionalLists } from "./MaintainerAdditionalLists";
import { MaintainerLinkButtonGroup } from "./MaintainerLinkButtonGroup";
@ -9,15 +9,15 @@ interface IProps {
export const MaintainerInfoCard = (props: IProps) =>
props.maintainer.name
? <div className="card">
<div className="card-body">
<h3 className="card-header">Maintained by {props.maintainer.name}</h3>
<div className="container pt-1">
<div className="row">
<MaintainerAdditionalLists/>
<MaintainerLinkButtonGroup {...props.maintainer}/>
</div>
</div>
</div>
</div>
: null;
? <div className="card">
<div className="card-body">
<h3 className="card-header">Maintained by {props.maintainer.name}</h3>
<div className="container pt-1">
<div className="row">
<MaintainerAdditionalLists />
<MaintainerLinkButtonGroup {...props.maintainer} />
</div>
</div>
</div>
</div>
: null;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { IMaintainer } from "../../../interfaces";
import { IMaintainer } from "../../../interfaces/IMaintainer";
import { MaintainerInfoCard } from "./MaintainerInfoCard";
interface IProps {
@ -8,7 +8,7 @@ interface IProps {
export const MaintainersInfoCard = (props: IProps) =>
props.maintainers && props.maintainers.length > 0
? <div className="w-100">
{props.maintainers.map((m: IMaintainer, i: number) => <MaintainerInfoCard maintainer={m} key={i}/>)}
</div>
: null;
? <div className="w-100">
{props.maintainers.map((m: IMaintainer, i: number) => <MaintainerInfoCard maintainer={m} key={i} />)}
</div>
: null;

View file

@ -50,7 +50,7 @@ if (props.url.indexOf(".tpl") > 0)
{
title = `${titlePrefix}Subscribe to ${props.name} with Little Snitch's rule group subscription feature.`;
} else {
title = `${titlePrefix}Subscribe to ${props.name} with a browser extension supporting the \"abp:\" protocol (e.g. uBlock Origin, Adblock Plus).`;
title = `${titlePrefix}Subscribe to ${props.name} with a browser extension supporting the "abp:" protocol (e.g. uBlock Origin, Adblock Plus).`;
};
return props.url

View file

@ -1,5 +1,12 @@
import * as React from "react";
import { IColumnVisibility, ILanguage, ILicense, IList, IMaintainer, ISoftware, ISyntax, ITag } from "../../interfaces";
import { IColumnVisibility } from "../../interfaces/IColumnVisibility";
import { ILanguage } from "../../interfaces/ILanguage";
import { ILicense } from "../../interfaces/ILicense";
import { IList } from "../../interfaces/IList";
import { IMaintainer } from "../../interfaces/IMaintainer";
import { ISoftware } from "../../interfaces/ISoftware";
import { ISyntax } from "../../interfaces/ISyntax";
import { ITag } from "../../interfaces/ITag";
import "../../../../utils/loader.css";
import ReactTable from "react-table";
import "react-table/react-table.css";
@ -16,7 +23,7 @@ import {
Tags,
//UpdatedDate
} from "./columns";
import { IListDetails } from "../../components/detailsExpander";
import { IListDetails } from "../IListDetails";
import { DetailsExpander } from "../../components";
interface IProps {
@ -33,36 +40,36 @@ interface IProps {
export const ListsTable = (props: IProps) =>
props.languages.length > 0 && props.lists.length > 0 && props.software.length > 0 && props.tags.length > 0
? <ReactTable
data={props.lists}
defaultPageSize={props.pageSize}
showPageSizeOptions={false}
columns={[
Name,
Software(props.columnVisibility, props.software),
Languages(props.columnVisibility, props.languages),
Tags(props.columnVisibility, props.tags),
//UpdatedDate(props.columnVisibility),
//RuleCount(props.columnVisibility),
License(props.columnVisibility, props.licenses),
Maintainers(props.columnVisibility, props.maintainers),
SubscribeButton(props.columnVisibility),
DetailsButton
]}
defaultSorted={[{ id: "name" }]}
SubComponent={(r: any) =>
<DetailsExpander columnVisibility={props.columnVisibility}
list={mapListDetails(({
list: r.original,
languages: props.languages,
licenses: props.licenses,
maintainers: props.maintainers,
syntaxes: props.syntaxes,
tags: props.tags
} as ICreateListDtoProps))}
software={props.software}/>}
className="-striped -highlight"/>
: <div className="loader">Loading...</div>;
? <ReactTable
data={props.lists}
defaultPageSize={props.pageSize}
showPageSizeOptions={false}
columns={[
Name,
Software(props.columnVisibility, props.software),
Languages(props.columnVisibility, props.languages),
Tags(props.columnVisibility, props.tags),
//UpdatedDate(props.columnVisibility),
//RuleCount(props.columnVisibility),
License(props.columnVisibility, props.licenses),
Maintainers(props.columnVisibility, props.maintainers),
SubscribeButton(props.columnVisibility),
DetailsButton
]}
defaultSorted={[{ id: "name", desc: false }]}
SubComponent={(r: any) =>
<DetailsExpander columnVisibility={props.columnVisibility}
list={mapListDetails(({
list: r.original,
languages: props.languages,
licenses: props.licenses,
maintainers: props.maintainers,
syntaxes: props.syntaxes,
tags: props.tags
} as ICreateListDtoProps))}
software={props.software} />}
className="-striped -highlight" />
: <div className="loader">Loading...</div>;
interface ICreateListDtoProps {
list: IList;
@ -74,31 +81,31 @@ interface ICreateListDtoProps {
};
const mapListDetails = (props: ICreateListDtoProps): IListDetails =>
({
id: props.list.id,
chatUrl: props.list.chatUrl,
description: props.list.description,
descriptionSourceUrl: props.list.descriptionSourceUrl,
donateUrl: props.list.donateUrl,
emailAddress: props.list.emailAddress,
forumUrl: props.list.forumUrl,
homeUrl: props.list.homeUrl,
issuesUrl: props.list.issuesUrl,
languages: props.list.languageIds
? props.languages.filter((l: ILanguage) => props.list.languageIds.indexOf(l.id) > -1)
: undefined,
license: props.licenses.filter((l: ILicense) => props.list.licenseId === l.id)[0],
maintainers: props.list.maintainerIds
? props.maintainers.filter((m: IMaintainer) => props.list.maintainerIds.indexOf(m.id) > -1)
: undefined,
name: props.list.name,
policyUrl: props.list.policyUrl,
publishedDate: props.list.publishedDate,
//ruleCount: props.list.ruleCount,
submissionUrl: props.list.submissionUrl,
syntax: props.syntaxes.filter((s: ISyntax) => props.list.syntaxId === s.id)[0],
tags: props.list.tagIds ? props.tags.filter((t: ITag) => props.list.tagIds.indexOf(t.id) > -1) : undefined,
//updatedDate: props.list.updatedDate,
viewUrl: props.list.viewUrl,
viewUrlMirrors: props.list.viewUrlMirrors
} as IListDetails);
({
id: props.list.id,
chatUrl: props.list.chatUrl,
description: props.list.description,
descriptionSourceUrl: props.list.descriptionSourceUrl,
donateUrl: props.list.donateUrl,
emailAddress: props.list.emailAddress,
forumUrl: props.list.forumUrl,
homeUrl: props.list.homeUrl,
issuesUrl: props.list.issuesUrl,
languages: props.list.languageIds
? props.languages.filter((l: ILanguage) => props.list.languageIds.indexOf(l.id) > -1)
: undefined,
license: props.licenses.filter((l: ILicense) => props.list.licenseId === l.id)[0],
maintainers: props.list.maintainerIds
? props.maintainers.filter((m: IMaintainer) => props.list.maintainerIds.indexOf(m.id) > -1)
: undefined,
name: props.list.name,
policyUrl: props.list.policyUrl,
publishedDate: props.list.publishedDate,
//ruleCount: props.list.ruleCount,
submissionUrl: props.list.submissionUrl,
syntax: props.syntaxes.filter((s: ISyntax) => props.list.syntaxId === s.id)[0],
tags: props.list.tagIds ? props.tags.filter((t: ITag) => props.list.tagIds.indexOf(t.id) > -1) : undefined,
//updatedDate: props.list.updatedDate,
viewUrl: props.list.viewUrl,
viewUrlMirrors: props.list.viewUrlMirrors
} as IListDetails);

View file

@ -1,6 +1,7 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { IColumnVisibility, ILanguage } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { ILanguage } from "../../../interfaces/ILanguage";
export const Languages = (columnVisibility: IColumnVisibility[], languages: ILanguage[]) => {
const languagesSorted = languages.sort((a, b) => a.name.localeCompare(b.name));
@ -9,7 +10,7 @@ export const Languages = (columnVisibility: IColumnVisibility[], languages: ILan
accessor: "languageIds",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r),
Filter: ({ onChange, filter }: any) => Filter({ onChange, filter }, languagesSorted),
Filter: ({ onChange, filter }: any) => filterLanguages({ onChange, filter }, languagesSorted),
sortMethod: (a: number[], b: number[]) => sortMethod(a, b, languagesSorted),
Cell: (c: any) => Cell(c.value, languagesSorted),
style: { whiteSpace: "inherit" },
@ -21,23 +22,23 @@ export const Languages = (columnVisibility: IColumnVisibility[], languages: ILan
const filterMethod = (f: Filter, r: any[]): boolean => {
const listLanguageIds = r[f.id as any];
return f.value === "any" ||
(listLanguageIds
? listLanguageIds.join(",").split(",").includes(f.value)
: f.value === "none");
(listLanguageIds
? listLanguageIds.join(",").split(",").includes(f.value)
: f.value === "none");
};
const Filter = (props: any, languages: ILanguage[]) =>
const filterLanguages = (props: any, languages: ILanguage[]) =>
<select onChange={(event: any) => props.onChange(event.target.value)}
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
<option value="any">Any</option>
<option value="none">None</option>
{languages.length > 0
? languages.map((l: ILanguage, i: number) =>
<option value={l.id} key={i}>
{l.name} ({l.filterListIds ? l.filterListIds.length : 0})
? languages.map((l: ILanguage, i: number) =>
<option value={l.id} key={i}>
{l.name} ({l.filterListIds ? l.filterListIds.length : 0})
</option>)
: null}
: null}
</select>;
const sortMethod = (a: number[], b: number[], languages: ILanguage[]) => {
@ -58,14 +59,14 @@ const sortMethod = (a: number[], b: number[], languages: ILanguage[]) => {
const Cell = (languageIds: number[], languages: ILanguage[]) =>
languageIds
? <div className="fl-wrap-cell">
{languageIds.map((id: number, i: number) => {
const language = languages.filter((l: ILanguage) => l.id === id)[0];
return <span className="badge badge-secondary"
title={language.name}
key={i}>
{language.iso6391}
</span>;
})}
</div>
: null;
? <div className="fl-wrap-cell">
{languageIds.map((id: number, i: number) => {
const language = languages.filter((l: ILanguage) => l.id === id)[0];
return <span className="badge badge-secondary"
title={language.name}
key={i}>
{language.iso6391}
</span>;
})}
</div>
: null;

View file

@ -1,19 +1,20 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { IColumnVisibility, ILicense } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { ILicense } from "../../../interfaces/ILicense";
export const License = (columnVisibility: IColumnVisibility[], licenses: ILicense[]) =>
({
Header: <span title="A legal document governing the use or redistribution of a FilterList.">License</span>,
accessor: "licenseId",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, licenses),
Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, licenses),
sortMethod: (a: number, b: number) => sortMethod(a, b, licenses),
Cell: (c: any) => Cell(c.value, licenses),
width: 75,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "License")[0].visible
} as Column);
({
Header: <span title="A legal document governing the use or redistribution of a FilterList.">License</span>,
accessor: "licenseId",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, licenses),
Filter: ({ filter, onChange }: any) => filterLicenses({ onChange, filter }, licenses),
sortMethod: (a: number, b: number) => sortMethod(a, b, licenses),
Cell: (c: any) => Cell(c.value, licenses),
width: 75,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "License")[0].visible
} as Column);
const filterMethod = (f: Filter, r: any[], licenses: ILicense[]): boolean => {
const listLicenseId: number = r[f.id as any];
@ -27,19 +28,19 @@ const filterMethod = (f: Filter, r: any[], licenses: ILicense[]): boolean => {
}
};
const Filter = (props: any, licenses: ILicense[]) =>
const filterLicenses = (props: any, licenses: ILicense[]) =>
<select
onChange={(event: any) => props.onChange(event.target.value)}
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
<option value="any">Any</option>
{licenses.length > 0
? licenses.sort((a, b) => a.name.replace(/['"]+/g, "").localeCompare(b.name.replace(/['"]+/g, ""))).map(
(l: ILicense, i: number) =>
<option value={l.id} key={i}>
{l.name} ({l.filterListIds ? l.filterListIds.length : 0})
? licenses.sort((a, b) => a.name.replace(/['"]+/g, "").localeCompare(b.name.replace(/['"]+/g, ""))).map(
(l: ILicense, i: number) =>
<option value={l.id} key={i}>
{l.name} ({l.filterListIds ? l.filterListIds.length : 0})
</option>)
: null}
: null}
</select>;
const sortMethod = (a: number, b: number, licenses: ILicense[]) => {
@ -59,10 +60,10 @@ const sortMethod = (a: number, b: number, licenses: ILicense[]) => {
const Cell = (licenseId: number, licenses: ILicense[]) => {
const license = licenses.filter((l: ILicense) => licenseId === l.id)[0];
return license
? <div>
<span title={license.name}>
{license.descriptionUrl ? <a href={license.descriptionUrl}>{license.name}</a> : license.name}
</span>
</div>
: null;
? <div>
<span title={license.name}>
{license.descriptionUrl ? <a href={license.descriptionUrl}>{license.name}</a> : license.name}
</span>
</div>
: null;
};

View file

@ -1,31 +1,32 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { IColumnVisibility, IMaintainer } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { IMaintainer } from "../../../interfaces/IMaintainer";
export const Maintainers = (columnVisibility: IColumnVisibility[], maintainers: IMaintainer[]) =>
({
Header: <span title="Individuals, groups, or organizations who maintain the FilterList.">Maintainers</span>,
accessor: "maintainerIds",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, maintainers),
Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, maintainers),
sortMethod: (a: number[], b: number[]) => sortMethod(a, b, maintainers),
Cell: (c: any) => Cell(c.value, maintainers),
width: 140,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Maintainers")[0].visible
} as Column);
({
Header: <span title="Individuals, groups, or organizations who maintain the FilterList.">Maintainers</span>,
accessor: "maintainerIds",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, maintainers),
Filter: ({ filter, onChange }: any) => filterMaintainers({ onChange, filter }, maintainers),
sortMethod: (a: number[], b: number[]) => sortMethod(a, b, maintainers),
Cell: (c: any) => Cell(c.value, maintainers),
width: 140,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Maintainers")[0].visible
} as Column);
const filterMethod = (f: Filter, r: any[], maintainers: IMaintainer[]): boolean => {
const listMaintainerIds: number[] = r[f.id as any];
return f.value === "any" ||
(listMaintainerIds
? f.value === "none"
? false
: listMaintainerIds.indexOf(maintainers.filter((m: IMaintainer) => m.id === parseInt(f.value))[0].id) > -1
: f.value === "none");
(listMaintainerIds
? f.value === "none"
? false
: listMaintainerIds.indexOf(maintainers.filter((m: IMaintainer) => m.id === parseInt(f.value))[0].id) > -1
: f.value === "none");
};
const Filter = (props: any, maintainers: IMaintainer[]) =>
const filterMaintainers = (props: any, maintainers: IMaintainer[]) =>
<select
onChange={(event: any) => props.onChange(event.target.value)}
style={{ width: "100%" }}
@ -33,12 +34,12 @@ const Filter = (props: any, maintainers: IMaintainer[]) =>
<option value="any">Any</option>
<option value="none">None</option>
{maintainers.length > 0
? maintainers.sort((a, b) => a.name.localeCompare(b.name))
.map((m: IMaintainer, i: number) =>
<option value={m.id} key={i}>
{m.name} ({m.filterListIds ? m.filterListIds.length : 0})
? maintainers.sort((a, b) => a.name.localeCompare(b.name))
.map((m: IMaintainer, i: number) =>
<option value={m.id} key={i}>
{m.name} ({m.filterListIds ? m.filterListIds.length : 0})
</option>)
: null}
: null}
</select>;
const sortMethod = (a: number[], b: number[], maintainers: IMaintainer[]) => {
@ -57,12 +58,12 @@ const sortMethod = (a: number[], b: number[], maintainers: IMaintainer[]) => {
const Cell = (maintainerIds: number[], maintainers: IMaintainer[]) =>
maintainerIds
? <div className="fl-wrap-cell">
{maintainers.filter((m: IMaintainer) => maintainerIds.indexOf(m.id) > -1)
.map((m: IMaintainer, i: number) => {
return m.homeUrl
? <a href={m.homeUrl} key={i}>{m.name}</a>
: <span key={i}>{m.name}</span>;
}).reduce(((prev: JSX.Element, curr: JSX.Element): any => [prev, ", ", curr]) as any)}
</div>
: null;
? <div className="fl-wrap-cell">
{maintainers.filter((m: IMaintainer) => maintainerIds.indexOf(m.id) > -1)
.map((m: IMaintainer, i: number) => {
return m.homeUrl
? <a href={m.homeUrl} key={i}>{m.name}</a>
: <span key={i}>{m.name}</span>;
}).reduce(((prev: JSX.Element, curr: JSX.Element): any => [prev, ", ", curr]) as any)}
</div>
: null;

View file

@ -1,9 +1,9 @@
import * as React from "react";
import { Column } from "react-table";
import { IColumnVisibility } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
export const RuleCount = (columnVisibility: IColumnVisibility[]) =>
({
({
Header: <span title="The number of rules in the FilterList.">Rules</span>,
accessor: "ruleCount",
sortMethod: (a: string, b: string) => sortMethod(a, b),
@ -11,10 +11,10 @@ export const RuleCount = (columnVisibility: IColumnVisibility[]) =>
style: { whiteSpace: "inherit" },
width: 85,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Rules")[0].visible
} as Column);
} as Column);
const sortMethod = (a: string, b: string) =>
a
a
? b
? a > b
? -1
@ -23,6 +23,6 @@ const sortMethod = (a: string, b: string) =>
: 1;
const Cell = (ruleCount: number) =>
ruleCount
? <span>{ ruleCount.toLocaleString() }</span>
ruleCount
? <span>{ruleCount.toLocaleString()}</span>
: null;

View file

@ -1,6 +1,7 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { IColumnVisibility, ISoftware } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { ISoftware } from "../../../interfaces/ISoftware";
import { SoftwareIcon } from "../../softwareIcon";
export const Software = (columnVisibility: IColumnVisibility[], software: ISoftware[]) => {
@ -11,7 +12,7 @@ export const Software = (columnVisibility: IColumnVisibility[], software: ISoftw
accessor: "syntaxId",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, softwareSorted),
Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, softwareSorted),
Filter: ({ filter, onChange }: any) => filterSoftware({ onChange, filter }, softwareSorted),
sortMethod: (a: number, b: number) => sortMethod(a, b, softwareSorted),
Cell: (c: any) => Cell(c.value, software),
width: 155,
@ -27,15 +28,15 @@ const filterMethod = (f: Filter, r: any[], software: ISoftware[]): boolean => {
return isAny || (listSyntaxId ? isMatch : false);
};
const Filter = (props: any, software: ISoftware[]) =>
const filterSoftware = (props: any, software: ISoftware[]) =>
<select
onChange={(event: any) => props.onChange(event.target.value)}
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
<option value="any">Any</option>
{software.length > 0
? software.map((s: ISoftware, i: number) => <option value={s.id} key={i}>{s.name}</option>)
: null}
? software.map((s: ISoftware, i: number) => <option value={s.id} key={i}>{s.name}</option>)
: null}
</select>;
const sortMethod = (a: number, b: number, software: ISoftware[]) => {
@ -62,13 +63,13 @@ const sortMethod = (a: number, b: number, software: ISoftware[]) => {
const Cell = (listSyntaxId: number, software: ISoftware[]) =>
listSyntaxId
? <div className="fl-wrap-cell">
{software.filter((s: ISoftware) => s.syntaxIds.indexOf(listSyntaxId) > -1)
.map((s: ISoftware, i: number) =>
s.homeUrl
? <a href={s.homeUrl} key={i}>
<SoftwareIcon id={s.id}/>
</a>
: <SoftwareIcon id={s.id} key={i}/>)}
</div>
: null;
? <div className="fl-wrap-cell">
{software.filter((s: ISoftware) => s.syntaxIds.indexOf(listSyntaxId) > -1)
.map((s: ISoftware, i: number) =>
s.homeUrl
? <a href={s.homeUrl} key={i}>
<SoftwareIcon id={s.id} />
</a>
: <SoftwareIcon id={s.id} key={i} />)}
</div>
: null;

View file

@ -1,17 +1,17 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { IColumnVisibility } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { SubscribeButtonGroup } from "../../linkButtons";
export const SubscribeButton = (columnVisibility: IColumnVisibility[]) => ({
Header: <span title={`Subscribe to the list with a browser extension supporting the "abp:" protocol (e.g. uBlock Origin, Adblock Plus)`}>
Subscribe
Subscribe
</span>,
accessor: "viewUrl",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r),
sortMethod: (a: string, b: string) => sortMethod(a, b),
Cell: (c: any) => <SubscribeButtonGroup name={c.row.name} url={c.value} urlMirrors={c.row.viewUrlMirrors}/>,
Cell: (c: any) => <SubscribeButtonGroup name={c.row.name} url={c.value} urlMirrors={c.row.viewUrlMirrors} />,
style: { textAlign: "center" },
width: 110,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Subscribe")[0].visible

View file

@ -1,6 +1,7 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { IColumnVisibility, ISyntax } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { ISyntax } from "../../../interfaces/ISyntax";
//TODO: https://github.com/collinbarrett/FilterLists/issues/488
export const Syntax = (columnVisibility: IColumnVisibility[], syntaxes: ISyntax[]) => ({
@ -8,7 +9,7 @@ export const Syntax = (columnVisibility: IColumnVisibility[], syntaxes: ISyntax[
accessor: "syntaxId",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, syntaxes),
Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, syntaxes),
Filter: ({ filter, onChange }: any) => filterSyntaxes({ onChange, filter }, syntaxes),
Cell: (c: any) => Cell(c.value, syntaxes),
width: 155,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Syntax")[0].visible
@ -21,26 +22,26 @@ const filterMethod = (f: Filter, r: any[], syntaxes: ISyntax[]): boolean => {
} else if (listSyntaxId) {
const syntaxFiltered = syntaxes.filter((s: ISyntax) => s.id === parseInt(f.value));
return syntaxFiltered[0].id
? syntaxFiltered[0].id === listSyntaxId
: false;
? syntaxFiltered[0].id === listSyntaxId
: false;
} else {
return false;
}
};
const Filter = (props: any, syntaxes: ISyntax[]) =>
const filterSyntaxes = (props: any, syntaxes: ISyntax[]) =>
<select
onChange={(event: any) => props.onChange(event.target.value)}
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
<option value="any">Any</option>
{syntaxes.length > 0
? syntaxes.sort((a, b) => a.name.localeCompare(b.name)).map(
(s: ISyntax, i: number) => <option value={s.id} key={i}>{s.name}</option>)
: null}
? syntaxes.sort((a, b) => a.name.localeCompare(b.name)).map(
(s: ISyntax, i: number) => <option value={s.id} key={i}>{s.name}</option>)
: null}
</select>;
const Cell = (listSyntaxId: number, syntaxes: ISyntax[]) =>
listSyntaxId
? syntaxes.filter((s: ISyntax) => s.id === listSyntaxId)[0].name
: null;
? syntaxes.filter((s: ISyntax) => s.id === listSyntaxId)[0].name
: null;

View file

@ -1,7 +1,8 @@
import * as React from "react";
import { Column, Filter } from "react-table";
import { TagGroup } from "../../TagGroup";
import { IColumnVisibility, ITag } from "../../../interfaces";
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
import { ITag } from "../../../interfaces/ITag";
export const Tags = (columnVisibility: IColumnVisibility[], tags: ITag[]) => {
const tagsSorted = tags.sort((a: ITag, b: ITag) => a.name.localeCompare(b.name));
@ -11,7 +12,7 @@ export const Tags = (columnVisibility: IColumnVisibility[], tags: ITag[]) => {
accessor: "tagIds",
filterable: true,
filterMethod: (f: Filter, r: any[]) => filterMethod(f, r),
Filter: ({ onChange, filter }: any) => Filter({ onChange, filter }, tagsSorted),
Filter: ({ onChange, filter }: any) => filterTags({ onChange, filter }, tagsSorted),
sortMethod: (a: number[], b: number[]) => sortMethod(a, b, tagsSorted),
Cell: (c: any) => Cell(c.value, tagsSorted),
width: 260,
@ -22,42 +23,42 @@ export const Tags = (columnVisibility: IColumnVisibility[], tags: ITag[]) => {
const filterMethod = (f: Filter, r: any[]): boolean => {
const listTagIds = r[f.id as any];
return f.value === "any" ||
(listTagIds
? listTagIds.join(",").split(",").includes(f.value)
: f.value === "none");
(listTagIds
? listTagIds.join(",").split(",").includes(f.value)
: f.value === "none");
};
const Filter = (props: any, tags: ITag[]) =>
const filterTags = (props: any, tags: ITag[]) =>
<select onChange={(event: any) => props.onChange(event.target.value)}
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
style={{ width: "100%" }}
value={props.filter ? props.filter.value : "any"}>
<option value="any">Any</option>
<option value="none">None</option>
{tags.length > 0
? tags.map((t: ITag, i: number) =>
<option value={t.id} title={t.description} key={i}>
{t.name} ({t.filterListIds ? t.filterListIds.length : 0})
? tags.map((t: ITag, i: number) =>
<option value={t.id} title={t.description} key={i}>
{t.name} ({t.filterListIds ? t.filterListIds.length : 0})
</option>)
: null}
: null}
</select>;
const sortMethod = (a: number[], b: number[], tags: ITag[]): any => {
return a
? b
? a.length === b.length
? tags.filter((t: ITag) => a.indexOf(t.id) > -1).map((t: ITag) => t.name).join()
.toLowerCase() >
tags.filter((t: ITag) => b.indexOf(t.id) > -1).map((t: ITag) => t.name).join().toLowerCase()
? 1
: -1
: a.length > b.length
? -1
: 1
: -1
: 1;
? b
? a.length === b.length
? tags.filter((t: ITag) => a.indexOf(t.id) > -1).map((t: ITag) => t.name).join()
.toLowerCase() >
tags.filter((t: ITag) => b.indexOf(t.id) > -1).map((t: ITag) => t.name).join().toLowerCase()
? 1
: -1
: a.length > b.length
? -1
: 1
: -1
: 1;
};
const Cell = (tagIds: number[], tags: ITag[]) =>
tagIds
? <TagGroup tags={tags.filter((t: ITag) => tagIds.indexOf(t.id) > -1)}/>
: null;
? <TagGroup tags={tags.filter((t: ITag) => tagIds.indexOf(t.id) > -1)} />
: null;

View file

@ -1,33 +1,33 @@
import * as React from "react";
import { Column } from "react-table";
import * as moment from "moment";
import { IColumnVisibility } from "../../../interfaces";
import moment from 'moment';
import { IColumnVisibility } from "../../../interfaces/IColumnVisibility";
export const UpdatedDate = (columnVisibility: IColumnVisibility[]) =>
({
Header: <span title="The estimated date that the FilterList was last updated by the maintainer.">Updated</span>,
accessor: "updatedDate",
sortMethod: (a: string, b: string) => sortMethod(a, b),
Cell: (c: any) => Cell(c.value),
style: { whiteSpace: "inherit" },
width: 100,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Updated")[0].visible
} as Column);
({
Header: <span title="The estimated date that the FilterList was last updated by the maintainer.">Updated</span>,
accessor: "updatedDate",
sortMethod: (a: string, b: string) => sortMethod(a, b),
Cell: (c: any) => Cell(c.value),
style: { whiteSpace: "inherit" },
width: 100,
show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Updated")[0].visible
} as Column);
const sortMethod = (a: string, b: string) =>
a && moment(a).isValid()
? (b && moment(b).isValid()
? (moment(a).isBefore(b)
? 1
: -1)
: -1)
: 1;
? (b && moment(b).isValid()
? (moment(a).isBefore(b)
? 1
: -1)
: -1)
: 1;
const Cell = (updatedDate: string) =>
updatedDate
? <div>
{moment(updatedDate).isValid()
? moment(updatedDate).format("l")
: null}
</div>
: null;
? <div>
{moment(updatedDate).isValid()
? moment(updatedDate).format("l")
: null}
</div>
: null;

View file

@ -1,19 +0,0 @@
import { IColumnVisibility } from "./IColumnVisibility";
import { ILanguage } from "./ILanguage";
import { ILicense } from "./ILicense";
import { IList } from "./IList";
import { IMaintainer } from "./IMaintainer";
import { ISoftware } from "./ISoftware";
import { ISyntax } from "./ISyntax";
import { ITag } from "./ITag";
export {
IColumnVisibility,
ILanguage,
ILicense,
IList,
IMaintainer,
ISoftware,
ISyntax,
ITag
};