mirror of
https://github.com/collinbarrett/FilterLists.git
synced 2026-03-11 09:04:27 +00:00
api details refactor ref #505
This commit is contained in:
parent
0c60eff22b
commit
4a2e49cbf3
49 changed files with 269 additions and 552 deletions
|
|
@ -23,7 +23,7 @@ public async Task<IActionResult> GetAll() =>
|
|||
[HttpGet]
|
||||
[Route("{id}")]
|
||||
public async Task<IActionResult> GetById(int id) =>
|
||||
await Get(() => filterListService.GetDetailsAsync(id), id);
|
||||
await Get(() => filterListService.GetByIdAsync(id), id);
|
||||
|
||||
[HttpGet("seed")]
|
||||
public async Task<IActionResult> Seed() =>
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@ await DbContext.FilterLists
|
|||
.ProjectTo<FilterListDto>(MapConfig)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<ListDetails> GetDetailsAsync(int id) =>
|
||||
public async Task<FilterListDto> GetByIdAsync(int id) =>
|
||||
await DbContext.FilterLists
|
||||
.ProjectTo<ListDetails>(MapConfig)
|
||||
.FirstOrDefaultAsync(l => l.Id == id)
|
||||
.FilterParentListFromMaintainerAdditionalLists();
|
||||
.ProjectTo<FilterListDto>(MapConfig)
|
||||
.FirstOrDefaultAsync(l => l.Id == id);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
|
||||
namespace FilterLists.Services.FilterList
|
||||
{
|
||||
public static class FilterListServiceExtensions
|
||||
{
|
||||
public static async Task<ListDetails> FilterParentListFromMaintainerAdditionalLists(
|
||||
this Task<ListDetails> listDetailsDtos)
|
||||
{
|
||||
foreach (var maintainer in listDetailsDtos.Result.Maintainers)
|
||||
maintainer.AdditionalLists = maintainer
|
||||
.AdditionalLists.Where(additionalList =>
|
||||
additionalList.Id != listDetailsDtos.Result.Id)
|
||||
.ToList();
|
||||
return await listDetailsDtos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.MappingProfiles
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListDetailsDtoMappingProfile : Profile
|
||||
{
|
||||
public ListDetailsDtoMappingProfile() =>
|
||||
CreateMap<Data.Entities.FilterList, ListDetails>()
|
||||
.ForMember(dest => dest.Id,
|
||||
opt => opt.MapFrom(src =>
|
||||
(int)src.Id))
|
||||
.ForMember(dest => dest.Languages,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.FilterListLanguages.Select(la => la.Language.Name)))
|
||||
.ForMember(dest => dest.Maintainers,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.FilterListMaintainers.Select(m => m.Maintainer)))
|
||||
.ForMember(dest => dest.Tags,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.FilterListTags.Select(m => m.Tag)))
|
||||
.ForMember(dest => dest.RuleCount,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.Snapshots
|
||||
.Count(s => s.WasSuccessful) > 0
|
||||
? src.Snapshots
|
||||
.Where(s => s.WasSuccessful)
|
||||
.OrderByDescending(s => s.CreatedDateUtc)
|
||||
.FirstOrDefault()
|
||||
.SnapshotRules
|
||||
.Count
|
||||
: 0))
|
||||
.ForMember(dest => dest.UpdatedDate,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.DiscontinuedDate ??
|
||||
(src.Snapshots
|
||||
.Count(s => s.WasSuccessful && s.Md5Checksum != null) >= 2
|
||||
? src.Snapshots
|
||||
.Where(s => s.WasSuccessful && s.Md5Checksum != null)
|
||||
.Select(s => s.CreatedDateUtc)
|
||||
.OrderByDescending(c => c)
|
||||
.FirstOrDefault()
|
||||
: null)))
|
||||
.ForMember(dest => dest.ViewUrl,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.Snapshots
|
||||
.Where(s => s.WasSuccessful)
|
||||
.OrderByDescending(s => s.CreatedDateUtc)
|
||||
.FirstOrDefault()
|
||||
.WaybackUrl ?? src.ViewUrl));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.MappingProfiles
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListMaintainerDtoMappingProfile : Profile
|
||||
{
|
||||
public ListMaintainerDtoMappingProfile() =>
|
||||
CreateMap<Data.Entities.Maintainer, ListMaintainerDto>()
|
||||
.ForMember(dest => dest.Id,
|
||||
opt => opt.MapFrom(src =>
|
||||
(int)src.Id))
|
||||
.ForMember(dest => dest.AdditionalLists,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.FilterListMaintainers.Select(lm => lm.FilterList)));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.MappingProfiles
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListSyntaxDtoMappingProfile : Profile
|
||||
{
|
||||
public ListSyntaxDtoMappingProfile() =>
|
||||
CreateMap<Data.Entities.Syntax, ListSyntaxDto>()
|
||||
.ForMember(dest => dest.SupportedSoftware,
|
||||
opt => opt.MapFrom(src =>
|
||||
src.SoftwareSyntaxes
|
||||
.Select(ss => ss.Software)
|
||||
.OrderBy(s => s.Name)));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using AutoMapper;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.MappingProfiles
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListTagDtoMappingProfile : Profile
|
||||
{
|
||||
public ListTagDtoMappingProfile() =>
|
||||
CreateMap<Data.Entities.Tag, ListTagDto>()
|
||||
.ForMember(dest => dest.ColorHex,
|
||||
opt => opt.MapFrom(src =>
|
||||
TagColors.Colors[(int)src.Id]));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
using AutoMapper;
|
||||
using FilterLists.Data.Entities;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.MappingProfiles
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class MaintainerAdditionalListsDtoMappingProfile : Profile
|
||||
{
|
||||
public MaintainerAdditionalListsDtoMappingProfile() =>
|
||||
CreateMap<Data.Entities.FilterList, MaintainerAdditionalListsDto>()
|
||||
.ForMember(dest => dest.Id,
|
||||
opt => opt.MapFrom(src =>
|
||||
(int)src.Id));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using AutoMapper;
|
||||
using FilterLists.Services.FilterList.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.MappingProfiles
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class SyntaxSupportedSoftwareDtoMappingProfile : Profile
|
||||
{
|
||||
public SyntaxSupportedSoftwareDtoMappingProfile() =>
|
||||
CreateMap<Data.Entities.Software, SyntaxSupportedSoftwareDto>()
|
||||
.ForMember(dest => dest.Id,
|
||||
opt => opt.MapFrom(src =>
|
||||
(int)src.Id));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListDetails
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string ChatUrl { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string DescriptionSourceUrl { get; set; }
|
||||
public DateTime? DiscontinuedDate { get; set; }
|
||||
public string DonateUrl { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public string ForumUrl { get; set; }
|
||||
public string HomeUrl { get; set; }
|
||||
public string IssuesUrl { get; set; }
|
||||
public IEnumerable<string> Languages { get; set; }
|
||||
public ListLicenseDto License { get; set; }
|
||||
public IEnumerable<ListMaintainerDto> Maintainers { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string PolicyUrl { get; set; }
|
||||
public DateTime? PublishedDate { get; set; }
|
||||
public int RuleCount { get; set; }
|
||||
public string SubmissionUrl { get; set; }
|
||||
public ListSyntaxDto Syntax { get; set; }
|
||||
public IEnumerable<ListTagDto> Tags { get; set; }
|
||||
public DateTime? UpdatedDate { get; set; }
|
||||
public string ViewUrl { get; set; }
|
||||
public string ViewUrlMirror1 { get; set; }
|
||||
public string ViewUrlMirror2 { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListLanguagesDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Iso6391 { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListLicenseDto
|
||||
{
|
||||
public string DescriptionUrl { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListMaintainerDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public string HomeUrl { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string TwitterHandle { get; set; }
|
||||
public IEnumerable<MaintainerAdditionalListsDto> AdditionalLists { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListSyntaxDto
|
||||
{
|
||||
public string DefinitionUrl { get; set; }
|
||||
public string Name { get; set; }
|
||||
public IEnumerable<SyntaxSupportedSoftwareDto> SupportedSoftware { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ListTagDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ColorHex { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class MaintainerAdditionalListsDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace FilterLists.Services.FilterList.Models
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class SyntaxSupportedSoftwareDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string HomeUrl { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace FilterLists.Services.FilterList
|
||||
{
|
||||
public static class TagColors
|
||||
{
|
||||
//https://stackoverflow.com/a/4382138/2343739
|
||||
public static readonly IList<string> Colors = new ReadOnlyCollection<string>(new List<string>
|
||||
{
|
||||
"FFB300", // Vivid Yellow
|
||||
"803E75", // Strong Purple
|
||||
"FF6800", // Vivid Orange
|
||||
"A6BDD7", // Very Light Blue
|
||||
"C10020", // Vivid Red
|
||||
"CEA262", // Grayish Yellow
|
||||
"817066", // Medium Gray
|
||||
"007D34", // Vivid Green
|
||||
"F6768E", // Strong Purplish Pink
|
||||
"00538A", // Strong Blue
|
||||
"FF7A5C", // Strong Yellowish Pink
|
||||
"53377A", // Strong Violet
|
||||
"FF8E00", // Vivid Orange Yellow
|
||||
"B32851", // Strong Purplish Red
|
||||
"F4C800", // Vivid Greenish Yellow
|
||||
"7F180D", // Strong Reddish Brown
|
||||
"93AA00", // Vivid Yellowish Green
|
||||
"593315", // Deep Yellowish Brown
|
||||
"F13A13", // Vivid Reddish Orange
|
||||
"232C16" // Dark Olive Green
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { IColumnVisibility, ILanguage, IList, ISoftware, ITag } from "./interfaces";
|
||||
import { Tagline, ListsTable } from "./components";
|
||||
import { IColumnVisibility, ILanguage, IList, IMaintainer, ISoftware, ITag } from "./interfaces";
|
||||
import { ListsTable, Oneliner } from "./components";
|
||||
|
||||
const columnVisibilityDefaults: IColumnVisibility[] = [
|
||||
{ column: "Software", visible: true },
|
||||
|
|
@ -12,6 +12,7 @@ const columnVisibilityDefaults: IColumnVisibility[] = [
|
|||
interface IProps {
|
||||
languages: ILanguage[];
|
||||
lists: IList[];
|
||||
maintainers: IMaintainer[];
|
||||
ruleCount: number;
|
||||
software: ISoftware[];
|
||||
tags: ITag[];
|
||||
|
|
@ -44,7 +45,7 @@ export class Home extends React.Component<IProps, IState> {
|
|||
|
||||
render() {
|
||||
return <div>
|
||||
<Tagline listCount={this.props.lists.length} ruleCount={this.props.ruleCount}/>
|
||||
<Oneliner listCount={this.props.lists.length} ruleCount={this.props.ruleCount}/>
|
||||
<ListsTable {...this.props} {...this.state}/>
|
||||
{this.renderColumnVisibilityCheckboxes()}
|
||||
</div>;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import * as React from "react";
|
||||
import "isomorphic-fetch";
|
||||
import { ILanguage, IList, ISoftware, ITag } from "./interfaces";
|
||||
import { ILanguage, IList, IMaintainer, ISoftware, ITag } from "./interfaces";
|
||||
import { Home } from "./Home";
|
||||
|
||||
interface IState {
|
||||
languages: ILanguage[];
|
||||
lists: IList[];
|
||||
maintainers: IMaintainer[];
|
||||
ruleCount: number;
|
||||
software: ISoftware[];
|
||||
tags: ITag[];
|
||||
|
|
@ -17,6 +18,7 @@ export class HomeContainer extends React.Component<{}, IState> {
|
|||
this.state = {
|
||||
languages: [],
|
||||
lists: [],
|
||||
maintainers: [],
|
||||
ruleCount: 0,
|
||||
software: [],
|
||||
tags: []
|
||||
|
|
@ -25,40 +27,47 @@ export class HomeContainer extends React.Component<{}, IState> {
|
|||
|
||||
componentDidMount() {
|
||||
this.fetchLists();
|
||||
this.fetchLanguages();
|
||||
this.fetchMaintainers();
|
||||
this.fetchSoftware();
|
||||
this.fetchTags();
|
||||
this.fetchLanguages();
|
||||
this.fetchRuleCount();
|
||||
};
|
||||
|
||||
fetchLists() {
|
||||
fetch("https://filterlists.com/api/v1/lists")
|
||||
.then(r => r.json() as Promise<IList[]>)
|
||||
.then(d => { this.setState({ lists: d }); });
|
||||
};
|
||||
|
||||
fetchSoftware() {
|
||||
fetch("https://filterlists.com/api/v1/software")
|
||||
.then(r => r.json() as Promise<ISoftware[]>)
|
||||
.then(d => { this.setState({ software: d }); });
|
||||
};
|
||||
|
||||
fetchTags() {
|
||||
fetch("https://filterlists.com/api/v1/tags")
|
||||
.then(r => r.json() as Promise<ITag[]>)
|
||||
.then(d => { this.setState({ tags: d }); });
|
||||
.then(p => { this.setState({ lists: p }); });
|
||||
};
|
||||
|
||||
fetchLanguages() {
|
||||
fetch("https://filterlists.com/api/v1/languages")
|
||||
.then(r => r.json() as Promise<ILanguage[]>)
|
||||
.then(d => { this.setState({ languages: d }); });
|
||||
.then(p => { this.setState({ languages: p }); });
|
||||
};
|
||||
|
||||
fetchMaintainers() {
|
||||
fetch("https://filterlists.com/api/v1/maintainers")
|
||||
.then(r => r.json() as Promise<IMaintainer[]>)
|
||||
.then(p => { this.setState({ maintainers: p }); });
|
||||
};
|
||||
|
||||
fetchSoftware() {
|
||||
fetch("https://filterlists.com/api/v1/software")
|
||||
.then(r => r.json() as Promise<ISoftware[]>)
|
||||
.then(p => { this.setState({ software: p }); });
|
||||
};
|
||||
|
||||
fetchTags() {
|
||||
fetch("https://filterlists.com/api/v1/tags")
|
||||
.then(r => r.json() as Promise<ITag[]>)
|
||||
.then(p => { this.setState({ tags: p }); });
|
||||
};
|
||||
|
||||
fetchRuleCount() {
|
||||
fetch("https://filterlists.com/api/v1/rules")
|
||||
.then(r => r.json() as Promise<number>)
|
||||
.then(d => { this.setState({ ruleCount: d }); });
|
||||
.then(p => { this.setState({ ruleCount: p }); });
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ interface IProps {
|
|||
ruleCount: number;
|
||||
};
|
||||
|
||||
export const Tagline = (props: IProps) =>
|
||||
export const Oneliner = (props: IProps) =>
|
||||
props.listCount > 0 && props.ruleCount > 0
|
||||
? <p className="ml-2 mr-2">
|
||||
The independent, comprehensive directory of <strong>{props.ruleCount.toLocaleString()
|
||||
|
|
@ -2,16 +2,35 @@ import * as React from "react";
|
|||
import { ITag } from "../interfaces";
|
||||
import { getContrast } from "../../../utils";
|
||||
|
||||
export const Tag = (props: ITag) => {
|
||||
const hexColor = kelly_colors_hex[props.id % kelly_colors_hex.length];
|
||||
return <span className="badge"
|
||||
style={{
|
||||
backgroundColor: `#${hexColor}`,
|
||||
color: getContrast(hexColor)
|
||||
}}
|
||||
title={props.description}>
|
||||
{props.name}
|
||||
</span>;
|
||||
interface IProps {
|
||||
tags: ITag[];
|
||||
};
|
||||
|
||||
export const TagGroup = (props: IProps) =>
|
||||
props.tags && props.tags.length > 0
|
||||
? <div className="fl-tag-container">
|
||||
{props.tags.map((t: ITag, i: number) => <Tag tag={t} key={i}/>)}
|
||||
</div>
|
||||
: null;
|
||||
|
||||
interface ITagProps {
|
||||
tag: ITag;
|
||||
};
|
||||
|
||||
const Tag = (props: ITagProps) => {
|
||||
if (props.tag) {
|
||||
const hexColor = kelly_colors_hex[props.tag.id % kelly_colors_hex.length];
|
||||
return <span className="badge"
|
||||
style={{
|
||||
backgroundColor: `#${hexColor}`,
|
||||
color: getContrast(hexColor)
|
||||
}}
|
||||
title={props.tag.description}>
|
||||
{props.tag.name}
|
||||
</span>;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
//https://stackoverflow.com/a/4382138/2343739
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import * as React from "react";
|
||||
import { IFilterListDetailsDto } from "./IFilterListDetailsDto";
|
||||
import { IListDetails } from "./IListDetails";
|
||||
import { InfoCard } from "./infoCard";
|
||||
import { LinkButtonGroup } from "./LinkButtonGroup";
|
||||
import { MaintainersInfoCard } from "./maintainersInfoCard";
|
||||
|
||||
export const DetailsExpander = (props: IFilterListDetailsDto) => {
|
||||
export const DetailsExpander = (props: IListDetails) => {
|
||||
return <div className="card border-primary">
|
||||
<div className="card-body p-2">
|
||||
<div className="container m-0">
|
||||
|
|
|
|||
|
|
@ -1,42 +1,25 @@
|
|||
import * as React from "react";
|
||||
import "isomorphic-fetch";
|
||||
import "../../../../utils/loader.css";
|
||||
import { IFilterListDetailsDto } from "./IFilterListDetailsDto";
|
||||
import { IListDetails } from "./IListDetails";
|
||||
import { DetailsExpander } from "./DetailsExpander";
|
||||
|
||||
interface IProps {
|
||||
listId: number;
|
||||
list: IListDetails;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
filterListDetails: IFilterListDetailsDto;
|
||||
}
|
||||
|
||||
export class DetailsExpanderContainer extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
filterListDetails: {} as IFilterListDetailsDto
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchFilterListDetails();
|
||||
}
|
||||
|
||||
fetchFilterListDetails() {
|
||||
fetch(`https://filterlists.com/api/v1/lists/${this.props.listId}`)
|
||||
.then(r => r.json() as Promise<IFilterListDetailsDto>)
|
||||
.then(d => {
|
||||
this.setState({
|
||||
filterListDetails: d
|
||||
});
|
||||
});
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.filterListDetails.name
|
||||
? <DetailsExpander {...this.state.filterListDetails}/>
|
||||
return this.props.list.name
|
||||
? <DetailsExpander {...this.props.list}/>
|
||||
: <div className="loader">Loading...</div>;;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
export interface IFilterListDetailsDto {
|
||||
chatUrl: string;
|
||||
description: string;
|
||||
descriptionSourceUrl: string;
|
||||
discontinuedDate: string;
|
||||
donateUrl: string;
|
||||
emailAddress: string;
|
||||
forumUrl: string;
|
||||
homeUrl: string;
|
||||
issuesUrl: string;
|
||||
languages: string[];
|
||||
license: IListLicenseDto;
|
||||
maintainers: IListMaintainerDto[];
|
||||
name: string;
|
||||
policyUrl: string;
|
||||
publishedDate: string;
|
||||
ruleCount: number;
|
||||
submissionUrl: string;
|
||||
syntax: IListSyntaxDto;
|
||||
tags: IListTagDto[];
|
||||
updatedDate: string;
|
||||
viewUrl: string;
|
||||
viewUrlMirror1: string;
|
||||
viewUrlMirror2: string;
|
||||
}
|
||||
|
||||
export interface IListLicenseDto {
|
||||
descriptionUrl: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IListMaintainerDto {
|
||||
id: number;
|
||||
emailAddress: string;
|
||||
homeUrl: string;
|
||||
name: string;
|
||||
twitterHandle: string;
|
||||
additionalLists: IMaintainerAdditionalListDto[];
|
||||
}
|
||||
|
||||
export interface IListSyntaxDto {
|
||||
definitionUrl: string;
|
||||
name: string;
|
||||
supportedSoftware: ISyntaxSupportedSoftwareDto[];
|
||||
}
|
||||
|
||||
export interface IListTagDto {
|
||||
name: string;
|
||||
colorHex: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface IMaintainerAdditionalListDto {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ISyntaxSupportedSoftwareDto {
|
||||
homeUrl: string;
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import { ILanguage, IMaintainer, ITag } from "../../interfaces";
|
||||
|
||||
export interface IListDetails {
|
||||
id: number;
|
||||
chatUrl: string;
|
||||
description: string;
|
||||
descriptionSourceUrl: string;
|
||||
discontinuedDate: string;
|
||||
donateUrl: string;
|
||||
emailAddress: string;
|
||||
forumUrl: string;
|
||||
homeUrl: string;
|
||||
issuesUrl: string;
|
||||
languages: ILanguage[];
|
||||
license: IListLicense;
|
||||
maintainers: IMaintainer[];
|
||||
name: string;
|
||||
policyUrl: string;
|
||||
publishedDate: string;
|
||||
ruleCount: number;
|
||||
submissionUrl: string;
|
||||
syntax: IListSyntax;
|
||||
tags: ITag[];
|
||||
updatedDate: string;
|
||||
viewUrl: string;
|
||||
viewUrlMirrors: string[];
|
||||
}
|
||||
|
||||
export interface IListLicense {
|
||||
descriptionUrl: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IListSyntax {
|
||||
definitionUrl: string;
|
||||
name: string;
|
||||
supportedSoftware: ISyntaxSupportedSoftware[];
|
||||
}
|
||||
|
||||
export interface ISyntaxSupportedSoftware {
|
||||
homeUrl: string;
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
|
@ -23,15 +23,13 @@ interface IProps {
|
|||
policyUrl: string;
|
||||
submissionUrl: string;
|
||||
viewUrl: string;
|
||||
viewUrlMirror1: string;
|
||||
viewUrlMirror2: string;
|
||||
viewUrlMirrors: string[];
|
||||
}
|
||||
|
||||
export const LinkButtonGroup = (props: IProps) => {
|
||||
const viewUrlMirrors = new Array(props.viewUrlMirror1, props.viewUrlMirror2).filter(u => u);
|
||||
return <div className="col-3 p-0 btn-group-vertical justify-content-start d-flex align-items-end">
|
||||
<SubscribeButtonGroup name={props.name} url={props.viewUrl} urlMirrors={viewUrlMirrors}/>
|
||||
<ViewButtonGroup name={props.name} url={props.viewUrl} urlMirrors={viewUrlMirrors}/>
|
||||
<SubscribeButtonGroup name={props.name} url={props.viewUrl} urlMirrors={props.viewUrlMirrors}/>
|
||||
<ViewButtonGroup name={props.name} url={props.viewUrl} urlMirrors={props.viewUrlMirrors}/>
|
||||
<HomeButton name={props.name} url={props.homeUrl}/>
|
||||
<PolicyButton name={props.name} url={props.policyUrl}/>
|
||||
<DonateButton name={props.name} url={props.donateUrl}/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { DetailsExpanderContainer } from "./DetailsExpanderContainer";
|
||||
import { IListDetails } from "./IListDetails";
|
||||
|
||||
export {
|
||||
DetailsExpanderContainer as DetailsExpander
|
||||
DetailsExpanderContainer as DetailsExpander,
|
||||
IListDetails
|
||||
};
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { IListLicenseDto, IListSyntaxDto, IListTagDto, ISyntaxSupportedSoftwareDto } from "../IFilterListDetailsDto";
|
||||
import { IListLicense, IListSyntax, ISyntaxSupportedSoftware } from "../IListDetails";
|
||||
import { ILanguage, ITag } from "../../../interfaces";
|
||||
import { Description } from "./Description";
|
||||
import { DiscontinuedDate } from "./DiscontinuedDate";
|
||||
import { Languages } from "./Languages";
|
||||
|
|
@ -8,30 +9,30 @@ import { PublishedDate } from "./PublishedDate";
|
|||
import { RuleCount } from "./RuleCount";
|
||||
import { SoftwareIcon } from "../../softwareIcon";
|
||||
import { Syntax } from "./Syntax";
|
||||
import { Tags } from "./Tags";
|
||||
import { TagGroup } from "../../TagGroup"
|
||||
import { UpdatedDate } from "./UpdatedDate";
|
||||
|
||||
interface IProps {
|
||||
description: string;
|
||||
descriptionSourceUrl: string;
|
||||
discontinuedDate: string;
|
||||
languages: string[];
|
||||
license: IListLicenseDto;
|
||||
languages: ILanguage[];
|
||||
license: IListLicense;
|
||||
name: string;
|
||||
publishedDate: string;
|
||||
ruleCount: number;
|
||||
syntax: IListSyntaxDto;
|
||||
tags: IListTagDto[];
|
||||
syntax: IListSyntax;
|
||||
tags: ITag[];
|
||||
updatedDate: string;
|
||||
}
|
||||
|
||||
export const InfoCard = (props: IProps) => {
|
||||
return <div className="col-9">
|
||||
<Tags tags={props.tags}/>
|
||||
<TagGroup tags={props.tags}/>
|
||||
<div className="d-md-none">
|
||||
{props.syntax
|
||||
? props.syntax.supportedSoftware.map(
|
||||
(s: ISyntaxSupportedSoftwareDto, i: number) =>
|
||||
(s: ISyntaxSupportedSoftware, i: number) =>
|
||||
<a href={s.homeUrl} key={i}>
|
||||
<SoftwareIcon id={s.id} key={i}/>
|
||||
</a>)
|
||||
|
|
@ -39,7 +40,7 @@ export const InfoCard = (props: IProps) => {
|
|||
</div>
|
||||
<Description {...props} url={props.descriptionSourceUrl}/>
|
||||
<ul className="list-group list-group-flush">
|
||||
<Languages languages={props.languages}/>
|
||||
<Languages languages={...props.languages}/>
|
||||
<RuleCount {...props}/>
|
||||
<DiscontinuedDate date={props.discontinuedDate}/>
|
||||
<UpdatedDate {...props}/>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
import * as React from "react";
|
||||
import { ILanguage } from "../../../interfaces";
|
||||
|
||||
interface IProps {
|
||||
languages: string[];
|
||||
languages: ILanguage[];
|
||||
}
|
||||
|
||||
export const Languages = (props: IProps) => {
|
||||
return props.languages.length > 0
|
||||
return 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: string, i: number) => <li key={i}>{language}</li>)}
|
||||
{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]}</p>
|
||||
<p>Language: {props.languages[0].name}</p>
|
||||
</li>
|
||||
: null;
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from "react";
|
||||
import { IListLicenseDto } from "../IFilterListDetailsDto";
|
||||
import { IListLicense as IListLicenseDto } from "../IListDetails";
|
||||
|
||||
export const License = (props: IListLicenseDto) => {
|
||||
return props.name
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from "react";
|
||||
import { IListSyntaxDto } from "../IFilterListDetailsDto";
|
||||
import { IListSyntax as IListSyntaxDto } from "../IListDetails";
|
||||
|
||||
export const Syntax = (props: IListSyntaxDto) => {
|
||||
return props.name
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { IListTagDto } from "../IFilterListDetailsDto";
|
||||
import { getContrast } from "../../../../../utils";
|
||||
|
||||
export const Tag = (props: IListTagDto) => {
|
||||
const style = props.colorHex
|
||||
? {
|
||||
backgroundColor: `#${props.colorHex}`,
|
||||
color: getContrast(`${props.colorHex}`)
|
||||
}
|
||||
: undefined;
|
||||
return props.name
|
||||
? <span className="badge"
|
||||
style={style}
|
||||
title={props.description}>
|
||||
{props.name}
|
||||
</span>
|
||||
: null;
|
||||
};
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { IListTagDto } from "../IFilterListDetailsDto";
|
||||
import { Tag } from "./Tag";
|
||||
|
||||
interface IProps {
|
||||
tags: IListTagDto[];
|
||||
}
|
||||
|
||||
export const Tags = (props: IProps) => {
|
||||
return props.tags && props.tags.length > 0
|
||||
? <div className="d-md-none">
|
||||
{props.tags.map((t: IListTagDto, i: number) => <Tag {...t} key={i}/>)}
|
||||
</div>
|
||||
: null;
|
||||
};
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
import * as React from "react";
|
||||
import { IMaintainerAdditionalListDto } from "../IFilterListDetailsDto";
|
||||
|
||||
interface IProps {
|
||||
name: string;
|
||||
additionalLists: IMaintainerAdditionalListDto[];
|
||||
}
|
||||
//interface IProps {
|
||||
// name: string;
|
||||
// additionalLists: IMaintainerAdditionalListDto[];
|
||||
//}
|
||||
|
||||
export const MaintainerAdditionalLists = (props: IProps) => {
|
||||
export const MaintainerAdditionalLists = (/*props: IProps*/) => {
|
||||
return <div className="col-9">
|
||||
{props.additionalLists && props.additionalLists.length > 0
|
||||
{ /*props.additionalLists && props.additionalLists.length > 0
|
||||
? <div>
|
||||
<h4>More by {props.name}:</h4>
|
||||
<ul>
|
||||
|
|
@ -17,6 +16,6 @@ export const MaintainerAdditionalLists = (props: IProps) => {
|
|||
</ul>
|
||||
|
||||
</div>
|
||||
: null}
|
||||
: null*/ }
|
||||
</div>;
|
||||
};
|
||||
|
|
@ -1,20 +1,23 @@
|
|||
import * as React from "react";
|
||||
import { IListMaintainerDto } from "../IFilterListDetailsDto";
|
||||
import { IMaintainer } from "../../../interfaces";
|
||||
import { MaintainerAdditionalLists } from "./MaintainerAdditionalLists";
|
||||
import { MaintainerLinkButtonGroup } from "./MaintainerLinkButtonGroup";
|
||||
|
||||
export const MaintainerInfoCard = (props: IListMaintainerDto) => {
|
||||
return props.name
|
||||
? <div className="card">
|
||||
<div className="card-body">
|
||||
<h3 className="card-header">Maintained by {props.name}</h3>
|
||||
<div className="container pt-1">
|
||||
<div className="row">
|
||||
<MaintainerAdditionalLists {...props}/>
|
||||
<MaintainerLinkButtonGroup {...props}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
: null;
|
||||
};
|
||||
interface IProps {
|
||||
maintainer: IMaintainer;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -8,10 +8,9 @@ interface IProps {
|
|||
twitterHandle: string;
|
||||
}
|
||||
|
||||
export const MaintainerLinkButtonGroup = (props: IProps) => {
|
||||
return <div className="col-3 p-0 btn-group-vertical justify-content-start d-flex align-items-end" role="group">
|
||||
<HomeButton {...props} url={props.homeUrl}/>
|
||||
<EmailButton {...props}/>
|
||||
<TwitterButton {...props}/>
|
||||
</div>;
|
||||
};
|
||||
export const MaintainerLinkButtonGroup = (props: IProps) =>
|
||||
<div className="col-3 p-0 btn-group-vertical justify-content-start d-flex align-items-end" role="group">
|
||||
<HomeButton {...props} url={props.homeUrl}/>
|
||||
<EmailButton {...props}/>
|
||||
<TwitterButton {...props}/>
|
||||
</div>;
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
import * as React from "react";
|
||||
import { IListMaintainerDto } from "../IFilterListDetailsDto";
|
||||
import { IMaintainer } from "../../../interfaces";
|
||||
import { MaintainerInfoCard } from "./MaintainerInfoCard";
|
||||
|
||||
interface IProps {
|
||||
maintainers: IListMaintainerDto[];
|
||||
maintainers: IMaintainer[];
|
||||
}
|
||||
|
||||
export const MaintainersInfoCard = (props: IProps) => {
|
||||
return props.maintainers && props.maintainers.length > 0
|
||||
? <div className="w-100">
|
||||
{props.maintainers.map(
|
||||
(m: IListMaintainerDto, i: number) => <MaintainerInfoCard {...m} key={i}/>)}
|
||||
</div>
|
||||
: null;
|
||||
};
|
||||
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;
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { DetailsExpander } from "./detailsExpander";
|
||||
import { ListsTable } from "./listsTable";
|
||||
import { Tagline } from "./Tagline";
|
||||
import { Oneliner } from "./Oneliner";
|
||||
|
||||
export {
|
||||
DetailsExpander,
|
||||
ListsTable,
|
||||
Tagline
|
||||
Oneliner
|
||||
};
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
import * as React from "react";
|
||||
import { IColumnVisibility, ILanguage, IList, ISoftware, ITag } from "../../interfaces";
|
||||
import { IColumnVisibility, ILanguage, IList, IMaintainer, ISoftware, ITag } from "../../interfaces";
|
||||
import "../../../../utils/loader.css";
|
||||
import ReactTable from "react-table"
|
||||
import "react-table/react-table.css"
|
||||
import "./listsTable.css";
|
||||
import { DetailsButton, Languages, Name, Software, Tags, UpdatedDate } from "./columns";
|
||||
import { IListDetails } from "../../components/detailsExpander";
|
||||
import { DetailsExpander } from "../../components";
|
||||
|
||||
interface IProps {
|
||||
languages: ILanguage[];
|
||||
lists: IList[];
|
||||
maintainers: IMaintainer[];
|
||||
software: ISoftware[];
|
||||
tags: ITag[];
|
||||
columnVisibility: IColumnVisibility[];
|
||||
|
|
@ -17,7 +19,7 @@ interface IProps {
|
|||
};
|
||||
|
||||
export const ListsTable = (props: IProps) =>
|
||||
props.lists.length > 0 && props.languages.length > 0 && props.software.length > 0
|
||||
props.languages.length > 0 && props.lists.length > 0 && props.software.length > 0 && props.tags.length > 0
|
||||
? <ReactTable
|
||||
data={props.lists}
|
||||
defaultPageSize={props.pageSize}
|
||||
|
|
@ -31,6 +33,50 @@ export const ListsTable = (props: IProps) =>
|
|||
DetailsButton
|
||||
]}
|
||||
defaultSorted={[{ id: "name" }]}
|
||||
SubComponent={(r: any) => <DetailsExpander listId={r.original.id}/>}
|
||||
SubComponent={(r: any) => <DetailsExpander list={mapListDetails(({
|
||||
list: r.original,
|
||||
languages: props.languages,
|
||||
maintainers: props.maintainers,
|
||||
tags: props.tags
|
||||
} as ICreateListDtoProps))}/>}
|
||||
className="-striped -highlight"/>
|
||||
: <div className="loader">Loading...</div>;
|
||||
: <div className="loader">Loading...</div>;
|
||||
|
||||
interface ICreateListDtoProps {
|
||||
list: IList;
|
||||
languages: ILanguage[];
|
||||
maintainers: IMaintainer[];
|
||||
tags: ITag[];
|
||||
};
|
||||
|
||||
const mapListDetails = (props: ICreateListDtoProps): IListDetails => {
|
||||
return {
|
||||
id: props.list.id,
|
||||
chatUrl: props.list.chatUrl,
|
||||
description: props.list.description,
|
||||
descriptionSourceUrl: props.list.descriptionSourceUrl,
|
||||
discontinuedDate: props.list.discontinuedDate,
|
||||
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:,
|
||||
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:,
|
||||
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;
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { Column, Filter } from "react-table";
|
||||
import { Tag } from "../../Tag"
|
||||
import { TagGroup } from "../../TagGroup"
|
||||
import { IColumnVisibility, ITag } from "../../../interfaces";
|
||||
|
||||
export const Tags = (columnVisibility: IColumnVisibility[], tags: ITag[]) => {
|
||||
|
|
@ -41,9 +41,6 @@ const sortMethod = (a: number[], b: number[]): any =>
|
|||
const Cell = (tagIds: number[], tags: ITag[]) =>
|
||||
tagIds
|
||||
? <div className="fl-tag-container">
|
||||
{tagIds.map((tid: number, i: number) => {
|
||||
const tag = tags.filter((t: ITag) => t.id === tid)[0];
|
||||
return <Tag {...tag} key={i}/>;
|
||||
})}
|
||||
<TagGroup tags={tags.filter((t: ITag) => tagIds.indexOf(t.id) > -1)}/>
|
||||
</div>
|
||||
: null;
|
||||
|
|
@ -57,4 +57,4 @@ const icons: { [id: number]: IIcon; } = {
|
|||
19: { image: img19, imageTitle: "Samsung Knox" },
|
||||
20: { image: img20, imageTitle: "Little Snitch" },
|
||||
21: { image: img21, imageTitle: "Privoxy" }
|
||||
};
|
||||
};
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
export interface ILanguage {
|
||||
id: number;
|
||||
filterListIds: number[];
|
||||
iso6391: string;
|
||||
name: string;
|
||||
}
|
||||
|
|
@ -1,8 +1,25 @@
|
|||
export interface IList {
|
||||
id: number;
|
||||
chatUrl: string;
|
||||
description: string;
|
||||
descriptionSourceUrl: string;
|
||||
discontinuedDate: string;
|
||||
donateUrl: string;
|
||||
emailAddress: string;
|
||||
forumUrl: string;
|
||||
homeUrl: string;
|
||||
issuesUrl: string;
|
||||
languageIds: number[];
|
||||
licenseId: string;
|
||||
maintainerIds: number[];
|
||||
name: string;
|
||||
policyUrl: string;
|
||||
publishedDate: string;
|
||||
ruleCount: number;
|
||||
submissionUrl: string;
|
||||
syntaxId: number;
|
||||
tagIds: number[];
|
||||
updatedDate: string;
|
||||
viewUrl: string;
|
||||
viewUrlMirrors: string[];
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
export interface IMaintainer {
|
||||
id: number;
|
||||
emailAddress: string;
|
||||
filterListIds: number[];
|
||||
homeUrl: string;
|
||||
name: string;
|
||||
twitterHandle: string;
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
export interface ISoftware {
|
||||
id: number;
|
||||
homeUrl: string;
|
||||
isAbpSubscribable: boolean;
|
||||
name: string;
|
||||
syntaxIds: number[];
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
export interface ITag {
|
||||
id: number;
|
||||
description: string;
|
||||
filterListIds: number[];
|
||||
name: string;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { IColumnVisibility } from "./IColumnVisibility";
|
||||
import { ILanguage } from "./ILanguage";
|
||||
import { IList } from "./IList";
|
||||
import { IMaintainer } from "./IMaintainer";
|
||||
import { ISoftware } from "./ISoftware";
|
||||
import { ITag } from "./ITag";
|
||||
|
||||
|
|
@ -9,6 +10,7 @@ export {
|
|||
IColumnVisibility,
|
||||
ILanguage,
|
||||
IList,
|
||||
IMaintainer,
|
||||
ISoftware,
|
||||
ITag
|
||||
};
|
||||
|
|
@ -3,11 +3,11 @@
|
|||
.loader,
|
||||
.loader:before,
|
||||
.loader:after {
|
||||
-webkit-animation: load1 1s infinite ease-in-out;
|
||||
animation: load1 1s infinite ease-in-out;
|
||||
background: #000000;
|
||||
height: 4em;
|
||||
width: 1em;
|
||||
-webkit-animation: load1 1s infinite ease-in-out;
|
||||
animation: load1 1s infinite ease-in-out;
|
||||
background: #000000;
|
||||
height: 4em;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
.loader {
|
||||
|
|
|
|||
Loading…
Reference in a new issue