Sidebar and tagingfor Technology and solution areas tagging/filtering (#147)
* Filtering sidebar and taging changes for Technology and solution areas tagging/filtering - Modified item.json, api controller to have Tachnologies instead of types. Renamed Category to solution areas. - Removed runtime version as now we have Functions 1.x and functions 2.x as first class technologies. - Modified item.json to have language and technologies string as to be displayed in UI. - Modifed sidebar and tags component to include all technologies, solution areas and languages.
This commit is contained in:
Родитель
d447822e1e
Коммит
43ba412443
|
@ -48,9 +48,10 @@ class ItemList extends Component {
|
|||
/>
|
||||
<p className="description">{item.description}</p>
|
||||
<ItemTags
|
||||
type={item.type}
|
||||
technologies={item.technologies}
|
||||
language={item.language}
|
||||
tags={item.tags}
|
||||
solutionareas={item.solutionareas}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,86 +1,33 @@
|
|||
import React, { Component } from "react";
|
||||
import { registerIcons, Icon } from "office-ui-fabric-react";
|
||||
import { ReactComponent as FunctionappSvg } from "../../assets/functionapp.svg";
|
||||
import { ReactComponent as LogicappSvg } from "../../assets/logicapp.svg";
|
||||
|
||||
import "./ItemTags.css";
|
||||
|
||||
registerIcons({
|
||||
icons: {
|
||||
"functionapp-svg": <FunctionappSvg className="svg" />,
|
||||
"logicapp-svg": <LogicappSvg className="svg" />
|
||||
}
|
||||
});
|
||||
class ItemTags extends Component {
|
||||
ToDisplayType(value) {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
var type = value.toLowerCase();
|
||||
if (type === "functionapp") {
|
||||
return "Function App";
|
||||
} else if (type === "logicapp") {
|
||||
return "Logic App";
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
ToDisplayLanguage(value) {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
var language = value.toLowerCase();
|
||||
if (language === "csharp") {
|
||||
return "C#";
|
||||
} else if (language === "javascript") {
|
||||
return "JavaScript";
|
||||
} else if (language === "python") {
|
||||
return "Python";
|
||||
} else if (language === "java") {
|
||||
return "Java";
|
||||
} else if (language === "na") {
|
||||
return "";
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let svgIconName;
|
||||
if (this.props.type === "functionapp") {
|
||||
svgIconName = "functionapp-svg";
|
||||
} else if (this.props.type === "logicapp") {
|
||||
svgIconName = "logicapp-svg";
|
||||
// Tags contain technologies, language, solutionareas and custom tags
|
||||
let allTags = [];
|
||||
|
||||
if (this.props.technologies) {
|
||||
allTags.push(...this.props.technologies);
|
||||
}
|
||||
|
||||
let itemTypeToDisplay = this.ToDisplayType(this.props.type);
|
||||
|
||||
let languageTag;
|
||||
if (this.props.language !== "" && this.props.language !== "na") {
|
||||
let itemLanguageToDisplay = this.ToDisplayLanguage(this.props.language);
|
||||
languageTag = <span className="tag">{itemLanguageToDisplay}</span>;
|
||||
allTags.push(this.props.language);
|
||||
}
|
||||
if (this.props.solutionareas) {
|
||||
allTags.push(...this.props.solutionareas);
|
||||
}
|
||||
|
||||
let tags;
|
||||
if (this.props.tags) {
|
||||
tags = this.props.tags.map((value, index) => {
|
||||
return (
|
||||
<span className="tag" key={index}>
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
allTags.push(...this.props.tags);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tagcontainer">
|
||||
Tags :
|
||||
<span className="tag">
|
||||
<Icon iconName={svgIconName} />
|
||||
<span>{itemTypeToDisplay}</span>
|
||||
</span>
|
||||
{languageTag}
|
||||
{tags}
|
||||
{allTags.map((value, index) => (
|
||||
<span className="tag" key={index}>
|
||||
{value}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,25 +27,31 @@ class Main extends Component {
|
|||
el.title.match(filter) ||
|
||||
el.description.match(filter) ||
|
||||
el.language.match(filter) ||
|
||||
el.type.match(filter) ||
|
||||
el.repository.replace("https://github.com/", "").match(filter) ||
|
||||
(el.runtimeversion && el.runtimeversion.match(filter)) ||
|
||||
(el.tags && el.tags.some(x => x.match(filter))) ||
|
||||
(el.technologies && el.technologies.some(x => x.match(filter))) ||
|
||||
(el.solutionareas && el.solutionareas.some(x => x.match(filter))) ||
|
||||
(el.author && el.author.match(filter))
|
||||
);
|
||||
|
||||
if (currentfilters.categories.types.length > 0) {
|
||||
if (currentfilters.categories.technologies.length > 0) {
|
||||
samples = samples.filter(s =>
|
||||
currentfilters.categories.types.includes(s.type)
|
||||
s.technologies.some(t=> currentfilters.categories.technologies.includes(t))
|
||||
);
|
||||
}
|
||||
|
||||
if (currentfilters.categories.languages.length > 0) {
|
||||
samples = samples.filter(s =>
|
||||
samples = samples.filter(s =>
|
||||
currentfilters.categories.languages.includes(s.language)
|
||||
);
|
||||
}
|
||||
|
||||
if (currentfilters.categories.solutionareas.length > 0) {
|
||||
samples = samples.filter(s =>
|
||||
s.solutionareas.some(a=> currentfilters.categories.solutionareas.includes(a))
|
||||
);
|
||||
}
|
||||
|
||||
return this.Sort(samples, currentfilters.sortby);
|
||||
}
|
||||
|
||||
|
@ -73,22 +79,26 @@ class Main extends Component {
|
|||
getFiltersFromQueryParams() {
|
||||
var filter = {
|
||||
categories: {
|
||||
types: [],
|
||||
languages: []
|
||||
technologies: [],
|
||||
languages: [],
|
||||
solutionareas: [],
|
||||
},
|
||||
filtertext: "",
|
||||
sortby: "totaldownloads"
|
||||
};
|
||||
|
||||
var params = queryStringToParams(this.props.location.search);
|
||||
if (params.type && params.type.length > 0) {
|
||||
filter.categories.types = params.type.split(",");
|
||||
if (params.technology && params.technology.length > 0) {
|
||||
filter.categories.technologies = params.technology.split(",");
|
||||
}
|
||||
|
||||
if (params.language && params.language.length > 0) {
|
||||
filter.categories.languages = params.language.split(",");
|
||||
}
|
||||
|
||||
if (params.solutionarea && params.solutionarea.length > 0) {
|
||||
filter.categories.solutionareas = params.solutionarea.split(",");
|
||||
}
|
||||
if (params.filtertext && params.filtertext.length > 0) {
|
||||
filter.filtertext = params.filtertext;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,37 @@ import { Checkbox } from "office-ui-fabric-react/lib/index";
|
|||
import { paramsToQueryString, queryStringToParams } from "../../helpers";
|
||||
import "./SideBar.css";
|
||||
|
||||
const technologies = [
|
||||
"Functions 1.x",
|
||||
"Functions 2.x",
|
||||
"Logic Apps",
|
||||
"Cosmos DB"
|
||||
];
|
||||
const solutionAreas = [
|
||||
"Web API",
|
||||
"Data Processing",
|
||||
"Integration",
|
||||
"Authentication",
|
||||
"Automation",
|
||||
"Event Processing",
|
||||
"Machine Learning",
|
||||
"Scheduled Jobs",
|
||||
"Static Website",
|
||||
"Gaming",
|
||||
"IoT"
|
||||
];
|
||||
|
||||
const languages = [
|
||||
"JavaScript",
|
||||
"TypeScript",
|
||||
"Java",
|
||||
"C#",
|
||||
"C# Script",
|
||||
"F#",
|
||||
"Python",
|
||||
"PowerShell"
|
||||
];
|
||||
|
||||
class SideBar extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -32,50 +63,55 @@ class SideBar extends Component {
|
|||
|
||||
ChangeUrl() {
|
||||
var params = queryStringToParams(this.props.location.search);
|
||||
delete params["type"];
|
||||
delete params["technology"];
|
||||
delete params["language"];
|
||||
if (this.state.filters.types.length > 0) {
|
||||
params["type"] = this.state.filters.types.join();
|
||||
delete params["solutionarea"];
|
||||
if (this.state.filters.technologies.length > 0) {
|
||||
params["technology"] = this.state.filters.technologies.join();
|
||||
}
|
||||
if (this.state.filters.languages.length > 0) {
|
||||
params["language"] = this.state.filters.languages.join();
|
||||
}
|
||||
if (this.state.filters.solutionareas.length > 0) {
|
||||
params["solutionarea"] = this.state.filters.solutionareas.join();
|
||||
}
|
||||
|
||||
this.props.history.push(paramsToQueryString(params));
|
||||
}
|
||||
|
||||
render() {
|
||||
const checkboxStyles = () => {
|
||||
const checkboxStyles = index => {
|
||||
return {
|
||||
root: {
|
||||
marginTop: "10px",
|
||||
marginBottom: "5px",
|
||||
color: "red"
|
||||
marginTop: index === 0 ? "10px" : "0px",
|
||||
marginBottom: "5px"
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="filterHeader">Filter by </h3>
|
||||
<div>
|
||||
<fieldset className="filterset">
|
||||
<span>Type</span>
|
||||
<span>Technology</span>
|
||||
<div className="filterList">
|
||||
<Checkbox
|
||||
styles={checkboxStyles}
|
||||
label="Function app"
|
||||
defaultChecked={this.isChecked("types", "functionapp")}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(ev, checked, "types", "functionapp")
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Logic app"
|
||||
defaultChecked={this.isChecked("types", "logicapp")}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(ev, checked, "types", "logicapp")
|
||||
}
|
||||
/>
|
||||
{technologies.map((technology, index) => (
|
||||
<Checkbox
|
||||
styles={checkboxStyles(index)}
|
||||
label={technology}
|
||||
key={technology}
|
||||
defaultChecked={this.isChecked("technologies", technology)}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(
|
||||
ev,
|
||||
checked,
|
||||
"technologies",
|
||||
technology
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
@ -83,21 +119,40 @@ class SideBar extends Component {
|
|||
<fieldset className="filterset">
|
||||
<span>Language</span>
|
||||
<div className="filterList">
|
||||
<Checkbox
|
||||
styles={checkboxStyles}
|
||||
label="C#"
|
||||
defaultChecked={this.isChecked("languages", "csharp")}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(ev, checked, "languages", "csharp")
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Javascript"
|
||||
defaultChecked={this.isChecked("languages", "javascript")}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(ev, checked, "languages", "javascript")
|
||||
}
|
||||
/>
|
||||
{languages.map((language, index) => (
|
||||
<Checkbox
|
||||
styles={checkboxStyles(index)}
|
||||
label={language}
|
||||
key={language}
|
||||
defaultChecked={this.isChecked("languages", language)}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(ev, checked, "languages", language)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<fieldset className="filterset">
|
||||
<span>Solution Area</span>
|
||||
<div className="filterList">
|
||||
{solutionAreas.map((solutionarea, index) => (
|
||||
<Checkbox
|
||||
styles={checkboxStyles(index)}
|
||||
label={solutionarea}
|
||||
key={solutionarea}
|
||||
defaultChecked={this.isChecked("solutionareas", solutionarea)}
|
||||
onChange={(ev, checked) =>
|
||||
this.checkboxclicked(
|
||||
ev,
|
||||
checked,
|
||||
"solutionareas",
|
||||
solutionarea
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
|
|
@ -26,25 +26,24 @@ namespace ServerlessLibrary.Controllers
|
|||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(IEnumerable<LibraryItemWithStats>), 200)]
|
||||
public JsonResult Get(string filterText, string type, string language)
|
||||
{
|
||||
|
||||
public JsonResult Get(string filterText, string language)
|
||||
{
|
||||
//TODO: Add filtering for solution areas and technologies.
|
||||
var results = _cacheService.GetCachedItems();
|
||||
var filteredResults = results.Where(
|
||||
x =>
|
||||
(
|
||||
(string.IsNullOrWhiteSpace(language) || x.Language == language) &&
|
||||
(string.IsNullOrWhiteSpace(type) || x.Type == type) &&
|
||||
(
|
||||
string.IsNullOrWhiteSpace(filterText)
|
||||
|| Regex.IsMatch(x.Title, filterText, RegexOptions.IgnoreCase)
|
||||
|| Regex.IsMatch(x.Description, filterText, RegexOptions.IgnoreCase)
|
||||
|| Regex.IsMatch(x.Repository.Replace("https://github.com/", "", StringComparison.InvariantCulture), filterText, RegexOptions.IgnoreCase)
|
||||
|| (!string.IsNullOrWhiteSpace(x.Author) && Regex.IsMatch(x.Author, filterText, RegexOptions.IgnoreCase))
|
||||
|| (x.RuntimeVersion != null && Regex.IsMatch(x.RuntimeVersion, filterText, RegexOptions.IgnoreCase))
|
||||
|| (x.Tags != null && x.Tags.Any(t => Regex.IsMatch(t, filterText, RegexOptions.IgnoreCase)))
|
||||
|| (x.Category != null && x.Category.Any(t => Regex.IsMatch(t, filterText, RegexOptions.IgnoreCase)))
|
||||
)
|
||||
|| (x.Technologies != null && x.Technologies.Any(t => Regex.IsMatch(t, filterText, RegexOptions.IgnoreCase)))
|
||||
|| (x.SolutionAreas != null && x.SolutionAreas.Any(c => Regex.IsMatch(c, filterText, RegexOptions.IgnoreCase)))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -41,17 +41,14 @@ namespace ServerlessLibrary.Models
|
|||
[JsonProperty(PropertyName = "language", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string Language { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "type", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string Type { get; set; }
|
||||
[JsonProperty(PropertyName = "technologies", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string[] Technologies { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "category", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string[] Category { get; set; }
|
||||
[JsonProperty(PropertyName = "solutionareas", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string[] SolutionAreas { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "author", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string Author { get; internal set; }
|
||||
|
||||
[JsonProperty(PropertyName = "runtimeversion", DefaultValueHandling = DefaultValueHandling.Include)]
|
||||
public string RuntimeVersion { get; set; }
|
||||
public string Author { get; internal set; }
|
||||
|
||||
internal T ConvertTo<T>()
|
||||
{
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче