mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-22 22:43:31 -07:00
Compare commits
No commits in common. "develop" and "v0.6.1.830" have entirely different histories.
develop
...
v0.6.1.830
4454 changed files with 119768 additions and 188481 deletions
|
@ -1,13 +0,0 @@
|
|||
// This file is used to open the backend and frontend in the same workspace, which is necessary as
|
||||
// the frontend has vscode settings that are distinct from the backend
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".."
|
||||
},
|
||||
{
|
||||
"path": "../frontend"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
|
||||
{
|
||||
"name": "Lidarr",
|
||||
"image": "mcr.microsoft.com/devcontainers/dotnet:1-6.0",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
"nodeGypDependencies": true,
|
||||
"version": "20",
|
||||
"nvmVersion": "latest"
|
||||
}
|
||||
},
|
||||
"forwardPorts": [8686],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": ["esbenp.prettier-vscode"]
|
||||
}
|
||||
}
|
||||
}
|
265
.editorconfig
265
.editorconfig
|
@ -2,275 +2,14 @@
|
|||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
# NOTE: Requires **VS2019 16.3** or later
|
||||
|
||||
# Stylecop.ruleset
|
||||
# Description: Rules for Lidarr
|
||||
|
||||
# Code files
|
||||
[*.cs]
|
||||
[*.{cs,html,js,hbs}]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
# Avoid "this." and "Me." if not necessary
|
||||
dotnet_style_qualification_for_field = false:warning
|
||||
dotnet_style_qualification_for_property = false:warning
|
||||
dotnet_style_qualification_for_method = false:warning
|
||||
dotnet_style_qualification_for_event = false:warning
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = flush_left
|
||||
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_naming_style.instance_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||
|
||||
# Prefer "var" everywhere
|
||||
csharp_style_var_for_built_in_types = true
|
||||
csharp_style_var_when_type_is_apparent = true
|
||||
csharp_style_var_elsewhere = true
|
||||
# Prefer "out" variables to be declared inline
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
|
||||
# Using directive is unnecessary.
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
||||
# Use var instead of explicit type
|
||||
dotnet_diagnostic.IDE0007.severity = error
|
||||
# Inline variable declaration
|
||||
dotnet_diagnostic.IDE0018.severity = error
|
||||
|
||||
# Stylecop Rules
|
||||
dotnet_diagnostic.SA0001.severity = none
|
||||
dotnet_diagnostic.SA1025.severity = none
|
||||
dotnet_diagnostic.SA1101.severity = none
|
||||
dotnet_diagnostic.SA1116.severity = none
|
||||
dotnet_diagnostic.SA1118.severity = none
|
||||
dotnet_diagnostic.SA1122.severity = none
|
||||
dotnet_diagnostic.SA1201.severity = suggestion
|
||||
dotnet_diagnostic.SA1202.severity = suggestion
|
||||
dotnet_diagnostic.SA1204.severity = suggestion
|
||||
dotnet_diagnostic.SA1300.severity = none
|
||||
dotnet_diagnostic.SA1303.severity = none
|
||||
dotnet_diagnostic.SA1304.severity = none
|
||||
dotnet_diagnostic.SA1306.severity = none
|
||||
dotnet_diagnostic.SA1309.severity = none
|
||||
dotnet_diagnostic.SA1310.severity = none
|
||||
dotnet_diagnostic.SA1401.severity = none
|
||||
dotnet_diagnostic.SA1402.severity = none
|
||||
dotnet_diagnostic.SA1404.severity = suggestion
|
||||
dotnet_diagnostic.SA1405.severity = suggestion
|
||||
dotnet_diagnostic.SA1406.severity = suggestion
|
||||
dotnet_diagnostic.SA1410.severity = suggestion
|
||||
dotnet_diagnostic.SA1411.severity = suggestion
|
||||
dotnet_diagnostic.SA1413.severity = none
|
||||
dotnet_diagnostic.SA1512.severity = none
|
||||
dotnet_diagnostic.SA1516.severity = none
|
||||
dotnet_diagnostic.SA1600.severity = none
|
||||
dotnet_diagnostic.SA1601.severity = none
|
||||
dotnet_diagnostic.SA1602.severity = none
|
||||
dotnet_diagnostic.SA1604.severity = none
|
||||
dotnet_diagnostic.SA1605.severity = none
|
||||
dotnet_diagnostic.SA1606.severity = none
|
||||
dotnet_diagnostic.SA1607.severity = none
|
||||
dotnet_diagnostic.SA1608.severity = none
|
||||
dotnet_diagnostic.SA1610.severity = none
|
||||
dotnet_diagnostic.SA1611.severity = none
|
||||
dotnet_diagnostic.SA1612.severity = none
|
||||
dotnet_diagnostic.SA1613.severity = none
|
||||
dotnet_diagnostic.SA1614.severity = none
|
||||
dotnet_diagnostic.SA1615.severity = none
|
||||
dotnet_diagnostic.SA1616.severity = none
|
||||
dotnet_diagnostic.SA1617.severity = none
|
||||
dotnet_diagnostic.SA1618.severity = none
|
||||
dotnet_diagnostic.SA1619.severity = none
|
||||
dotnet_diagnostic.SA1620.severity = none
|
||||
dotnet_diagnostic.SA1621.severity = none
|
||||
dotnet_diagnostic.SA1622.severity = none
|
||||
dotnet_diagnostic.SA1623.severity = none
|
||||
dotnet_diagnostic.SA1624.severity = none
|
||||
dotnet_diagnostic.SA1625.severity = none
|
||||
dotnet_diagnostic.SA1626.severity = none
|
||||
dotnet_diagnostic.SA1627.severity = none
|
||||
dotnet_diagnostic.SA1629.severity = none
|
||||
dotnet_diagnostic.SA1633.severity = none
|
||||
dotnet_diagnostic.SA1634.severity = none
|
||||
dotnet_diagnostic.SA1635.severity = none
|
||||
dotnet_diagnostic.SA1636.severity = none
|
||||
dotnet_diagnostic.SA1637.severity = none
|
||||
dotnet_diagnostic.SA1638.severity = none
|
||||
dotnet_diagnostic.SA1640.severity = none
|
||||
dotnet_diagnostic.SA1641.severity = none
|
||||
dotnet_diagnostic.SA1642.severity = none
|
||||
dotnet_diagnostic.SA1643.severity = none
|
||||
dotnet_diagnostic.SA1648.severity = none
|
||||
dotnet_diagnostic.SA1649.severity = none
|
||||
dotnet_diagnostic.SA1651.severity = none
|
||||
dotnet_diagnostic.SX1309.severity = warning
|
||||
|
||||
# Microsoft Analyzers that fail and need to be sorted thru
|
||||
dotnet_diagnostic.ASP0000.severity = suggestion
|
||||
dotnet_diagnostic.CA1000.severity = suggestion
|
||||
dotnet_diagnostic.CA1001.severity = suggestion
|
||||
dotnet_diagnostic.CA1002.severity = suggestion
|
||||
dotnet_diagnostic.CA1003.severity = suggestion
|
||||
dotnet_diagnostic.CA1008.severity = suggestion
|
||||
dotnet_diagnostic.CA1010.severity = suggestion
|
||||
dotnet_diagnostic.CA1012.severity = suggestion
|
||||
dotnet_diagnostic.CA1014.severity = suggestion
|
||||
dotnet_diagnostic.CA1016.severity = suggestion
|
||||
dotnet_diagnostic.CA1017.severity = suggestion
|
||||
dotnet_diagnostic.CA1018.severity = suggestion
|
||||
dotnet_diagnostic.CA1019.severity = suggestion
|
||||
dotnet_diagnostic.CA1021.severity = suggestion
|
||||
dotnet_diagnostic.CA1024.severity = suggestion
|
||||
dotnet_diagnostic.CA1027.severity = suggestion
|
||||
dotnet_diagnostic.CA1028.severity = suggestion
|
||||
dotnet_diagnostic.CA1030.severity = suggestion
|
||||
dotnet_diagnostic.CA1031.severity = suggestion
|
||||
dotnet_diagnostic.CA1032.severity = suggestion
|
||||
dotnet_diagnostic.CA1033.severity = suggestion
|
||||
dotnet_diagnostic.CA1034.severity = suggestion
|
||||
dotnet_diagnostic.CA1036.severity = suggestion
|
||||
dotnet_diagnostic.CA1040.severity = suggestion
|
||||
dotnet_diagnostic.CA1041.severity = suggestion
|
||||
dotnet_diagnostic.CA1043.severity = suggestion
|
||||
dotnet_diagnostic.CA1044.severity = suggestion
|
||||
dotnet_diagnostic.CA1050.severity = suggestion
|
||||
dotnet_diagnostic.CA1051.severity = suggestion
|
||||
dotnet_diagnostic.CA1052.severity = suggestion
|
||||
dotnet_diagnostic.CA1054.severity = suggestion
|
||||
dotnet_diagnostic.CA1055.severity = suggestion
|
||||
dotnet_diagnostic.CA1056.severity = suggestion
|
||||
dotnet_diagnostic.CA1058.severity = suggestion
|
||||
dotnet_diagnostic.CA1060.severity = suggestion
|
||||
dotnet_diagnostic.CA1061.severity = suggestion
|
||||
dotnet_diagnostic.CA1062.severity = suggestion
|
||||
dotnet_diagnostic.CA1063.severity = suggestion
|
||||
dotnet_diagnostic.CA1064.severity = suggestion
|
||||
dotnet_diagnostic.CA1065.severity = suggestion
|
||||
dotnet_diagnostic.CA1066.severity = suggestion
|
||||
dotnet_diagnostic.CA1067.severity = suggestion
|
||||
dotnet_diagnostic.CA1068.severity = suggestion
|
||||
dotnet_diagnostic.CA1069.severity = suggestion
|
||||
dotnet_diagnostic.CA1200.severity = suggestion
|
||||
dotnet_diagnostic.CA1303.severity = suggestion
|
||||
dotnet_diagnostic.CA1304.severity = suggestion
|
||||
dotnet_diagnostic.CA1305.severity = suggestion
|
||||
dotnet_diagnostic.CA1307.severity = suggestion
|
||||
dotnet_diagnostic.CA1308.severity = suggestion
|
||||
dotnet_diagnostic.CA1309.severity = suggestion
|
||||
dotnet_diagnostic.CA1310.severity = suggestion
|
||||
dotnet_diagnostic.CA1401.severity = suggestion
|
||||
dotnet_diagnostic.CA1416.severity = suggestion
|
||||
dotnet_diagnostic.CA1419.severity = suggestion
|
||||
dotnet_diagnostic.CA1507.severity = suggestion
|
||||
dotnet_diagnostic.CA1508.severity = suggestion
|
||||
dotnet_diagnostic.CA1707.severity = suggestion
|
||||
dotnet_diagnostic.CA1708.severity = suggestion
|
||||
dotnet_diagnostic.CA1710.severity = suggestion
|
||||
dotnet_diagnostic.CA1711.severity = suggestion
|
||||
dotnet_diagnostic.CA1712.severity = suggestion
|
||||
dotnet_diagnostic.CA1714.severity = suggestion
|
||||
dotnet_diagnostic.CA1715.severity = suggestion
|
||||
dotnet_diagnostic.CA1716.severity = suggestion
|
||||
dotnet_diagnostic.CA1717.severity = suggestion
|
||||
dotnet_diagnostic.CA1720.severity = suggestion
|
||||
dotnet_diagnostic.CA1721.severity = suggestion
|
||||
dotnet_diagnostic.CA1724.severity = suggestion
|
||||
dotnet_diagnostic.CA1725.severity = suggestion
|
||||
dotnet_diagnostic.CA1806.severity = suggestion
|
||||
dotnet_diagnostic.CA1810.severity = suggestion
|
||||
dotnet_diagnostic.CA1812.severity = suggestion
|
||||
dotnet_diagnostic.CA1813.severity = suggestion
|
||||
dotnet_diagnostic.CA1814.severity = suggestion
|
||||
dotnet_diagnostic.CA1815.severity = suggestion
|
||||
dotnet_diagnostic.CA1816.severity = suggestion
|
||||
dotnet_diagnostic.CA1819.severity = suggestion
|
||||
dotnet_diagnostic.CA1822.severity = suggestion
|
||||
dotnet_diagnostic.CA1823.severity = suggestion
|
||||
dotnet_diagnostic.CA1824.severity = suggestion
|
||||
dotnet_diagnostic.CA1848.severity = suggestion
|
||||
dotnet_diagnostic.CA2000.severity = suggestion
|
||||
dotnet_diagnostic.CA2002.severity = suggestion
|
||||
dotnet_diagnostic.CA2007.severity = suggestion
|
||||
dotnet_diagnostic.CA2008.severity = suggestion
|
||||
dotnet_diagnostic.CA2012.severity = suggestion
|
||||
dotnet_diagnostic.CA2013.severity = suggestion
|
||||
dotnet_diagnostic.CA2100.severity = suggestion
|
||||
dotnet_diagnostic.CA2101.severity = suggestion
|
||||
dotnet_diagnostic.CA2119.severity = suggestion
|
||||
dotnet_diagnostic.CA2153.severity = suggestion
|
||||
dotnet_diagnostic.CA2200.severity = suggestion
|
||||
dotnet_diagnostic.CA2201.severity = suggestion
|
||||
dotnet_diagnostic.CA2207.severity = suggestion
|
||||
dotnet_diagnostic.CA2208.severity = suggestion
|
||||
dotnet_diagnostic.CA2211.severity = suggestion
|
||||
dotnet_diagnostic.CA2213.severity = suggestion
|
||||
dotnet_diagnostic.CA2214.severity = suggestion
|
||||
dotnet_diagnostic.CA2215.severity = suggestion
|
||||
dotnet_diagnostic.CA2216.severity = suggestion
|
||||
dotnet_diagnostic.CA2219.severity = suggestion
|
||||
dotnet_diagnostic.CA2225.severity = suggestion
|
||||
dotnet_diagnostic.CA2226.severity = suggestion
|
||||
dotnet_diagnostic.CA2227.severity = suggestion
|
||||
dotnet_diagnostic.CA2229.severity = suggestion
|
||||
dotnet_diagnostic.CA2231.severity = suggestion
|
||||
dotnet_diagnostic.CA2234.severity = suggestion
|
||||
dotnet_diagnostic.CA2235.severity = suggestion
|
||||
dotnet_diagnostic.CA2237.severity = suggestion
|
||||
dotnet_diagnostic.CA2241.severity = suggestion
|
||||
dotnet_diagnostic.CA2242.severity = suggestion
|
||||
dotnet_diagnostic.CA2243.severity = suggestion
|
||||
dotnet_diagnostic.CA2244.severity = suggestion
|
||||
dotnet_diagnostic.CA2245.severity = suggestion
|
||||
dotnet_diagnostic.CA2246.severity = suggestion
|
||||
dotnet_diagnostic.CA2249.severity = suggestion
|
||||
dotnet_diagnostic.CA2251.severity = suggestion
|
||||
dotnet_diagnostic.CA2254.severity = suggestion
|
||||
dotnet_diagnostic.CA3061.severity = suggestion
|
||||
dotnet_diagnostic.CA3075.severity = suggestion
|
||||
dotnet_diagnostic.CA3076.severity = suggestion
|
||||
dotnet_diagnostic.CA3077.severity = suggestion
|
||||
dotnet_diagnostic.CA3147.severity = suggestion
|
||||
dotnet_diagnostic.CA5350.severity = suggestion
|
||||
dotnet_diagnostic.CA5351.severity = suggestion
|
||||
dotnet_diagnostic.CA5359.severity = suggestion
|
||||
dotnet_diagnostic.CA5360.severity = suggestion
|
||||
dotnet_diagnostic.CA5363.severity = suggestion
|
||||
dotnet_diagnostic.CA5364.severity = suggestion
|
||||
dotnet_diagnostic.CA5365.severity = suggestion
|
||||
dotnet_diagnostic.CA5366.severity = suggestion
|
||||
dotnet_diagnostic.CA5368.severity = suggestion
|
||||
dotnet_diagnostic.CA5369.severity = suggestion
|
||||
dotnet_diagnostic.CA5370.severity = suggestion
|
||||
dotnet_diagnostic.CA5371.severity = suggestion
|
||||
dotnet_diagnostic.CA5372.severity = suggestion
|
||||
dotnet_diagnostic.CA5373.severity = suggestion
|
||||
dotnet_diagnostic.CA5374.severity = suggestion
|
||||
dotnet_diagnostic.CA5379.severity = suggestion
|
||||
dotnet_diagnostic.CA5384.severity = suggestion
|
||||
dotnet_diagnostic.CA5385.severity = suggestion
|
||||
dotnet_diagnostic.CA5392.severity = suggestion
|
||||
dotnet_diagnostic.CA5394.severity = suggestion
|
||||
dotnet_diagnostic.CA5397.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.SYSLIB0006.severity = none
|
||||
|
||||
[*.{js,html,hbs,less,css,ts,tsx}]
|
||||
[*.less]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
|
9
.esprintrc
Normal file
9
.esprintrc
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"paths": [
|
||||
"frontend/src/**/*.js"
|
||||
],
|
||||
"ignored": [
|
||||
"**/node_modules/**/*"
|
||||
],
|
||||
"port": 5004
|
||||
}
|
22
.gitattributes
vendored
22
.gitattributes
vendored
|
@ -1,10 +1,22 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Explicitly set bash scripts to have unix endings
|
||||
*.sh text eol=lf
|
||||
distribution/osx/Lidarr text eol=lf
|
||||
*text eol=lf
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
*.sln merge=union
|
||||
*.csproj merge=union
|
||||
*.vbproj merge=union
|
||||
*.fsproj merge=union
|
||||
*.dbproj merge=union
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
9
.github/FUNDING.yml
vendored
9
.github/FUNDING.yml
vendored
|
@ -1,9 +0,0 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: lidarr # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: lidarr
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
custom: # Replace with a single custom sponsorship URL
|
41
.github/ISSUE_TEMPLATE.md
vendored
Normal file
41
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
<!--
|
||||
Before opening a new issue, please ensure:
|
||||
- You use the discord for support/questions
|
||||
- You search for existing bugs/feature requests
|
||||
- Remove extraneous template details
|
||||
-->
|
||||
|
||||
## Support / Questions
|
||||
|
||||
Please use https://discord.gg/8Y7rDc9 for support. Support requests or questions will be redirected to discord and the issue will be closed.
|
||||
|
||||
<!--
|
||||
Remove if not opening a bug report
|
||||
-->
|
||||
|
||||
## Bug Report
|
||||
|
||||
### System Information/Logs
|
||||
|
||||
**Lidarr Version:**
|
||||
|
||||
**Operating System:**
|
||||
|
||||
**.net Framework (Windows) or mono (macOS/Linux) Version:**
|
||||
|
||||
**Link to Log Files (debug or trace):**
|
||||
|
||||
**Browser (for UI bugs):**
|
||||
|
||||
### Additional Information
|
||||
|
||||
<!--
|
||||
Remove if not opening a feature request
|
||||
-->
|
||||
|
||||
## Feature Request
|
||||
|
||||
### Description of request and what problem are you looking to solve?
|
||||
|
||||
### Other Information
|
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Logs**
|
||||
Link to debug logs.
|
||||
|
||||
**System info (please complete the following information):**
|
||||
- Lidarr Version: [e.g. 0.3.0.430]
|
||||
- Operating System [e.g. iOS]
|
||||
- .net Framework (Windows) or mono (macOS/Linux) Version: [e.g. 4.5 or 5.12]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
83
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
83
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -1,83 +0,0 @@
|
|||
name: Bug Report
|
||||
description: 'Report a new bug, if you are not 100% certain this is a bug please go to our Discord first'
|
||||
labels: ['Type: Bug', 'Status: Needs Triage']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an open or closed issue already exists for the bug you encountered. If a bug exists and is closed note that it may only be fixed in an unstable branch.
|
||||
options:
|
||||
- label: I have searched the existing open and closed issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: A concise description of what you're experiencing.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: |
|
||||
1. In this environment...
|
||||
2. With this config...
|
||||
3. Run '...'
|
||||
4. See error...
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Environment
|
||||
description: |
|
||||
examples:
|
||||
- **OS**: Ubuntu 20.04
|
||||
- **Lidarr**: Lidarr 0.8.1.2135
|
||||
- **Docker Install**: Yes
|
||||
- **Using Reverse Proxy**: No
|
||||
- **Browser**: Firefox 90 (If UI related)
|
||||
- **Database**: Sqlite 3.36.0
|
||||
value: |
|
||||
- OS:
|
||||
- Lidarr:
|
||||
- Docker Install:
|
||||
- Using Reverse Proxy:
|
||||
- Browser:
|
||||
- Database:
|
||||
render: markdown
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: What branch are you running?
|
||||
options:
|
||||
- Master
|
||||
- Develop
|
||||
- Nightly
|
||||
- Plugins (experimental)
|
||||
- Other (This issue will be closed)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Trace Logs?
|
||||
description: |
|
||||
Trace Logs (https://wiki.servarr.com/lidarr/troubleshooting#logging-and-log-files)
|
||||
***Generally speaking, all bug reports must have trace logs provided.***
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Trace Logs have been provided as applicable. Reports may be closed if the required logs are not provided.
|
||||
description: Trace logs are generally required for all bug reports and contain `trace`. Info logs are invalid for bug reports and do not contain `debug` nor `trace`
|
||||
options:
|
||||
- label: I have read and followed the steps in the wiki link above and provided the required trace logs - the logs contain `trace` - that are relevant and show this issue.
|
||||
required: true
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,5 +0,0 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Support via Discord
|
||||
url: https://lidarr.audio/discord
|
||||
about: Chat with users and devs on support and setup related topics.
|
7
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: Custom issue template
|
||||
about: Describe this issue template's purpose here.
|
||||
|
||||
---
|
||||
|
||||
|
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
@ -1,38 +0,0 @@
|
|||
name: Feature Request
|
||||
description: 'Suggest an idea for Lidarr'
|
||||
labels: ['Type: Feature Request', 'Status: Needs Triage']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an open or closed issue already exists for the feature you are requesting. If a request exists and is closed note that it may only be fixed in an unstable branch.
|
||||
options:
|
||||
- label: I have searched the existing open and closed issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe
|
||||
description: A clear and concise description of what the problem is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: true
|
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,16 +1,14 @@
|
|||
#### Database Migration
|
||||
YES - XXXX | NO
|
||||
YES | NO
|
||||
|
||||
#### Description
|
||||
A few sentences describing the overall goals of the pull request's commits.
|
||||
|
||||
#### Screenshot (if UI related)
|
||||
|
||||
#### Todos
|
||||
- [ ] Tests
|
||||
- [ ] Translation Keys (./src/NzbDrone.Core/Localization/Core/en.json)
|
||||
- [ ] [Wiki Updates](https://wiki.servarr.com)
|
||||
- [ ] Documentation
|
||||
|
||||
|
||||
#### Issues Fixed or Closed by this PR
|
||||
|
||||
* Fixes #XXXX
|
||||
*
|
||||
|
|
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
|
@ -1,12 +0,0 @@
|
|||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for more information:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# https://containers.dev/guide/dependabot
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "devcontainers"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
16
.github/label-actions.yml
vendored
16
.github/label-actions.yml
vendored
|
@ -1,16 +0,0 @@
|
|||
# Configuration for Label Actions - https://github.com/dessant/label-actions
|
||||
|
||||
'Type: Support':
|
||||
comment: >
|
||||
:wave: @{issue-author}, we use the issue tracker exclusively
|
||||
for bug reports and feature requests. However, this issue appears
|
||||
to be a support request. Please hop over onto our [Discord](https://lidarr.audio/discord).
|
||||
close: true
|
||||
close-reason: 'not planned'
|
||||
|
||||
'Status: Logs Needed':
|
||||
comment: >
|
||||
:wave: @{issue-author}, In order to help you further we'll need to see logs.
|
||||
You'll need to enable trace logging and replicate the problem that you encountered.
|
||||
Guidance on how to enable trace logging can be found in
|
||||
our [troubleshooting guide](https://wiki.servarr.com/lidarr/troubleshooting#logging-and-log-files).
|
28
.github/labeler.yml
vendored
28
.github/labeler.yml
vendored
|
@ -1,28 +0,0 @@
|
|||
'Area: API':
|
||||
- src/Lidarr.Api.V1/**/*
|
||||
|
||||
'Area: Db-migration':
|
||||
- src/NzbDrone.Core/Datastore/Migration/*
|
||||
|
||||
'Area: Download Clients':
|
||||
- src/NzbDrone.Core/Download/Clients/**/*
|
||||
|
||||
'Area: Import Lists':
|
||||
- src/NzbDrone.Core/ImportLists/**/*
|
||||
|
||||
'Area: Indexer':
|
||||
- src/NzbDrone.Core/Indexers/**/*
|
||||
|
||||
'Area: Notifications':
|
||||
- src/NzbDrone.Core/Notifications/**/*
|
||||
|
||||
'Area: Organizer':
|
||||
- src/NzbDrone.Core/Organizer/**/*
|
||||
|
||||
'Area: Parser':
|
||||
- src/NzbDrone.Core/Parser/**/*
|
||||
|
||||
'Area: UI':
|
||||
- frontend/**/*
|
||||
- package.json
|
||||
- yarn.lock
|
17
.github/workflows/label-actions.yml
vendored
17
.github/workflows/label-actions.yml
vendored
|
@ -1,17 +0,0 @@
|
|||
name: 'Label Actions'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/label-actions@v4
|
||||
with:
|
||||
process-only: 'issues'
|
12
.github/workflows/labeler.yml
vendored
12
.github/workflows/labeler.yml
vendored
|
@ -1,12 +0,0 @@
|
|||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
21
.github/workflows/lock.yml
vendored
21
.github/workflows/lock.yml
vendored
|
@ -1,21 +0,0 @@
|
|||
name: 'Lock threads'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '90'
|
||||
exclude-issue-created-before: ''
|
||||
exclude-any-issue-labels: ''
|
||||
add-issue-labels: ''
|
||||
issue-comment: ''
|
||||
issue-lock-reason: 'resolved'
|
||||
process-only: ''
|
38
.gitignore
vendored
38
.gitignore
vendored
|
@ -11,7 +11,6 @@ src/**/[Oo]bj/
|
|||
*.user
|
||||
*.sln.docstates
|
||||
.vs/
|
||||
.vscode/
|
||||
|
||||
# Build results
|
||||
*_i.c
|
||||
|
@ -85,6 +84,7 @@ TestResults
|
|||
[Tt]est[Rr]esult*
|
||||
*.Cache
|
||||
ClientBin
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*.dbmdl
|
||||
Generated_Code #added for RIA/Silverlight projects
|
||||
|
@ -121,49 +121,23 @@ _artifacts
|
|||
_rawPackage/
|
||||
_dotTrace*
|
||||
_tests/
|
||||
_temp*
|
||||
*.Result.xml
|
||||
coverage*.xml
|
||||
coverage*.json
|
||||
setup/Output/
|
||||
*.~is
|
||||
.mono
|
||||
|
||||
# VS outout folders
|
||||
#VS outout folders
|
||||
bin
|
||||
obj
|
||||
output/*
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# macOS metadata files
|
||||
#OS X metadata files
|
||||
._*
|
||||
.DS_Store
|
||||
|
||||
_start
|
||||
_temp_*/**/*
|
||||
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
|
||||
# AppVeyor
|
||||
/tools/cake/
|
||||
/_artifacts/
|
||||
|
||||
# Cake
|
||||
/tools/Addins/*
|
||||
packages.config.md5sum
|
||||
|
||||
# ignore node_modules symlink
|
||||
node_modules
|
||||
node_modules.nosync
|
||||
|
||||
# API doc generation
|
||||
.config/
|
||||
|
||||
# Ignore Jetbrains IntelliJ Workspace Directories
|
||||
.idea/
|
||||
## Merge any idea folder
|
||||
*/**/.idea
|
||||
*.iml
|
||||
|
|
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[submodule "src/ExternalModules/CurlSharp"]
|
||||
path = src/ExternalModules/CurlSharp
|
||||
url = https://github.com/Sonarr/CurlSharp.git
|
||||
branch = master
|
35
.travis.yml
Normal file
35
.travis.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
language: csharp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- dos2unix
|
||||
- libchromaprint-tools
|
||||
update: true
|
||||
homebrew:
|
||||
packages:
|
||||
- yarn
|
||||
- dos2unix
|
||||
update: true
|
||||
|
||||
solution: src/Lidarr.sln
|
||||
|
||||
before_install:
|
||||
- nvm install 10
|
||||
- nvm use 10
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0
|
||||
- export PATH=$HOME/.yarn/bin:$PATH
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
script:
|
||||
- ./build.sh
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./test.sh Mac Unit; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test.sh Linux Unit; fi
|
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"ms-dotnettools.csdevkit",
|
||||
"ms-vscode-remote.remote-containers"
|
||||
]
|
||||
}
|
26
.vscode/launch.json
vendored
26
.vscode/launch.json
vendored
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
|
||||
"name": "Run Lidarr",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build dotnet",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/_output/net6.0/Lidarr",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "integratedTerminal",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
44
.vscode/tasks.json
vendored
44
.vscode/tasks.json
vendored
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build dotnet",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"msbuild",
|
||||
"-restore",
|
||||
"${workspaceFolder}/src/Lidarr.sln",
|
||||
"-p:GenerateFullPaths=true",
|
||||
"-p:Configuration=Debug",
|
||||
"-p:Platform=Posix",
|
||||
"-consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/src/Lidarr.sln",
|
||||
"-property:GenerateFullPaths=true",
|
||||
"-consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/src/Lidarr.sln"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
<development@lidarr.audio>.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
|
@ -1,13 +1,50 @@
|
|||
# How to Contribute
|
||||
# How to Contribute #
|
||||
|
||||
We're always looking for people to help make Lidarr even better, there are a number of ways to contribute.
|
||||
|
||||
This file has been moved to the wiki for the latest details please see the [contributing wiki page](https://wiki.servarr.com/lidarr/contributing).
|
||||
## Documentation ##
|
||||
Setup guides, FAQ, the more information we have on the wiki the better.
|
||||
|
||||
## Documentation
|
||||
## Development ##
|
||||
|
||||
Setup guides, [FAQ](https://wiki.servarr.com/lidarr/faq), the more information we have on the [wiki](https://wiki.servarr.com/lidarr) the better.
|
||||
### Tools required ###
|
||||
- Visual Studio 2017 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
|
||||
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [NodeJS](https://nodejs.org/en/download/) (Node 8.X.X or higher)
|
||||
- [Yarn](https://yarnpkg.com/)
|
||||
- .NET 4.6.1 or Mono equivalent.
|
||||
|
||||
## Development
|
||||
### Getting started ###
|
||||
|
||||
See the [Wiki Page](https://wiki.servarr.com/lidarr/contributing)
|
||||
1. Fork Lidarr
|
||||
2. Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
|
||||
3. Grab the submodules `git submodule init && git submodule update`
|
||||
4. Install the required Node Packages `yarn install`
|
||||
5. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
|
||||
6. Build the project in Visual Studio, Setting startup project to `NZBDrone.Console`
|
||||
7. Debug the project in Visual Studio
|
||||
8. Open http://localhost:8686
|
||||
|
||||
### Contributing Code ###
|
||||
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/lidarr/Lidarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
|
||||
- Rebase from Lidarr's develop branch, don't merge
|
||||
- Make meaningful commits, or squash them
|
||||
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
|
||||
- Reach out to us on the discord if you have any questions
|
||||
- Add tests (unit/integration)
|
||||
- Commit with *nix line endings for consistency (We checkout Windows and commit *nix)
|
||||
- One feature/bug fix per pull request to keep things clean and easy to understand
|
||||
- Use 4 spaces instead of tabs, this is the default for VS 2017 and WebStorm (to my knowledge)
|
||||
|
||||
### Pull Requesting ###
|
||||
- Only make pull requests to develop, never master, if you make a PR to master we'll comment on it and close it
|
||||
- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability
|
||||
- We'll try to respond to pull requests as soon as possible, if its been a day or two, please reach out to us, we may have missed it
|
||||
- Each PR should come from its own [feature branch](http://martinfowler.com/bliki/FeatureBranch.html) not develop in your fork, it should have a meaningful branch name (what is being added/fixed)
|
||||
- new-feature (Good)
|
||||
- fix-bug (Good)
|
||||
- patch (Bad)
|
||||
- develop (Bad)
|
||||
|
||||
If you have any questions about any of this, please let us know.
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-1.3318" y1="43.7371" x2="67.0419" y2="26.0967">
|
||||
<stop offset="0.1237" style="stop-color:#7866FF"/>
|
||||
<stop offset="0.5376" style="stop-color:#FE2EB6"/>
|
||||
<stop offset="0.8548" style="stop-color:#FD0486"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="67.3,16 43.7,0 0,31.1 11.1,70 58.9,60.3 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="45.9148" y1="38.9098" x2="67.6577" y2="9.0989">
|
||||
<stop offset="0.1237" style="stop-color:#FF0080"/>
|
||||
<stop offset="0.2587" style="stop-color:#FE0385"/>
|
||||
<stop offset="0.4109" style="stop-color:#FA0C92"/>
|
||||
<stop offset="0.5713" style="stop-color:#F41BA9"/>
|
||||
<stop offset="0.7363" style="stop-color:#EB2FC8"/>
|
||||
<stop offset="0.8656" style="stop-color:#E343E6"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="67.3,16 43.7,0 38,15.7 38,47.8 70,47.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
<rect x="17.4" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<g>
|
||||
<path style="fill:#FFFFFF;" d="M17.4,19.1h6.9c5.6,0,9.5,3.8,9.5,8.9V28c0,5-3.9,8.9-9.5,8.9h-6.9V19.1z M21.4,22.7v10.7h3
|
||||
c3.2,0,5.4-2.2,5.4-5.3V28c0-3.2-2.2-5.4-5.4-5.4H21.4z"/>
|
||||
<polygon style="fill:#FFFFFF;" points="40.3,22.7 34.9,22.7 34.9,19.1 49.6,19.1 49.6,22.7 44.2,22.7 44.2,37 40.3,37 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.8 KiB |
|
@ -1,66 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="120.1px" height="130.2px" viewBox="0 0 120.1 130.2" style="enable-background:new 0 0 120.1 130.2;" xml:space="preserve"
|
||||
>
|
||||
<g>
|
||||
<linearGradient id="XMLID_2_" gradientUnits="userSpaceOnUse" x1="31.8412" y1="120.5578" x2="110.2402" y2="73.24">
|
||||
<stop offset="0" style="stop-color:#FCEE39"/>
|
||||
<stop offset="1" style="stop-color:#F37B3D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3041_" style="fill:url(#XMLID_2_);" d="M118.6,71.8c0.9-0.8,1.4-1.9,1.5-3.2c0.1-2.6-1.8-4.7-4.4-4.9
|
||||
c-1.2-0.1-2.4,0.4-3.3,1.1l0,0l-83.8,45.9c-1.9,0.8-3.6,2.2-4.7,4.1c-2.9,4.8-1.3,11,3.6,13.9c3.4,2,7.5,1.8,10.7-0.2l0,0l0,0
|
||||
c0.2-0.2,0.5-0.3,0.7-0.5l78-54.8C117.3,72.9,118.4,72.1,118.6,71.8L118.6,71.8L118.6,71.8z"/>
|
||||
<linearGradient id="XMLID_3_" gradientUnits="userSpaceOnUse" x1="48.3607" y1="6.9083" x2="119.9179" y2="69.5546">
|
||||
<stop offset="0" style="stop-color:#EF5A6B"/>
|
||||
<stop offset="0.57" style="stop-color:#F26F4E"/>
|
||||
<stop offset="1" style="stop-color:#F37B3D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3049_" style="fill:url(#XMLID_3_);" d="M118.8,65.1L118.8,65.1L55,2.5C53.6,1,51.6,0,49.3,0
|
||||
c-4.3,0-7.7,3.5-7.7,7.7v0c0,2.1,0.8,3.9,2.1,5.3l0,0l0,0c0.4,0.4,0.8,0.7,1.2,1l67.4,57.7l0,0c0.8,0.7,1.8,1.2,3,1.3
|
||||
c2.6,0.1,4.7-1.8,4.9-4.4C120.2,67.3,119.7,66,118.8,65.1z"/>
|
||||
<linearGradient id="XMLID_4_" gradientUnits="userSpaceOnUse" x1="52.9467" y1="63.6407" x2="10.5379" y2="37.1562">
|
||||
<stop offset="0" style="stop-color:#7C59A4"/>
|
||||
<stop offset="0.3852" style="stop-color:#AF4C92"/>
|
||||
<stop offset="0.7654" style="stop-color:#DC4183"/>
|
||||
<stop offset="0.957" style="stop-color:#ED3D7D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3042_" style="fill:url(#XMLID_4_);" d="M57.1,59.5C57,59.5,17.7,28.5,16.9,28l0,0l0,0c-0.6-0.3-1.2-0.6-1.8-0.9
|
||||
c-5.8-2.2-12.2,0.8-14.4,6.6c-1.9,5.1,0.2,10.7,4.6,13.4l0,0l0,0C6,47.5,6.6,47.8,7.3,48c0.4,0.2,45.4,18.8,45.4,18.8l0,0
|
||||
c1.8,0.8,3.9,0.3,5.1-1.2C59.3,63.7,59,61,57.1,59.5z"/>
|
||||
<linearGradient id="XMLID_5_" gradientUnits="userSpaceOnUse" x1="52.1736" y1="3.7019" x2="10.7706" y2="37.8971">
|
||||
<stop offset="0" style="stop-color:#EF5A6B"/>
|
||||
<stop offset="0.364" style="stop-color:#EE4E72"/>
|
||||
<stop offset="1" style="stop-color:#ED3D7D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3057_" style="fill:url(#XMLID_5_);" d="M49.3,0c-1.7,0-3.3,0.6-4.6,1.5L4.9,28.3c-0.1,0.1-0.2,0.1-0.2,0.2l-0.1,0
|
||||
l0,0c-1.7,1.2-3.1,3-3.9,5.1C-1.5,39.4,1.5,45.9,7.3,48c3.6,1.4,7.5,0.7,10.4-1.4l0,0l0,0c0.7-0.5,1.3-1,1.8-1.6l34.6-31.2l0,0
|
||||
c1.8-1.4,3-3.6,3-6.1v0C57.1,3.5,53.6,0,49.3,0z"/>
|
||||
<g id="XMLID_3008_">
|
||||
<rect id="XMLID_3033_" x="34.6" y="37.4" style="fill:#000000;" width="51" height="51"/>
|
||||
<rect id="XMLID_3032_" x="39" y="78.8" style="fill:#FFFFFF;" width="19.1" height="3.2"/>
|
||||
<g id="XMLID_3009_">
|
||||
<path id="XMLID_3030_" style="fill:#FFFFFF;" d="M38.8,50.8l1.5-1.4c0.4,0.5,0.8,0.8,1.3,0.8c0.6,0,0.9-0.4,0.9-1.2l0-5.3l2.3,0
|
||||
l0,5.3c0,1-0.3,1.8-0.8,2.3c-0.5,0.5-1.3,0.8-2.3,0.8C40.2,52.2,39.4,51.6,38.8,50.8z"/>
|
||||
<path id="XMLID_3028_" style="fill:#FFFFFF;" d="M45.3,43.8l6.7,0v1.9l-4.4,0V47l4,0l0,1.8l-4,0l0,1.3l4.5,0l0,2l-6.7,0
|
||||
L45.3,43.8z"/>
|
||||
<path id="XMLID_3026_" style="fill:#FFFFFF;" d="M55,45.8l-2.5,0l0-2l7.3,0l0,2l-2.5,0l0,6.3l-2.3,0L55,45.8z"/>
|
||||
<path id="XMLID_3022_" style="fill:#FFFFFF;" d="M39,54l4.3,0c1,0,1.8,0.3,2.3,0.7c0.3,0.3,0.5,0.8,0.5,1.4v0
|
||||
c0,1-0.5,1.5-1.3,1.9c1,0.3,1.6,0.9,1.6,2v0c0,1.4-1.2,2.3-3.1,2.3l-4.3,0L39,54z M43.8,56.6c0-0.5-0.4-0.7-1-0.7l-1.5,0l0,1.5
|
||||
l1.4,0C43.4,57.3,43.8,57.1,43.8,56.6L43.8,56.6z M43,59l-1.8,0l0,1.5H43c0.7,0,1.1-0.3,1.1-0.8v0C44.1,59.2,43.7,59,43,59z"/>
|
||||
<path id="XMLID_3019_" style="fill:#FFFFFF;" d="M46.8,54l3.9,0c1.3,0,2.1,0.3,2.7,0.9c0.5,0.5,0.7,1.1,0.7,1.9v0
|
||||
c0,1.3-0.7,2.1-1.7,2.6l2,2.9l-2.6,0l-1.7-2.5h-1l0,2.5l-2.3,0L46.8,54z M50.6,58c0.8,0,1.2-0.4,1.2-1v0c0-0.7-0.5-1-1.2-1
|
||||
l-1.5,0v2H50.6z"/>
|
||||
<path id="XMLID_3016_" style="fill:#FFFFFF;" d="M56.8,54l2.2,0l3.5,8.4l-2.5,0l-0.6-1.5l-3.2,0l-0.6,1.5l-2.4,0L56.8,54z
|
||||
M58.8,59l-0.9-2.3L57,59L58.8,59z"/>
|
||||
<path id="XMLID_3014_" style="fill:#FFFFFF;" d="M62.8,54l2.3,0l0,8.3l-2.3,0L62.8,54z"/>
|
||||
<path id="XMLID_3012_" style="fill:#FFFFFF;" d="M65.7,54l2.1,0l3.4,4.4l0-4.4l2.3,0l0,8.3l-2,0L68,57.8l0,4.6l-2.3,0L65.7,54z"
|
||||
/>
|
||||
<path id="XMLID_3010_" style="fill:#FFFFFF;" d="M73.7,61.1l1.3-1.5c0.8,0.7,1.7,1,2.7,1c0.6,0,1-0.2,1-0.6v0
|
||||
c0-0.4-0.3-0.5-1.4-0.8c-1.8-0.4-3.1-0.9-3.1-2.6v0c0-1.5,1.2-2.7,3.2-2.7c1.4,0,2.5,0.4,3.4,1.1l-1.2,1.6
|
||||
c-0.8-0.5-1.6-0.8-2.3-0.8c-0.6,0-0.8,0.2-0.8,0.5v0c0,0.4,0.3,0.5,1.4,0.8c1.9,0.4,3.1,1,3.1,2.6v0c0,1.7-1.3,2.7-3.4,2.7
|
||||
C76.1,62.5,74.7,62,73.7,61.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.8 KiB |
|
@ -1,50 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="22.9451" y1="75.7869" x2="74.7868" y2="20.6415">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.4044" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.4677" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.6505" style="stop-color:#EB8523"/>
|
||||
<stop offset="0.9516" style="stop-color:#FEBD11"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="49.8,15.2 36,36.7 58.4,70 70,23.1 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="17.7187" y1="73.2922" x2="69.5556" y2="18.1519">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.4044" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.4677" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.7043" style="stop-color:#EB8523"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="51.1,15.7 49,0 18.8,33.6 27.6,42.3 20.8,70 58.4,70 "/>
|
||||
</g>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1.8281" y1="53.4275" x2="48.8245" y2="9.2255">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.6613" style="stop-color:#C41E57"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_3_);" points="49,0 11.6,0 0,47.1 55.6,47.1 "/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="49.8935" y1="-11.5569" x2="48.8588" y2="24.0352">
|
||||
<stop offset="0.5" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.6668" style="stop-color:#D13F48"/>
|
||||
<stop offset="0.7952" style="stop-color:#D94F39"/>
|
||||
<stop offset="0.8656" style="stop-color:#DD5433"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_4_);" points="55.3,47.1 51.1,15.7 49,0 41.7,23 "/>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<rect x="13.4" y="13.5" transform="matrix(-1 2.577289e-003 -2.577289e-003 -1 70.0288 70.081)" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
|
||||
<rect x="17.6" y="48.6" transform="matrix(1 -2.577289e-003 2.577289e-003 1 -0.1287 6.634109e-002)" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<path style="fill:#FFFFFF;" d="M17.4,19.1l8.2,0c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1l0,0.1c0,1.5-0.3,2.6-1.1,3.5
|
||||
c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4l-4.6,0l-3.7-5.5l-3.3,0l0,5.5l-3.9,0L17.4,19.1z M25.3,27.8c1,0,1.7-0.2,2.2-0.7
|
||||
c0.5-0.5,0.8-1.1,0.8-1.8l0-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6l-3.9,0l0,5.1L25.3,27.8z"/>
|
||||
<path style="fill:#FFFFFF;" d="M36,33.2l-1.9,0l0-3.3l2.5,0l0.6-3.8l-2.3,0l0-3.3l2.8,0l0.6-3.7l3.4,0l-0.6,3.7l3.7,0l0.6-3.7
|
||||
l3.4,0l-0.6,3.7l1.9,0l0,3.3l-2.5,0L47,29.9l2.3,0l0,3.3l-2.8,0L45.8,37l-3.4,0l0.7-3.8l-3.7,0L38.7,37l-3.4,0L36,33.2z
|
||||
M43.7,29.9l0.6-3.8l-3.7,0L40,29.9L43.7,29.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.1 KiB |
|
@ -1,42 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="70.22612" y1="27.79912" x2="-5.13024" y2="63.12242" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#c90f5e"/>
|
||||
<stop offset="0.22111" stop-color="#c90f5e"/>
|
||||
<stop offset="0.2356" stop-color="#c90f5e"/>
|
||||
<stop offset="0.35559" stop-color="#ca135c"/>
|
||||
<stop offset="0.46633" stop-color="#ce1e57"/>
|
||||
<stop offset="0.5735" stop-color="#d4314e"/>
|
||||
<stop offset="0.67844" stop-color="#dc4b41"/>
|
||||
<stop offset="0.78179" stop-color="#e66d31"/>
|
||||
<stop offset="0.88253" stop-color="#f3961d"/>
|
||||
<stop offset="0.94241" stop-color="#fcb20f"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="24.65904" y1="61.99608" x2="46.04762" y2="2.93445" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.04188" stop-color="#077cfb"/>
|
||||
<stop offset="0.44503" stop-color="#c90f5e"/>
|
||||
<stop offset="0.95812" stop-color="#077cfb"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="17.39552" y1="63.34592" x2="33.19389" y2="7.20092" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.27749" stop-color="#c90f5e"/>
|
||||
<stop offset="0.97382" stop-color="#fcb20f"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>rider</title>
|
||||
<g>
|
||||
<polygon points="70 27.237 63.391 23.75 20.926 0 3.827 17.921 21.619 41.068 60.537 44.397 70 27.237" fill="url(#linear-gradient)"/>
|
||||
<polygon points="50.423 16.132 44.271 1.107 27.643 17.471 11.768 50.194 49.411 70 70 57.98 50.423 16.132" fill="url(#linear-gradient-2)"/>
|
||||
<polygon points="20.926 0 0 14.095 7.779 62.172 27.848 69.889 53.78 48.823 20.926 0" fill="url(#linear-gradient-3)"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="13.30219" y="13.19311" width="43.61371" height="43.61371"/>
|
||||
<g>
|
||||
<path d="M17.22741,18.86293h8.39564a7.38416,7.38416,0,0,1,5.34268,1.85358,5.86989,5.86989,0,0,1,1.52648,4.1433h0A5.74339,5.74339,0,0,1,28.567,30.5296l4.47041,6.54206H28.34891L24.42368,31.1838h-3.162v5.88785H17.22741V18.86293h0ZM25.296,27.69471c1.96262,0,3.053-1.09034,3.053-2.61682h0c0-1.74455-1.19938-2.61682-3.162-2.61682H21.15265v5.23365H25.296Z" fill="#fff"/>
|
||||
<path d="M36.09034,18.86293H43.2866c5.77882,0,9.70405,3.92523,9.70405,9.15888h0c0,5.12461-3.92523,9.15888-9.70405,9.15888H36.09034V18.86293Zm4.03427,3.59813V33.47352h3.162a5.23727,5.23727,0,0,0,5.56075-5.45171h0a5.26493,5.26493,0,0,0-5.56075-5.56075h-3.162Z" fill="#fff"/>
|
||||
</g>
|
||||
<rect x="17.22741" y="48.62925" width="16.35514" height="2.72586" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3 KiB |
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="25.0676" y1="1.4599" x2="43.1829" y2="66.675">
|
||||
<stop offset="0.2849" style="stop-color:#00CDD7"/>
|
||||
<stop offset="0.9409" style="stop-color:#2086D7"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="9.4,63.3 0,7.3 17.5,0.1 28.6,6.7 38.8,1.2 60.1,9.4 48.1,70 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="30.7199" y1="9.7343" x2="61.365" y2="54.6713">
|
||||
<stop offset="0.1398" style="stop-color:#FFF045"/>
|
||||
<stop offset="0.3656" style="stop-color:#00CDD7"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="70,23.7 61,1.4 44.6,0 19.3,24.3 26.1,55.6 38.8,64.6 70,46 62.3,31.7 "/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="61.0819" y1="15.2899" x2="65.1065" y2="29.5436">
|
||||
<stop offset="0.2849" style="stop-color:#00CDD7"/>
|
||||
<stop offset="0.9409" style="stop-color:#2086D7"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_3_);" points="56,20.4 62.3,31.7 70,23.7 64.4,9.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
<rect x="17.5" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<path style="fill:#FFFFFF;" d="M38.7,34.3l2.3-2.8c1.6,1.3,3.3,2.2,5.3,2.2c1.6,0,2.5-0.6,2.5-1.7v-0.1c0-1-0.6-1.5-3.6-2.3
|
||||
c-3.6-0.9-5.8-1.9-5.8-5.5v-0.1c0-3.3,2.6-5.4,6.2-5.4c2.6,0,4.8,0.8,6.6,2.3l-2,3c-1.6-1.1-3.1-1.8-4.6-1.8
|
||||
c-1.5,0-2.3,0.7-2.3,1.6v0.1c0,1.2,0.8,1.6,3.8,2.4c3.6,1,5.6,2.3,5.6,5.4v0.1c0,3.6-2.7,5.6-6.5,5.6
|
||||
C43.5,37.2,40.8,36.2,38.7,34.3"/>
|
||||
</g>
|
||||
<polygon style="fill:#FFFFFF;" points="35.2,19 32.5,29.4 29.5,19 26.5,19 23.4,29.4 20.7,19 16.6,19 21.7,36.9 25,36.9 28,26.5
|
||||
30.9,36.9 34.3,36.9 39.4,19 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.1 KiB |
68
README.md
68
README.md
|
@ -1,17 +1,13 @@
|
|||
# Lidarr
|
||||
|
||||
[](https://dev.azure.com/Lidarr/Lidarr/_build/latest?definitionId=1&branchName=develop)
|
||||
[](https://translate.servarr.com/engage/servarr/?utm_source=widget)
|
||||
[](https://wiki.servarr.com/lidarr/installation#docker)
|
||||
[](https://ci.appveyor.com/project/lidarr/lidarr)
|
||||
[](https://www.codacy.com/app/Lidarr/Lidarr?utm_source=github.com&utm_medium=referral&utm_content=lidarr/Lidarr&utm_campaign=Badge_Grade)
|
||||
[](https://github.com/lidarr/Lidarr/wiki/Docker)
|
||||

|
||||
[](#backers)
|
||||
[](#sponsors)
|
||||
[](#backers) [](#sponsors)
|
||||
|
||||
Lidarr is a music collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new tracks from your favorite artists and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
|
||||
|
||||
> [!WARNING]
|
||||
> NOTICE - The Lidarr Metadata Server is recovering and rebuilding the cache which is impacting adding artists, library imports, etc. Please follow [GHI 5498](https://github.com/Lidarr/Lidarr/issues/5498) or see Discord for details.
|
||||
|
||||
## Major Features Include:
|
||||
|
||||
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
||||
|
@ -26,52 +22,46 @@ Lidarr is a music collection manager for Usenet and BitTorrent users. It can mon
|
|||
* Full support for specials and multi-album releases
|
||||
* And a beautiful UI
|
||||
|
||||
## Feature Requests
|
||||
|
||||
[](http://feathub.com/lidarr/Lidarr)
|
||||
|
||||
## Support
|
||||
|
||||
Note: GitHub Issues are for Bugs and Feature Requests Only
|
||||
|
||||
[](https://lidarr.audio/discord)
|
||||
[](https://github.com/Lidarr/Lidarr/issues)
|
||||
[](https://wiki.servarr.com/lidarr)
|
||||
[](https://discord.gg/8Y7rDc9)
|
||||
[](https://www.reddit.com/r/lidarr)
|
||||
[](https://github.com/Lidarr/Lidarr/issues)
|
||||
[](https://github.com/Lidarr/Lidarr/wiki)
|
||||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
<a href="https://github.com/lidarr/Lidarr/graphs/contributors"><img src="https://opencollective.com/lidarr/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/Lidarr#backer)
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/lidarr#backer)]
|
||||
|
||||
<a href="https://opencollective.com/lidarr#backers" target="_blank"><img src="https://opencollective.com/lidarr/backers.svg?width=890"></a>
|
||||
|
||||
<img src="https://opencollective.com/Lidarr/backers.svg?width=890"></a>
|
||||
|
||||
## Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/Lidarr#sponsor)
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/lidarr#sponsor)]
|
||||
|
||||
<img src="https://opencollective.com/Lidarr/sponsors.svg?width=890"></a>
|
||||
|
||||
## Mega Sponsors
|
||||
<img src="https://opencollective.com/Lidarr/tiers/mega-sponsor.svg?width=890"></a>
|
||||
|
||||
## JetBrains
|
||||
Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
|
||||
|
||||
* [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
|
||||
* [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
||||
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||
|
||||
## DigitalOcean
|
||||
|
||||
This project is also supported by DigitalOcean
|
||||
<p>
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px">
|
||||
</a>
|
||||
</p>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/0/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/1/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/2/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/3/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/4/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/5/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/6/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/7/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/8/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/lidarr/sponsor/9/website" target="_blank"><img src="https://opencollective.com/lidarr/sponsor/9/avatar.svg"></a>
|
||||
|
||||
### License
|
||||
|
||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||
* Copyright 2010-2021
|
||||
* Copyright 2010-2019
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report (suspected) security vulnerabilities on Discord (preferred) to
|
||||
any of the Servarr Dev role holders (red names) or via email: development@servarr.com. You will receive a response from
|
||||
us within 72 hours. If the issue is confirmed, we will release a patch as soon
|
||||
as possible depending on complexity/severity.
|
43
appveyor-package.sh
Executable file
43
appveyor-package.sh
Executable file
|
@ -0,0 +1,43 @@
|
|||
#! /bin/bash
|
||||
|
||||
artifactsFolder="./_artifacts";
|
||||
artifactsFolderWindows=$artifactsFolder/windows
|
||||
artifactsFolderLinux=$artifactsFolder/linux
|
||||
artifactsFolderMacOS=$artifactsFolder/macos
|
||||
artifactsFolderMacOSApp=$artifactsFolder/macos-app
|
||||
|
||||
PublishArtifacts()
|
||||
{
|
||||
7z a $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.windows.zip $artifactsFolderWindows/*
|
||||
|
||||
7z a $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.osx-app.zip $artifactsFolderMacOSApp/*
|
||||
|
||||
7z a -ttar $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.osx.tar $artifactsFolderMacOS/*
|
||||
7z a -tgzip $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.osx.tar.gz $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.osx.tar
|
||||
rm -f $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.osx.tar
|
||||
|
||||
7z a -ttar $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.linux.tar $artifactsFolderLinux/*
|
||||
7z a -tgzip $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.linux.tar.gz $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.linux.tar
|
||||
rm -f $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.linux.tar
|
||||
|
||||
if [ "${CI_WINDOWS}" = "True" ]; then
|
||||
./setup/inno/ISCC.exe "./setup/lidarr.iss"
|
||||
cp ./setup/output/Lidarr.*windows.exe $artifactsFolder/Lidarr.${APPVEYOR_REPO_BRANCH}.${APPVEYOR_BUILD_VERSION}.windows-installer.exe
|
||||
fi
|
||||
}
|
||||
|
||||
PublishSourceMaps()
|
||||
{
|
||||
# Only create release on develop
|
||||
# Secure SENTRY_AUTH_TOKEN will only be decoded on branch builds, not PRs
|
||||
if [ "${CI_WINDOWS}" = "True" ] && [ "${APPVEYOR_REPO_BRANCH}" = "develop" ] && [ ! -z "${SENTRY_AUTH_TOKEN}" ]; then
|
||||
echo "Uploading source maps to sentry"
|
||||
yarn sentry-cli releases new --finalize -p lidarr -p lidarr-ui -p lidarr-update "${APPVEYOR_BUILD_VERSION}-debug"
|
||||
yarn sentry-cli releases -p lidarr-ui files "${APPVEYOR_BUILD_VERSION}-debug" upload-sourcemaps _output/UI/ --rewrite
|
||||
yarn sentry-cli releases set-commits --auto "${APPVEYOR_BUILD_VERSION}-debug"
|
||||
yarn sentry-cli releases deploys "${APPVEYOR_BUILD_VERSION}-debug" new -e nightly
|
||||
fi
|
||||
}
|
||||
|
||||
PublishArtifacts
|
||||
PublishSourceMaps
|
71
appveyor.yml
Normal file
71
appveyor.yml
Normal file
|
@ -0,0 +1,71 @@
|
|||
version: '0.6.1.{build}'
|
||||
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
- Ubuntu1804
|
||||
|
||||
assembly_info:
|
||||
patch: true
|
||||
file: 'src\NzbDrone.Common\Properties\SharedAssemblyInfo.cs'
|
||||
assembly_version: '{version}'
|
||||
assembly_file_version: '{version}'
|
||||
assembly_informational_version: '{version}-rc1'
|
||||
|
||||
environment:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
nodejs_version: "10"
|
||||
SENTRY_AUTH_TOKEN:
|
||||
secure: dIzaGkyqP8JefC+GyXH2RtBHCufpzegoJnxvwGenCsMZNgaVbnoNo4ZMnPY2WYpstCcdXmZb7hbPYmu4FRkKQ8xDQ34YNGlKRKnlFuOQoq8=
|
||||
SENTRY_ORG: "lidarr"
|
||||
|
||||
install:
|
||||
- git submodule update --init --recursive
|
||||
- cmd: powershell Install-Product node $env:nodejs_version
|
||||
- sh: nvm install $nodejs_version
|
||||
- sh: sudo apt update
|
||||
- sh: sudo apt install -y libchromaprint-tools
|
||||
|
||||
build_script:
|
||||
- cmd: C:\msys64\usr\bin\bash -lc "cd \"$APPVEYOR_BUILD_FOLDER\" && exec ./build.sh
|
||||
- sh: ./build.sh
|
||||
|
||||
after_build:
|
||||
- cmd: C:\msys64\usr\bin\bash -lc "cd \"$APPVEYOR_BUILD_FOLDER\" && exec ./appveyor-package.sh
|
||||
- sh: ./appveyor-package.sh
|
||||
- ps: Get-ChildItem .\_artifacts\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- ps: Get-ChildItem .\_artifacts\*.exe | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- ps: Get-ChildItem .\_artifacts\*.tar.gz | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
|
||||
test_script:
|
||||
- node --version
|
||||
- yarn --version
|
||||
- cmd: C:\msys64\usr\bin\bash -lc "cd \"$APPVEYOR_BUILD_FOLDER\" && exec ./test.sh Windows Unit
|
||||
- sh: ./test.sh Linux Unit
|
||||
- sh: find "$APPVEYOR_BUILD_FOLDER" -type f -name 'myresults.xml' -print0 | xargs -0 -I '{}' curl -F 'file=@{}' "https://ci.appveyor.com/api/testresults/nunit3/$APPVEYOR_JOB_ID"
|
||||
|
||||
cache:
|
||||
- node_modules -> package.json
|
||||
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
on_failure:
|
||||
- ps: Get-ChildItem .\_artifacts\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- ps: Get-ChildItem .\_artifacts\*.exe | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- ps: Get-ChildItem .\_artifacts\*.tar.gz | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
|
||||
only_commits:
|
||||
files:
|
||||
- src/
|
||||
- osx/
|
||||
- gulp/
|
||||
- logo/
|
||||
- setup/
|
||||
- frontend/
|
||||
- appveyor.yml
|
||||
- build.sh
|
||||
- test.sh
|
||||
- package.json
|
||||
- appveyor-package.sh
|
1269
azure-pipelines.yml
1269
azure-pipelines.yml
File diff suppressed because it is too large
Load diff
574
build.sh
574
build.sh
|
@ -1,9 +1,36 @@
|
|||
#! /usr/bin/env bash
|
||||
set -e
|
||||
#! /bin/bash
|
||||
msBuildVersion='15.0'
|
||||
outputFolder='./_output'
|
||||
outputFolderLinux='./_output_linux'
|
||||
outputFolderMacOS='./_output_macos'
|
||||
outputFolderMacOSApp='./_output_macos_app'
|
||||
testPackageFolder='./_tests/'
|
||||
testSearchPattern='*.Test/bin/x86/Release/*'
|
||||
sourceFolder='./src'
|
||||
slnFile=$sourceFolder/Lidarr.sln
|
||||
updateFolder=$outputFolder/Lidarr.Update
|
||||
updateFolderMono=$outputFolderLinux/Lidarr.Update
|
||||
|
||||
outputFolder='_output'
|
||||
testPackageFolder='_tests'
|
||||
artifactsFolder="_artifacts";
|
||||
#Artifact variables
|
||||
artifactsFolder="./_artifacts";
|
||||
artifactsFolderWindows=$artifactsFolder/windows
|
||||
artifactsFolderLinux=$artifactsFolder/linux
|
||||
artifactsFolderMacOS=$artifactsFolder/macos
|
||||
artifactsFolderMacOSApp=$artifactsFolder/macos-app
|
||||
|
||||
nuget='tools/nuget/nuget.exe';
|
||||
vswhere='tools/vswhere/vswhere.exe';
|
||||
|
||||
CheckExitCode()
|
||||
{
|
||||
"$@"
|
||||
local status=$?
|
||||
if [ $status -ne 0 ]; then
|
||||
echo "error with $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
return $status
|
||||
}
|
||||
|
||||
ProgressStart()
|
||||
{
|
||||
|
@ -15,46 +42,68 @@ ProgressEnd()
|
|||
echo "Finish '$1'"
|
||||
}
|
||||
|
||||
UpdateVersionNumber()
|
||||
CleanFolder()
|
||||
{
|
||||
if [ "$LIDARRVERSION" != "" ]; then
|
||||
echo "Updating Version Info"
|
||||
sed -i'' -e "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$LIDARRVERSION<\/AssemblyVersion>/g" src/Directory.Build.props
|
||||
sed -i'' -e "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BUILD_SOURCEBRANCHNAME}<\/AssemblyConfiguration>/g" src/Directory.Build.props
|
||||
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$LIDARRVERSION<\/string>/g" distribution/osx/Lidarr.app/Contents/Info.plist
|
||||
local path=$1
|
||||
local keepConfigFiles=$2
|
||||
|
||||
find $path -name "*.transform" -exec rm "{}" \;
|
||||
|
||||
if [ $keepConfigFiles != true ] ; then
|
||||
find $path -name "*.dll.config" -exec rm "{}" \;
|
||||
fi
|
||||
|
||||
echo "Removing FluentValidation.Resources files"
|
||||
find $path -name "FluentValidation.resources.dll" -exec rm "{}" \;
|
||||
find $path -name "App.config" -exec rm "{}" \;
|
||||
|
||||
echo "Removing vshost files"
|
||||
find $path -name "*.vshost.exe" -exec rm "{}" \;
|
||||
|
||||
echo "Removing dylib files"
|
||||
find $path -name "*.dylib" -exec rm "{}" \;
|
||||
|
||||
echo "Removing Empty folders"
|
||||
find $path -depth -empty -type d -exec rm -r "{}" \;
|
||||
}
|
||||
|
||||
EnableExtraPlatformsInSDK()
|
||||
BuildWithMSBuild()
|
||||
{
|
||||
SDK_PATH=$(dotnet --list-sdks | grep -P '6\.\d\.\d+' | head -1 | sed 's/\(6\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g')
|
||||
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
|
||||
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
|
||||
echo "Extra platforms already enabled"
|
||||
else
|
||||
echo "Enabling extra platform support"
|
||||
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS
|
||||
fi
|
||||
installationPath=`$vswhere -latest -products \* -requires Microsoft.Component.MSBuild -property installationPath`
|
||||
installationPath=${installationPath/C:\\/\/c\/}
|
||||
installationPath=${installationPath//\\/\/}
|
||||
msBuild="$installationPath/MSBuild/$msBuildVersion/Bin"
|
||||
echo $msBuild
|
||||
|
||||
export PATH=$msBuild:$PATH
|
||||
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Debug //p:Platform=x86 //t:Clean //m
|
||||
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Clean //m
|
||||
$nuget locals all -clear
|
||||
$nuget restore $slnFile
|
||||
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Build //m //p:AllowedReferenceRelatedFileExtensions=.pdb
|
||||
}
|
||||
|
||||
EnableExtraPlatforms()
|
||||
BuildWithXbuild()
|
||||
{
|
||||
if grep -qv freebsd-x64 src/Directory.Build.props; then
|
||||
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64;linux-x86</RuntimeIdentifiers>^g" src/Directory.Build.props
|
||||
fi
|
||||
export MONO_IOMAP=case
|
||||
CheckExitCode msbuild /p:Configuration=Debug /t:Clean $slnFile
|
||||
CheckExitCode msbuild /p:Configuration=Release /t:Clean $slnFile
|
||||
mono $nuget locals all -clear
|
||||
mono $nuget restore $slnFile
|
||||
CheckExitCode msbuild /p:Configuration=Release /p:Platform=x86 /t:Build /p:AllowedReferenceRelatedFileExtensions=.pdb $slnFile
|
||||
}
|
||||
|
||||
LintUI()
|
||||
{
|
||||
ProgressStart 'ESLint'
|
||||
yarn lint
|
||||
CheckExitCode yarn eslint
|
||||
ProgressEnd 'ESLint'
|
||||
|
||||
ProgressStart 'Stylelint'
|
||||
if [ "$os" = "windows" ]; then
|
||||
yarn stylelint-windows
|
||||
if [ $runtime = "dotnet" ] ; then
|
||||
CheckExitCode yarn stylelint-windows
|
||||
else
|
||||
yarn stylelint-linux
|
||||
CheckExitCode yarn stylelint-linux
|
||||
fi
|
||||
ProgressEnd 'Stylelint'
|
||||
}
|
||||
|
@ -64,379 +113,236 @@ Build()
|
|||
ProgressStart 'Build'
|
||||
|
||||
rm -rf $outputFolder
|
||||
rm -rf $testPackageFolder
|
||||
|
||||
slnFile=src/Lidarr.sln
|
||||
|
||||
if [ $os = "windows" ]; then
|
||||
platform=Windows
|
||||
if [ $runtime = "dotnet" ] ; then
|
||||
BuildWithMSBuild
|
||||
else
|
||||
platform=Posix
|
||||
BuildWithXbuild
|
||||
fi
|
||||
|
||||
dotnet clean $slnFile -c Debug
|
||||
dotnet clean $slnFile -c Release
|
||||
CleanFolder $outputFolder false
|
||||
|
||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||
then
|
||||
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -t:PublishAllRids
|
||||
else
|
||||
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -p:RuntimeIdentifiers=$RID -t:PublishAllRids
|
||||
fi
|
||||
echo "Removing Mono.Posix.dll"
|
||||
rm $outputFolder/Mono.Posix.dll
|
||||
|
||||
echo "Adding LICENSE.md"
|
||||
cp LICENSE.md $outputFolder
|
||||
|
||||
ProgressEnd 'Build'
|
||||
}
|
||||
|
||||
YarnInstall()
|
||||
RunGulp()
|
||||
{
|
||||
ProgressStart 'yarn install'
|
||||
yarn install --frozen-lockfile --network-timeout 120000
|
||||
yarn install
|
||||
#npm-cache install npm || CheckExitCode npm install --no-optional --no-bin-links
|
||||
ProgressEnd 'yarn install'
|
||||
|
||||
LintUI
|
||||
|
||||
ProgressStart 'Running gulp'
|
||||
CheckExitCode yarn run build --production
|
||||
ProgressEnd 'Running gulp'
|
||||
}
|
||||
|
||||
RunWebpack()
|
||||
CreateMdbs()
|
||||
{
|
||||
ProgressStart 'Running webpack'
|
||||
yarn run build --env production
|
||||
ProgressEnd 'Running webpack'
|
||||
local path=$1
|
||||
if [ $runtime = "dotnet" ] ; then
|
||||
local pdbFiles=( $(find $path -name "*.pdb") )
|
||||
for filename in "${pdbFiles[@]}"
|
||||
do
|
||||
if [ -e ${filename%.pdb}.dll ] ; then
|
||||
tools/pdb2mdb/pdb2mdb.exe ${filename%.pdb}.dll
|
||||
fi
|
||||
if [ -e ${filename%.pdb}.exe ] ; then
|
||||
tools/pdb2mdb/pdb2mdb.exe ${filename%.pdb}.exe
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Removing PDBs"
|
||||
find $path -name "*.pdb" -exec rm "{}" \;
|
||||
fi
|
||||
}
|
||||
|
||||
PackageFiles()
|
||||
PackageMono()
|
||||
{
|
||||
local folder="$1"
|
||||
local framework="$2"
|
||||
local runtime="$3"
|
||||
ProgressStart 'Creating Mono Package'
|
||||
|
||||
rm -rf $folder
|
||||
mkdir -p $folder
|
||||
cp -r $outputFolder/$framework/$runtime/publish/* $folder
|
||||
cp -r $outputFolder/Lidarr.Update/$framework/$runtime/publish $folder/Lidarr.Update
|
||||
cp -r $outputFolder/UI $folder
|
||||
rm -rf $outputFolderLinux
|
||||
|
||||
echo "Adding LICENSE"
|
||||
cp LICENSE.md $folder
|
||||
}
|
||||
echo "Copying Binaries"
|
||||
cp -r $outputFolder $outputFolderLinux
|
||||
|
||||
PackageLinux()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
|
||||
ProgressStart "Creating $runtime Package for $framework"
|
||||
|
||||
local folder=$artifactsFolder/$runtime/$framework/Lidarr
|
||||
|
||||
PackageFiles "$folder" "$framework" "$runtime"
|
||||
echo "Creating MDBs"
|
||||
CreateMdbs $outputFolderLinux
|
||||
|
||||
echo "Removing Service helpers"
|
||||
rm -f $folder/ServiceUninstall.*
|
||||
rm -f $folder/ServiceInstall.*
|
||||
rm -f $outputFolderLinux/ServiceUninstall.*
|
||||
rm -f $outputFolderLinux/ServiceInstall.*
|
||||
|
||||
echo "Removing native windows binaries Sqlite, fpcalc"
|
||||
rm -f $outputFolderLinux/sqlite3.*
|
||||
rm -f $outputFolderLinux/fpcalc*
|
||||
|
||||
echo "Adding CurlSharp.dll.config (for dllmap)"
|
||||
cp $sourceFolder/NzbDrone.Common/CurlSharp.dll.config $outputFolderLinux
|
||||
|
||||
echo "Renaming Lidarr.Console.exe to Lidarr.exe"
|
||||
rm $outputFolderLinux/Lidarr.exe*
|
||||
for file in $outputFolderLinux/Lidarr.Console.exe*; do
|
||||
mv "$file" "${file//.Console/}"
|
||||
done
|
||||
|
||||
echo "Removing Lidarr.Windows"
|
||||
rm $folder/Lidarr.Windows.*
|
||||
rm $outputFolderLinux/Lidarr.Windows.*
|
||||
|
||||
echo "Adding Lidarr.Mono to UpdatePackage"
|
||||
cp $folder/Lidarr.Mono.* $folder/Lidarr.Update
|
||||
if [ "$framework" = "net6.0" ]; then
|
||||
cp $folder/Mono.Posix.NETStandard.* $folder/Lidarr.Update
|
||||
cp $folder/libMonoPosixHelper.* $folder/Lidarr.Update
|
||||
fi
|
||||
cp $outputFolderLinux/Lidarr.Mono.* $updateFolderMono
|
||||
|
||||
ProgressEnd "Creating $runtime Package for $framework"
|
||||
ProgressEnd 'Creating Mono Package'
|
||||
}
|
||||
|
||||
PackageMacOS()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
ProgressStart 'Creating MacOS Package'
|
||||
|
||||
ProgressStart "Creating $runtime Package for $framework"
|
||||
rm -rf $outputFolderMacOS
|
||||
mkdir $outputFolderMacOS
|
||||
|
||||
local folder=$artifactsFolder/$runtime/$framework/Lidarr
|
||||
echo "Adding Startup script"
|
||||
cp ./macOS/Lidarr $outputFolderMacOS
|
||||
dos2unix $outputFolderMacOS/Lidarr
|
||||
|
||||
PackageFiles "$folder" "$framework" "$runtime"
|
||||
echo "Copying Binaries"
|
||||
cp -r $outputFolderLinux/* $outputFolderMacOS
|
||||
cp $outputFolder/fpcalc $outputFolderMacOS
|
||||
|
||||
echo "Removing Service helpers"
|
||||
rm -f $folder/ServiceUninstall.*
|
||||
rm -f $folder/ServiceInstall.*
|
||||
|
||||
echo "Removing Lidarr.Windows"
|
||||
rm $folder/Lidarr.Windows.*
|
||||
|
||||
echo "Adding Lidarr.Mono to UpdatePackage"
|
||||
cp $folder/Lidarr.Mono.* $folder/Lidarr.Update
|
||||
if [ "$framework" = "net6.0" ]; then
|
||||
cp $folder/Mono.Posix.NETStandard.* $folder/Lidarr.Update
|
||||
cp $folder/libMonoPosixHelper.* $folder/Lidarr.Update
|
||||
fi
|
||||
echo "Adding sqlite dylibs"
|
||||
cp $sourceFolder/Libraries/Sqlite/*.dylib $outputFolderMacOS
|
||||
|
||||
ProgressEnd 'Creating MacOS Package'
|
||||
}
|
||||
|
||||
PackageMacOSApp()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
ProgressStart 'Creating macOS App Package'
|
||||
|
||||
ProgressStart "Creating $runtime App Package for $framework"
|
||||
rm -rf $outputFolderMacOSApp
|
||||
mkdir $outputFolderMacOSApp
|
||||
cp -r ./macOS/Lidarr.app $outputFolderMacOSApp
|
||||
mkdir -p $outputFolderMacOSApp/Lidarr.app/Contents/MacOS
|
||||
|
||||
local folder=$artifactsFolder/$runtime-app/$framework
|
||||
|
||||
rm -rf $folder
|
||||
mkdir -p $folder
|
||||
cp -r distribution/osx/Lidarr.app $folder
|
||||
mkdir -p $folder/Lidarr.app/Contents/MacOS
|
||||
echo "Adding Startup script"
|
||||
cp ./macOS/Lidarr $outputFolderMacOSApp/Lidarr.app/Contents/MacOS
|
||||
dos2unix $outputFolderMacOSApp/Lidarr.app/Contents/MacOS/Lidarr
|
||||
|
||||
echo "Copying Binaries"
|
||||
cp -r $artifactsFolder/$runtime/$framework/Lidarr/* $folder/Lidarr.app/Contents/MacOS
|
||||
cp -r $outputFolderLinux/* $outputFolderMacOSApp/Lidarr.app/Contents/MacOS
|
||||
cp $outputFolder/fpcalc $outputFolderMacOSApp/Lidarr.app/Contents/MacOS
|
||||
|
||||
echo "Adding sqlite dylibs"
|
||||
cp $sourceFolder/Libraries/Sqlite/*.dylib $outputFolderMacOSApp/Lidarr.app/Contents/MacOS
|
||||
|
||||
echo "Removing Update Folder"
|
||||
rm -r $folder/Lidarr.app/Contents/MacOS/Lidarr.Update
|
||||
rm -r $outputFolderMacOSApp/Lidarr.app/Contents/MacOS/Lidarr.Update
|
||||
|
||||
ProgressEnd 'Creating macOS App Package'
|
||||
}
|
||||
|
||||
PackageWindows()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
|
||||
ProgressStart "Creating Windows Package for $framework"
|
||||
|
||||
local folder=$artifactsFolder/$runtime/$framework/Lidarr
|
||||
|
||||
PackageFiles "$folder" "$framework" "$runtime"
|
||||
cp -r $outputFolder/$framework-windows/$runtime/publish/* $folder
|
||||
|
||||
echo "Removing Lidarr.Mono"
|
||||
rm -f $folder/Lidarr.Mono.*
|
||||
rm -f $folder/Mono.Posix.NETStandard.*
|
||||
rm -f $folder/libMonoPosixHelper.*
|
||||
|
||||
echo "Adding Lidarr.Windows to UpdatePackage"
|
||||
cp $folder/Lidarr.Windows.* $folder/Lidarr.Update
|
||||
|
||||
ProgressEnd "Creating $runtime Package for $framework"
|
||||
}
|
||||
|
||||
Package()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
local SPLIT
|
||||
|
||||
IFS='-' read -ra SPLIT <<< "$runtime"
|
||||
|
||||
case "${SPLIT[0]}" in
|
||||
linux|freebsd*)
|
||||
PackageLinux "$framework" "$runtime"
|
||||
;;
|
||||
win)
|
||||
PackageWindows "$framework" "$runtime"
|
||||
;;
|
||||
osx)
|
||||
PackageMacOS "$framework" "$runtime"
|
||||
PackageMacOSApp "$framework" "$runtime"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
BuildInstaller()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
|
||||
./_inno/ISCC.exe distribution/windows/setup/lidarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
|
||||
}
|
||||
|
||||
InstallInno()
|
||||
{
|
||||
ProgressStart "Installing portable Inno Setup"
|
||||
|
||||
rm -rf _inno
|
||||
curl -s --output innosetup.exe "https://files.jrsoftware.org/is/6/innosetup-${INNOVERSION:-6.2.0}.exe"
|
||||
mkdir _inno
|
||||
./innosetup.exe //portable=1 //silent //currentuser //dir=.\\_inno
|
||||
rm innosetup.exe
|
||||
|
||||
ProgressEnd "Installed portable Inno Setup"
|
||||
}
|
||||
|
||||
RemoveInno()
|
||||
{
|
||||
rm -rf _inno
|
||||
}
|
||||
|
||||
PackageTests()
|
||||
{
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
ProgressStart 'Creating Test Package'
|
||||
|
||||
cp test.sh "$testPackageFolder/$framework/$runtime/publish"
|
||||
rm -rf $testPackageFolder
|
||||
mkdir $testPackageFolder
|
||||
|
||||
rm -f $testPackageFolder/$framework/$runtime/*.log.config
|
||||
find . -maxdepth 6 -path $testSearchPattern -exec cp -r "{}" $testPackageFolder \;
|
||||
|
||||
if [ $runtime = "dotnet" ] ; then
|
||||
$nuget install NUnit.ConsoleRunner -Version 3.7.0 -Output $testPackageFolder
|
||||
else
|
||||
mono $nuget install NUnit.ConsoleRunner -Version 3.7.0 -Output $testPackageFolder
|
||||
fi
|
||||
|
||||
cp $outputFolder/*.dll $testPackageFolder
|
||||
cp $outputFolder/*.exe $testPackageFolder
|
||||
cp $outputFolder/fpcalc $testPackageFolder
|
||||
cp ./*.sh $testPackageFolder
|
||||
|
||||
echo "Creating MDBs for tests"
|
||||
CreateMdbs $testPackageFolder
|
||||
|
||||
rm -f $testPackageFolder/*.log.config
|
||||
|
||||
CleanFolder $testPackageFolder true
|
||||
|
||||
echo "Adding CurlSharp.dll.config (for dllmap)"
|
||||
cp $sourceFolder/NzbDrone.Common/CurlSharp.dll.config $testPackageFolder
|
||||
|
||||
echo "Copying CurlSharp libraries"
|
||||
cp $sourceFolder/ExternalModules/CurlSharp/libs/i386/* $testPackageFolder
|
||||
|
||||
echo "Copying dylibs"
|
||||
cp -r $outputFolderMacOS/*.dylib $testPackageFolder
|
||||
|
||||
ProgressEnd 'Creating Test Package'
|
||||
}
|
||||
|
||||
CleanupWindowsPackage()
|
||||
{
|
||||
ProgressStart 'Cleaning Windows Package'
|
||||
|
||||
echo "Removing Lidarr.Mono"
|
||||
rm -f $outputFolder/Lidarr.Mono.*
|
||||
|
||||
echo "Adding Lidarr.Windows to UpdatePackage"
|
||||
cp $outputFolder/Lidarr.Windows.* $updateFolder
|
||||
|
||||
echo "Removing MacOS fpcalc"
|
||||
rm $outputFolder/fpcalc
|
||||
|
||||
ProgressEnd 'Cleaning Windows Package'
|
||||
}
|
||||
|
||||
PackageArtifacts()
|
||||
{
|
||||
echo "Creating Artifact Directories"
|
||||
|
||||
rm -rf $artifactsFolder
|
||||
mkdir $artifactsFolder
|
||||
|
||||
mkdir $artifactsFolderWindows
|
||||
mkdir $artifactsFolderMacOS
|
||||
mkdir $artifactsFolderLinux
|
||||
mkdir $artifactsFolderWindows/Lidarr
|
||||
mkdir $artifactsFolderMacOS/Lidarr
|
||||
mkdir $artifactsFolderLinux/Lidarr
|
||||
mkdir $artifactsFolderMacOSApp
|
||||
|
||||
cp -r $outputFolder/* $artifactsFolderWindows/Lidarr
|
||||
cp -r $outputFolderMacOSApp/* $artifactsFolderMacOSApp
|
||||
cp -r $outputFolderMacOS/* $artifactsFolderMacOS/Lidarr
|
||||
cp -r $outputFolderLinux/* $artifactsFolderLinux/Lidarr
|
||||
}
|
||||
|
||||
# Use mono or .net depending on OS
|
||||
case "$(uname -s)" in
|
||||
CYGWIN*|MINGW32*|MINGW64*|MSYS*)
|
||||
# on windows, use dotnet
|
||||
os="windows"
|
||||
runtime="dotnet"
|
||||
;;
|
||||
*)
|
||||
# otherwise use mono
|
||||
os="posix"
|
||||
runtime="mono"
|
||||
;;
|
||||
esac
|
||||
|
||||
POSITIONAL=()
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "No arguments provided, building everything"
|
||||
BACKEND=YES
|
||||
FRONTEND=YES
|
||||
PACKAGES=YES
|
||||
INSTALLER=NO
|
||||
LINT=YES
|
||||
ENABLE_EXTRA_PLATFORMS=NO
|
||||
ENABLE_EXTRA_PLATFORMS_IN_SDK=NO
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
|
||||
case $key in
|
||||
--backend)
|
||||
BACKEND=YES
|
||||
shift # past argument
|
||||
;;
|
||||
--enable-bsd|--enable-extra-platforms)
|
||||
ENABLE_EXTRA_PLATFORMS=YES
|
||||
shift # past argument
|
||||
;;
|
||||
--enable-extra-platforms-in-sdk)
|
||||
ENABLE_EXTRA_PLATFORMS_IN_SDK=YES
|
||||
shift # past argument
|
||||
;;
|
||||
-r|--runtime)
|
||||
RID="$2"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
-f|--framework)
|
||||
FRAMEWORK="$2"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
--frontend)
|
||||
FRONTEND=YES
|
||||
shift # past argument
|
||||
;;
|
||||
--packages)
|
||||
PACKAGES=YES
|
||||
shift # past argument
|
||||
;;
|
||||
--installer)
|
||||
INSTALLER=YES
|
||||
shift # past argument
|
||||
;;
|
||||
--lint)
|
||||
LINT=YES
|
||||
shift # past argument
|
||||
;;
|
||||
--all)
|
||||
BACKEND=YES
|
||||
FRONTEND=YES
|
||||
PACKAGES=YES
|
||||
LINT=YES
|
||||
shift # past argument
|
||||
;;
|
||||
*) # unknown option
|
||||
POSITIONAL+=("$1") # save it in an array for later
|
||||
shift # past argument
|
||||
;;
|
||||
esac
|
||||
done
|
||||
set -- "${POSITIONAL[@]}" # restore positional parameters
|
||||
|
||||
if [ "$ENABLE_EXTRA_PLATFORMS_IN_SDK" = "YES" ];
|
||||
then
|
||||
EnableExtraPlatformsInSDK
|
||||
fi
|
||||
|
||||
if [ "$BACKEND" = "YES" ];
|
||||
then
|
||||
UpdateVersionNumber
|
||||
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
|
||||
then
|
||||
EnableExtraPlatforms
|
||||
fi
|
||||
Build
|
||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||
then
|
||||
PackageTests "net6.0" "win-x64"
|
||||
PackageTests "net6.0" "win-x86"
|
||||
PackageTests "net6.0" "linux-x64"
|
||||
PackageTests "net6.0" "linux-musl-x64"
|
||||
PackageTests "net6.0" "osx-x64"
|
||||
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
|
||||
then
|
||||
PackageTests "net6.0" "freebsd-x64"
|
||||
PackageTests "net6.0" "linux-x86"
|
||||
fi
|
||||
else
|
||||
PackageTests "$FRAMEWORK" "$RID"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$LINT" = "YES" || "$FRONTEND" = "YES" ]];
|
||||
then
|
||||
YarnInstall
|
||||
fi
|
||||
|
||||
if [ "$LINT" = "YES" ];
|
||||
then
|
||||
LintUI
|
||||
fi
|
||||
|
||||
if [ "$FRONTEND" = "YES" ];
|
||||
then
|
||||
RunWebpack
|
||||
fi
|
||||
|
||||
if [ "$PACKAGES" = "YES" ];
|
||||
then
|
||||
UpdateVersionNumber
|
||||
|
||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||
then
|
||||
Package "net6.0" "win-x64"
|
||||
Package "net6.0" "win-x86"
|
||||
Package "net6.0" "linux-x64"
|
||||
Package "net6.0" "linux-musl-x64"
|
||||
Package "net6.0" "linux-arm64"
|
||||
Package "net6.0" "linux-musl-arm64"
|
||||
Package "net6.0" "linux-arm"
|
||||
Package "net6.0" "linux-musl-arm"
|
||||
Package "net6.0" "osx-x64"
|
||||
Package "net6.0" "osx-arm64"
|
||||
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
|
||||
then
|
||||
Package "net6.0" "freebsd-x64"
|
||||
Package "net6.0" "linux-x86"
|
||||
fi
|
||||
else
|
||||
Package "$FRAMEWORK" "$RID"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$INSTALLER" = "YES" ];
|
||||
then
|
||||
InstallInno
|
||||
BuildInstaller "net6.0" "win-x64"
|
||||
BuildInstaller "net6.0" "win-x86"
|
||||
RemoveInno
|
||||
fi
|
||||
Build
|
||||
RunGulp
|
||||
PackageMono
|
||||
PackageMacOS
|
||||
PackageMacOSApp
|
||||
PackageTests
|
||||
CleanupWindowsPackage
|
||||
PackageArtifacts
|
||||
|
|
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
nzbdrone {version} {branch}; urgency=low
|
||||
|
||||
* Automatic Release.
|
||||
|
||||
-- NzbDrone <contact@nzbdrone.com> Mon, 26 Aug 2013 00:00:00 -0700
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
8
|
12
debian/control
vendored
Normal file
12
debian/control
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
Section: web
|
||||
Priority: optional
|
||||
Maintainer: Sonarr <contact@nzbdrone.com>
|
||||
Source: nzbdrone
|
||||
Homepage: https://lidarr.audio
|
||||
Vcs-Git: git@github.com:lidarr/Lidarr.git
|
||||
Vcs-Browser: https://github.com/lidarr/Lidarr
|
||||
|
||||
Package: nzbdrone
|
||||
Architecture: all
|
||||
Depends: libmono-cil-dev (>= 3.2), sqlite3 (>= 3.7), mediainfo (>= 0.7.52)
|
||||
Description: Lidarr is a music collection manager
|
24
debian/copyright
vendored
Executable file
24
debian/copyright
vendored
Executable file
|
@ -0,0 +1,24 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: nzbdrone
|
||||
Source: https://github.com/lidarr/Lidarr
|
||||
|
||||
Files: *
|
||||
Copyright: 2010-2016 Lidarr <hello@lidarr.audio>
|
||||
|
||||
License: GPL-3.0+
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
1
debian/install
vendored
Executable file
1
debian/install
vendored
Executable file
|
@ -0,0 +1 @@
|
|||
nzbdrone_bin/* opt/NzbDrone
|
13
debian/rules
vendored
Executable file
13
debian/rules
vendored
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
%:
|
||||
dh $@
|
|
@ -1,182 +0,0 @@
|
|||
#!/bin/bash
|
||||
### Description: Lidarr .NET Debian install
|
||||
### Originally written for Radarr by: DoctorArr - doctorarr@the-rowlands.co.uk on 2021-10-01 v1.0
|
||||
### Updates for servarr suite made by Bakerboy448, DoctorArr, brightghost, aeramor and VP-EN
|
||||
### Version v1.0.0 2023-12-29 - StevieTV - adapted from servarr script for Lidarr installs
|
||||
### Version V1.0.1 2024-01-02 - StevieTV - remove UTF8-BOM
|
||||
### Version V1.0.2 2024-01-03 - markus101 - Get user input from /dev/tty
|
||||
### Version V1.0.3 2024-01-06 - StevieTV - exit script when it is ran from install directory
|
||||
|
||||
### Boilerplate Warning
|
||||
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
#LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
#OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
scriptversion="1.0.3"
|
||||
scriptdate="2024-01-06"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "Running Lidarr Install Script - Version [$scriptversion] as of [$scriptdate]"
|
||||
|
||||
# Am I root?, need root!
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root."
|
||||
exit
|
||||
fi
|
||||
|
||||
app="lidarr"
|
||||
app_port="8686"
|
||||
app_prereq="curl sqlite3 wget"
|
||||
app_umask="0002"
|
||||
branch="main"
|
||||
|
||||
# Constants
|
||||
### Update these variables as required for your specific instance
|
||||
installdir="/opt" # {Update me if needed} Install Location
|
||||
bindir="${installdir}/${app^}" # Full Path to Install Location
|
||||
datadir="/var/lib/$app/" # {Update me if needed} AppData directory to use
|
||||
app_bin=${app^} # Binary Name of the app
|
||||
|
||||
# This script should not be ran from installdir, otherwise later in the script the extracted files will be removed before they can be moved to installdir.
|
||||
if [ "$installdir" == "$(dirname -- "$( readlink -f -- "$0"; )")" ] || [ "$bindir" == "$(dirname -- "$( readlink -f -- "$0"; )")" ]; then
|
||||
echo "You should not run this script from the intended install directory. The script will exit. Please re-run it from another directory"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Prompt User
|
||||
read -r -p "What user should ${app^} run as? (Default: $app): " app_uid < /dev/tty
|
||||
app_uid=$(echo "$app_uid" | tr -d ' ')
|
||||
app_uid=${app_uid:-$app}
|
||||
# Prompt Group
|
||||
read -r -p "What group should ${app^} run as? (Default: media): " app_guid < /dev/tty
|
||||
app_guid=$(echo "$app_guid" | tr -d ' ')
|
||||
app_guid=${app_guid:-media}
|
||||
|
||||
echo "This will install [${app^}] to [$bindir] and use [$datadir] for the AppData Directory"
|
||||
echo "${app^} will run as the user [$app_uid] and group [$app_guid]. By continuing, you've confirmed that the selected user and group will have READ and WRITE access to your Media Library and Download Client Completed Download directories"
|
||||
read -n 1 -r -s -p $'Press enter to continue or ctrl+c to exit...\n' < /dev/tty
|
||||
|
||||
# Create User / Group as needed
|
||||
if [ "$app_guid" != "$app_uid" ]; then
|
||||
if ! getent group "$app_guid" >/dev/null; then
|
||||
groupadd "$app_guid"
|
||||
fi
|
||||
fi
|
||||
if ! getent passwd "$app_uid" >/dev/null; then
|
||||
adduser --system --no-create-home --ingroup "$app_guid" "$app_uid"
|
||||
echo "Created and added User [$app_uid] to Group [$app_guid]"
|
||||
fi
|
||||
if ! getent group "$app_guid" | grep -qw "$app_uid"; then
|
||||
echo "User [$app_uid] did not exist in Group [$app_guid]"
|
||||
usermod -a -G "$app_guid" "$app_uid"
|
||||
echo "Added User [$app_uid] to Group [$app_guid]"
|
||||
fi
|
||||
|
||||
# Stop the App if running
|
||||
if service --status-all | grep -Fq "$app"; then
|
||||
systemctl stop "$app"
|
||||
systemctl disable "$app".service
|
||||
echo "Stopped existing $app"
|
||||
fi
|
||||
|
||||
# Create Appdata Directory
|
||||
|
||||
# AppData
|
||||
mkdir -p "$datadir"
|
||||
chown -R "$app_uid":"$app_guid" "$datadir"
|
||||
chmod 775 "$datadir"
|
||||
echo "Directories created"
|
||||
# Download and install the App
|
||||
|
||||
# prerequisite packages
|
||||
echo ""
|
||||
echo "Installing pre-requisite Packages"
|
||||
# shellcheck disable=SC2086
|
||||
apt update && apt install -y $app_prereq
|
||||
echo ""
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
# get arch
|
||||
dlbase="https://lidarr.servarr.com/v1/update/$branch/updatefile?os=linux&runtime=netcore"
|
||||
case "$ARCH" in
|
||||
"amd64") DLURL="${dlbase}&arch=x64" ;;
|
||||
"armhf") DLURL="${dlbase}&arch=arm" ;;
|
||||
"arm64") DLURL="${dlbase}&arch=arm64" ;;
|
||||
*)
|
||||
echo "Arch not supported"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
echo ""
|
||||
echo "Removing previous tarballs"
|
||||
# -f to Force so we fail if it doesn't exist
|
||||
rm -f "${app^}".*.tar.gz
|
||||
echo ""
|
||||
echo "Downloading..."
|
||||
wget --content-disposition "$DLURL"
|
||||
tar -xvzf "${app^}".*.tar.gz
|
||||
echo ""
|
||||
echo "Installation files downloaded and extracted"
|
||||
|
||||
# remove existing installs
|
||||
echo "Removing existing installation"
|
||||
rm -rf "$bindir"
|
||||
echo "Installing..."
|
||||
mv "${app^}" $installdir
|
||||
chown "$app_uid":"$app_guid" -R "$bindir"
|
||||
chmod 775 "$bindir"
|
||||
rm -rf "${app^}.*.tar.gz"
|
||||
# Ensure we check for an update in case user installs older version or different branch
|
||||
touch "$datadir"/update_required
|
||||
chown "$app_uid":"$app_guid" "$datadir"/update_required
|
||||
echo "App Installed"
|
||||
# Configure Autostart
|
||||
|
||||
# Remove any previous app .service
|
||||
echo "Removing old service file"
|
||||
rm -rf /etc/systemd/system/"$app".service
|
||||
|
||||
# Create app .service with correct user startup
|
||||
echo "Creating service file"
|
||||
cat <<EOF | tee /etc/systemd/system/"$app".service >/dev/null
|
||||
[Unit]
|
||||
Description=${app^} Daemon
|
||||
After=syslog.target network.target
|
||||
[Service]
|
||||
User=$app_uid
|
||||
Group=$app_guid
|
||||
UMask=$app_umask
|
||||
Type=simple
|
||||
ExecStart=$bindir/$app_bin -nobrowser -data=$datadir
|
||||
TimeoutStopSec=20
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Start the App
|
||||
echo "Service file created. Attempting to start the app"
|
||||
systemctl -q daemon-reload
|
||||
systemctl enable --now -q "$app"
|
||||
|
||||
# Finish Update/Installation
|
||||
host=$(hostname -I)
|
||||
ip_local=$(grep -oP '^\S*' <<<"$host")
|
||||
echo ""
|
||||
echo "Install complete"
|
||||
sleep 10
|
||||
STATUS="$(systemctl is-active "$app")"
|
||||
if [ "${STATUS}" = "active" ]; then
|
||||
echo "Browse to http://$ip_local:$app_port for the ${app^} GUI"
|
||||
else
|
||||
echo "${app^} failed to start"
|
||||
fi
|
||||
|
||||
# Exit
|
||||
exit 0
|
|
@ -1,20 +0,0 @@
|
|||
# This file is owned by the lidarr package, DO NOT MODIFY MANUALLY
|
||||
# Instead use 'dpkg-reconfigure -plow lidarr' to modify User/Group/UMask/-data
|
||||
# Or use systemd built-in override functionality using 'systemctl edit lidarr'
|
||||
[Unit]
|
||||
Description=Lidarr Daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=lidarr
|
||||
Group=lidarr
|
||||
UMask=002
|
||||
|
||||
Type=simple
|
||||
ExecStart=/opt/Lidarr/Lidarr -nobrowser -data=/var/lib/lidarr
|
||||
TimeoutStopSec=20
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,84 +0,0 @@
|
|||
; Script generated by the Inno Setup Script Wizard.
|
||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
#define AppName "Lidarr"
|
||||
#define AppPublisher "Team Lidarr"
|
||||
#define AppURL "https://lidarr.audio/"
|
||||
#define ForumsURL "https://lidarr.audio/discord"
|
||||
#define AppExeName "Lidarr.exe"
|
||||
#define BaseVersion GetEnv('MAJORVERSION')
|
||||
#define BuildNumber GetEnv('MINORVERSION')
|
||||
#define BuildVersion GetEnv('LIDARRVERSION')
|
||||
|
||||
[Setup]
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
; Do not use the same AppId value in installers for other applications.
|
||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||
AppId={{56C1065D-3523-4025-B76D-6F73F67F7F93}
|
||||
AppName={#AppName}
|
||||
AppVersion={#BaseVersion}
|
||||
AppPublisher={#AppPublisher}
|
||||
AppPublisherURL={#AppURL}
|
||||
AppSupportURL={#ForumsURL}
|
||||
AppUpdatesURL={#AppURL}
|
||||
DefaultDirName={commonappdata}\Lidarr
|
||||
DisableDirPage=yes
|
||||
DefaultGroupName={#AppName}
|
||||
DisableProgramGroupPage=yes
|
||||
OutputBaseFilename=Lidarr.{#BuildVersion}.{#Runtime}
|
||||
SolidCompression=yes
|
||||
AppCopyright=Creative Commons 3.0 License
|
||||
AllowUNCPath=False
|
||||
UninstallDisplayIcon={app}\bin\Lidarr.exe
|
||||
DisableReadyPage=True
|
||||
CompressionThreads=2
|
||||
Compression=lzma2/normal
|
||||
AppContact={#ForumsURL}
|
||||
VersionInfoVersion={#BaseVersion}.{#BuildNumber}
|
||||
SetupLogging=yes
|
||||
OutputDir=output
|
||||
WizardStyle=modern
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopIcon"; Description: "{cm:CreateDesktopIcon}"
|
||||
Name: "windowsService"; Description: "Install Windows Service (Starts when the computer starts as the LocalService user, you will need to change the user to access network shares)"; GroupDescription: "Start automatically"; Flags: exclusive
|
||||
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
|
||||
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
|
||||
|
||||
[Dirs]
|
||||
Name: "{app}"; Permissions: users-modify
|
||||
|
||||
[Files]
|
||||
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Lidarr\Lidarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
|
||||
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Lidarr\*"; Excludes: "Lidarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{#AppName}"; Filename: "{app}\bin\{#AppExeName}"; Parameters: "/icon"
|
||||
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\bin\{#AppExeName}"; Parameters: "/icon"; Tasks: desktopIcon
|
||||
Name: "{userstartup}\{#AppName}"; Filename: "{app}\bin\Lidarr.exe"; WorkingDir: "{app}\bin"; Tasks: startupShortcut
|
||||
|
||||
[InstallDelete]
|
||||
Name: "{app}\bin"; Type: filesandordirs
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\bin\Lidarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u /exitimmediately"; Flags: runhidden waituntilterminated;
|
||||
Filename: "{app}\bin\Lidarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl /exitimmediately"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none;
|
||||
Filename: "{app}\bin\Lidarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i /exitimmediately"; Flags: runhidden waituntilterminated; Tasks: windowsService
|
||||
Filename: "{app}\bin\Lidarr.exe"; Description: "Open Lidarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService;
|
||||
Filename: "{app}\bin\Lidarr.exe"; Description: "Start Lidarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none;
|
||||
|
||||
[UninstallRun]
|
||||
Filename: "{app}\bin\lidarr.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
|
||||
|
||||
[Code]
|
||||
function PrepareToInstall(var NeedsRestart: Boolean): String;
|
||||
var
|
||||
ResultCode: Integer;
|
||||
begin
|
||||
Exec('net', 'stop lidarr', '', 0, ewWaitUntilTerminated, ResultCode)
|
||||
Exec('sc', 'delete lidarr', '', 0, ewWaitUntilTerminated, ResultCode)
|
||||
end;
|
49
docs.sh
49
docs.sh
|
@ -1,49 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
FRAMEWORK="net6.0"
|
||||
PLATFORM=$1
|
||||
ARCHITECTURE="${2:-x64}"
|
||||
|
||||
if [ "$PLATFORM" = "Windows" ]; then
|
||||
RUNTIME="win-$ARCHITECTURE"
|
||||
elif [ "$PLATFORM" = "Linux" ]; then
|
||||
RUNTIME="linux-$ARCHITECTURE"
|
||||
elif [ "$PLATFORM" = "Mac" ]; then
|
||||
RUNTIME="osx-$ARCHITECTURE"
|
||||
else
|
||||
echo "Platform must be provided as first argument: Windows, Linux or Mac"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
outputFolder='_output'
|
||||
testPackageFolder='_tests'
|
||||
|
||||
rm -rf $outputFolder
|
||||
rm -rf $testPackageFolder
|
||||
|
||||
slnFile=src/Lidarr.sln
|
||||
|
||||
platform=Posix
|
||||
|
||||
if [ "$PLATFORM" = "Windows" ]; then
|
||||
application=Lidarr.Console.dll
|
||||
else
|
||||
application=Lidarr.dll
|
||||
fi
|
||||
|
||||
dotnet clean $slnFile -c Debug
|
||||
dotnet clean $slnFile -c Release
|
||||
|
||||
dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids
|
||||
|
||||
dotnet new tool-manifest
|
||||
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli
|
||||
|
||||
dotnet tool run swagger tofile --output ./src/Lidarr.Api.V1/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v1 &
|
||||
|
||||
sleep 45
|
||||
|
||||
kill %1
|
||||
|
||||
exit 0
|
25
frontend/.csscomb.json
Normal file
25
frontend/.csscomb.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"remove-empty-rulesets": true,
|
||||
"always-semicolon": true,
|
||||
"color-case": "lower",
|
||||
"block-indent": " ",
|
||||
"color-shorthand": false,
|
||||
"element-case": "lower",
|
||||
"eof-newline": true,
|
||||
"leading-zero": true,
|
||||
"quotes": "double",
|
||||
"sort-order-fallback": "abc",
|
||||
"space-before-colon": "",
|
||||
"space-after-colon": " ",
|
||||
"space-before-combinator": " ",
|
||||
"space-after-combinator": " ",
|
||||
"space-between-declarations": "\n",
|
||||
"space-before-opening-brace": " ",
|
||||
"space-after-opening-brace": "\n",
|
||||
"space-after-selector-delimiter": " ",
|
||||
"space-before-selector-delimiter": "",
|
||||
"space-before-closing-brace": "\n",
|
||||
"strip-spaces": true,
|
||||
"tab-size": true,
|
||||
"unitless-zero": false
|
||||
}
|
6
frontend/.editorconfig
Normal file
6
frontend/.editorconfig
Normal file
|
@ -0,0 +1,6 @@
|
|||
[*]
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{js,css}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
335
frontend/.esformatter
Normal file
335
frontend/.esformatter
Normal file
|
@ -0,0 +1,335 @@
|
|||
{
|
||||
"indent": {
|
||||
"value": " ",
|
||||
"FunctionExpression": 1,
|
||||
"ArrayExpression": 1,
|
||||
"ObjectExpression": 1
|
||||
},
|
||||
"lineBreak": {
|
||||
"value": "\n",
|
||||
|
||||
"before": {
|
||||
"ArrayPatternClosing": 0,
|
||||
"ArrayPatternComma": 0,
|
||||
"ArrayPatternOpening": 0,
|
||||
"ArrowFunctionExpressionArrow": 0,
|
||||
"ArrowFunctionExpressionClosingBrace": ">=1",
|
||||
"ArrowFunctionExpressionOpeningBrace": 0,
|
||||
"AssignmentExpression": ">=1",
|
||||
"AssignmentOperator": 0,
|
||||
"BlockStatement": 0,
|
||||
"BreakKeyword": ">=1",
|
||||
"CallExpression": -1,
|
||||
"CallExpressionClosingParentheses": -1,
|
||||
"CallExpressionOpeningParentheses": 0,
|
||||
"CatchClosingBrace": ">=1",
|
||||
"CatchKeyword": 0,
|
||||
"CatchOpeningBrace": 0,
|
||||
"ClassDeclaration": ">=1",
|
||||
"ClassDeclarationClosingBrace": ">=1",
|
||||
"ClassDeclarationOpeningBrace": 0,
|
||||
"ConditionalExpression": ">=1",
|
||||
"DeleteOperator": ">=1",
|
||||
"DoWhileStatement": ">=1",
|
||||
"DoWhileStatementClosingBrace": ">=1",
|
||||
"DoWhileStatementOpeningBrace": 0,
|
||||
"ElseIfStatement": 0,
|
||||
"ElseIfStatementClosingBrace": ">=1",
|
||||
"ElseIfStatementOpeningBrace": 0,
|
||||
"ElseStatement": 0,
|
||||
"ElseStatementClosingBrace": ">=1",
|
||||
"ElseStatementOpeningBrace": 0,
|
||||
"EmptyStatement": -1,
|
||||
"EndOfFile": -1,
|
||||
"FinallyClosingBrace": ">=1",
|
||||
"FinallyKeyword": -1,
|
||||
"FinallyOpeningBrace": 0,
|
||||
"ForInStatement": ">=1",
|
||||
"ForInStatementClosingBrace": ">=1",
|
||||
"ForInStatementExpressionClosing": 0,
|
||||
"ForInStatementExpressionOpening": 0,
|
||||
"ForInStatementOpeningBrace": 0,
|
||||
"ForStatement": ">=1",
|
||||
"ForStatementClosingBrace": ">=1",
|
||||
"ForStatementExpressionClosing": "<2",
|
||||
"ForStatementExpressionOpening": 0,
|
||||
"ForStatementOpeningBrace": 0,
|
||||
"FunctionDeclaration": ">=1",
|
||||
"FunctionDeclarationClosingBrace": ">=1",
|
||||
"FunctionDeclarationOpeningBrace": 0,
|
||||
"FunctionExpression": 0,
|
||||
"FunctionExpressionClosingBrace": 1,
|
||||
"FunctionExpressionOpeningBrace":0,
|
||||
"IIFEClosingParentheses": 0,
|
||||
"IfStatement": ">=1",
|
||||
"IfStatementClosingBrace": ">=1",
|
||||
"IfStatementOpeningBrace": 0,
|
||||
"LogicalExpression": -1,
|
||||
"MemberExpressionClosing": 0,
|
||||
"MemberExpressionOpening": 0,
|
||||
"MemberExpressionPeriod": -1,
|
||||
"MethodDefinition": ">=1",
|
||||
"ObjectExpressionClosingBrace": "<=1",
|
||||
"ObjectPatternClosingBrace": 0,
|
||||
"ObjectPatternComma": 0,
|
||||
"ObjectPatternOpeningBrace": 0,
|
||||
"ParameterDefault": 0,
|
||||
"Property": "<=2",
|
||||
"PropertyValue": 0,
|
||||
"ReturnStatement": -1,
|
||||
"SwitchClosingBrace": ">=1",
|
||||
"SwitchOpeningBrace": 0,
|
||||
"ThisExpression": -1,
|
||||
"ThrowStatement": ">=1",
|
||||
"TryClosingBrace": ">=1",
|
||||
"TryKeyword": -1,
|
||||
"TryOpeningBrace": 0,
|
||||
"VariableDeclaration": ">=1",
|
||||
"VariableDeclarationSemiColon": 0,
|
||||
"VariableDeclarationWithoutInit": ">=1",
|
||||
"VariableName": ">=1",
|
||||
"VariableValue": 0,
|
||||
"WhileStatement": ">=1",
|
||||
"WhileStatementClosingBrace": ">=1",
|
||||
"WhileStatementOpeningBrace": 0
|
||||
},
|
||||
|
||||
"after": {
|
||||
"ArrayPatternClosing": 0,
|
||||
"ArrayPatternComma": 0,
|
||||
"ArrayPatternOpening": 0,
|
||||
"ArrowFunctionExpressionArrow": 0,
|
||||
"ArrowFunctionExpressionClosingBrace": -1,
|
||||
"ArrowFunctionExpressionOpeningBrace": ">=1",
|
||||
"AssignmentExpression": ">=1",
|
||||
"AssignmentOperator": 0,
|
||||
"BlockStatement": 0,
|
||||
"BreakKeyword": -1,
|
||||
"CallExpression": -1,
|
||||
"CallExpressionClosingParentheses": -1,
|
||||
"CallExpressionOpeningParentheses": -1,
|
||||
"CatchClosingBrace": ">=0",
|
||||
"CatchKeyword": 0,
|
||||
"CatchOpeningBrace": ">=1",
|
||||
"ClassDeclaration": ">=1",
|
||||
"ClassDeclarationClosingBrace": ">=1",
|
||||
"ClassDeclarationOpeningBrace": ">=1",
|
||||
"ConditionalExpression": ">=1",
|
||||
"DeleteOperator": ">=1",
|
||||
"DoWhileStatement": ">=1",
|
||||
"DoWhileStatementClosingBrace": 0,
|
||||
"DoWhileStatementOpeningBrace": ">=1",
|
||||
"ElseIfStatement": ">=1",
|
||||
"ElseIfStatementClosingBrace": ">=1",
|
||||
"ElseIfStatementOpeningBrace": ">=1",
|
||||
"ElseStatement": ">=1",
|
||||
"ElseStatementClosingBrace": ">=1",
|
||||
"ElseStatementOpeningBrace": ">=1",
|
||||
"EmptyStatement": -1,
|
||||
"FinallyClosingBrace": ">=1",
|
||||
"FinallyKeyword": -1,
|
||||
"FinallyOpeningBrace": ">=1",
|
||||
"ForInStatement": ">=1",
|
||||
"ForInStatementClosingBrace": ">=1",
|
||||
"ForInStatementExpressionClosing": -1,
|
||||
"ForInStatementExpressionOpening": "<2",
|
||||
"ForInStatementOpeningBrace": ">=1",
|
||||
"ForStatement": ">=1",
|
||||
"ForStatementClosingBrace": ">=1",
|
||||
"ForStatementExpressionClosing": -1,
|
||||
"ForStatementExpressionOpening": "<2",
|
||||
"ForStatementOpeningBrace": ">=1",
|
||||
"FunctionDeclaration": ">=1",
|
||||
"FunctionDeclarationClosingBrace": ">=1",
|
||||
"FunctionDeclarationOpeningBrace": ">=1",
|
||||
"FunctionExpression": 0,
|
||||
"FunctionExpressionClosingBrace": -1,
|
||||
"FunctionExpressionOpeningBrace": 1,
|
||||
"IIFEOpeningParentheses": 0,
|
||||
"IfStatement": ">=1",
|
||||
"IfStatementClosingBrace": ">=1",
|
||||
"IfStatementOpeningBrace": ">=1",
|
||||
"LogicalExpression": -1,
|
||||
"MemberExpressionClosing": 0,
|
||||
"MemberExpressionOpening": 0,
|
||||
"MemberExpressionPeriod": 0,
|
||||
"MethodDefinition": ">=1",
|
||||
"ObjectExpressionOpeningBrace": "<=1",
|
||||
"ObjectPatternClosingBrace": 0,
|
||||
"ObjectPatternComma": 0,
|
||||
"ObjectPatternOpeningBrace": 0,
|
||||
"ParameterDefault": 0,
|
||||
"Property": -1,
|
||||
"PropertyName": 0,
|
||||
"ReturnStatement": -1,
|
||||
"SwitchCaseColon": ">=1",
|
||||
"SwitchClosingBrace": ">=1",
|
||||
"SwitchOpeningBrace": ">=1",
|
||||
"ThisExpression": 0,
|
||||
"ThrowStatement": ">=1",
|
||||
"TryClosingBrace": 0,
|
||||
"TryKeyword": -1,
|
||||
"TryOpeningBrace": ">=1",
|
||||
"VariableDeclaration": ">=1",
|
||||
"VariableDeclarationSemiColon": ">=1",
|
||||
"VariableValue": -1,
|
||||
"WhileStatement": ">=1",
|
||||
"WhileStatementClosingBrace": ">=1",
|
||||
"WhileStatementOpeningBrace": ">=1"
|
||||
}
|
||||
},
|
||||
"whiteSpace": {
|
||||
"value": " ",
|
||||
"removeTrailing": 1,
|
||||
"before": {
|
||||
"ArgumentComma": 0,
|
||||
"ArgumentList": 0,
|
||||
"ArgumentListArrayExpression": 0,
|
||||
"ArgumentListFunctionExpression": 1,
|
||||
"ArgumentListObjectExpression": 0,
|
||||
"ArrayExpressionClosing": 0,
|
||||
"ArrayExpressionComma": 0,
|
||||
"ArrayExpressionOpening": 1,
|
||||
"AssignmentOperator": 1,
|
||||
"BinaryExpression": 0,
|
||||
"BinaryExpressionOperator": 1,
|
||||
"BlockComment": 1,
|
||||
"CallExpression": 1,
|
||||
"CatchClosingBrace": 1,
|
||||
"CatchKeyword": 1,
|
||||
"CatchOpeningBrace": 1,
|
||||
"CatchParameterList": 0,
|
||||
"CommaOperator": 0,
|
||||
"ConditionalExpressionAlternate": 1,
|
||||
"ConditionalExpressionConsequent": 1,
|
||||
"DoWhileStatementClosingBrace": 1,
|
||||
"DoWhileStatementConditional": 1,
|
||||
"DoWhileStatementOpeningBrace": 1,
|
||||
"ElseIfStatementClosingBrace": 1,
|
||||
"ElseIfStatementOpeningBrace": 1,
|
||||
"ElseStatementClosingBrace": 1,
|
||||
"ElseStatementOpeningBrace": 1,
|
||||
"EmptyStatement": 0,
|
||||
"ExpressionClosingParentheses": 0,
|
||||
"FinallyClosingBrace": 1,
|
||||
"FinallyKeyword": -1,
|
||||
"FinallyOpeningBrace": 1,
|
||||
"ForInStatement": 1,
|
||||
"ForInStatementClosingBrace": 1,
|
||||
"ForInStatementExpressionClosing": 0,
|
||||
"ForInStatementExpressionOpening": 1,
|
||||
"ForInStatementOpeningBrace": 1,
|
||||
"ForStatement": 1,
|
||||
"ForStatementClosingBrace": 1,
|
||||
"ForStatementExpressionClosing": 0,
|
||||
"ForStatementExpressionOpening": 1,
|
||||
"ForStatementOpeningBrace": 1,
|
||||
"ForStatementSemicolon": 0,
|
||||
"FunctionDeclarationClosingBrace": 1,
|
||||
"FunctionDeclarationOpeningBrace": 1,
|
||||
"FunctionExpressionClosingBrace": 1,
|
||||
"FunctionExpressionOpeningBrace": 1,
|
||||
"IfStatementClosingBrace": 1,
|
||||
"IfStatementConditionalClosing": 0,
|
||||
"IfStatementConditionalOpening": 1,
|
||||
"IfStatementOpeningBrace": 1,
|
||||
"LineComment": 1,
|
||||
"LogicalExpressionOperator": 1,
|
||||
"MemberExpressionClosing": 0,
|
||||
"ObjectExpressionClosingBrace": 1,
|
||||
"ParameterComma": 0,
|
||||
"ParameterList": 0,
|
||||
"Property": 1,
|
||||
"PropertyName": 1,
|
||||
"PropertyValue": 1,
|
||||
"SwitchDiscriminantClosing": 0,
|
||||
"SwitchDiscriminantOpening": 1,
|
||||
"ThrowKeyword": 1,
|
||||
"TryClosingBrace": 1,
|
||||
"TryKeyword": -1,
|
||||
"TryOpeningBrace": 1,
|
||||
"UnaryExpressionOperator": 0,
|
||||
"VariableName": 1,
|
||||
"VariableValue": 1,
|
||||
"WhileStatementClosingBrace": 1,
|
||||
"WhileStatementConditionalClosing": 0,
|
||||
"WhileStatementConditionalOpening": 1,
|
||||
"WhileStatementOpeningBrace": 1
|
||||
},
|
||||
"after": {
|
||||
"ArgumentComma": 1,
|
||||
"ArgumentList": 0,
|
||||
"ArgumentListArrayExpression": 1,
|
||||
"ArgumentListFunctionExpression": 1,
|
||||
"ArgumentListObjectExpression": 0,
|
||||
"ArrayExpressionClosing": 0,
|
||||
"ArrayExpressionComma": 1,
|
||||
"ArrayExpressionOpening": 0,
|
||||
"AssignmentOperator": 1,
|
||||
"BinaryExpression": 0,
|
||||
"BinaryExpressionOperator": 1,
|
||||
"BlockComment": 1,
|
||||
"CallExpression": 0,
|
||||
"CatchClosingBrace": 1,
|
||||
"CatchKeyword": 1,
|
||||
"CatchOpeningBrace": 1,
|
||||
"CatchParameterList": 0,
|
||||
"CommaOperator": 1,
|
||||
"ConditionalExpressionConsequent": 1,
|
||||
"ConditionalExpressionTest": 1,
|
||||
"DoWhileStatementBody": 1,
|
||||
"DoWhileStatementClosingBrace": 1,
|
||||
"DoWhileStatementOpeningBrace": 1,
|
||||
"ElseIfStatementClosingBrace": 1,
|
||||
"ElseIfStatementOpeningBrace": 1,
|
||||
"ElseStatementClosingBrace": 1,
|
||||
"ElseStatementOpeningBrace": 1,
|
||||
"EmptyStatement": 0,
|
||||
"ExpressionOpeningParentheses": 0,
|
||||
"FinallyClosingBrace": 1,
|
||||
"FinallyKeyword": -1,
|
||||
"FinallyOpeningBrace": 1,
|
||||
"ForInStatement": 1,
|
||||
"ForInStatementClosingBrace": 1,
|
||||
"ForInStatementExpressionClosing": 1,
|
||||
"ForInStatementExpressionOpening": 0,
|
||||
"ForInStatementOpeningBrace": 1,
|
||||
"ForStatement": 1,
|
||||
"ForStatementClosingBrace": 1,
|
||||
"ForStatementExpressionClosing": 1,
|
||||
"ForStatementExpressionOpening": 0,
|
||||
"ForStatementOpeningBrace": 1,
|
||||
"ForStatementSemicolon": 1,
|
||||
"FunctionDeclarationClosingBrace": 0,
|
||||
"FunctionDeclarationOpeningBrace": 0,
|
||||
"FunctionExpressionClosingBrace": 0,
|
||||
"FunctionExpressionOpeningBrace": 0,
|
||||
"FunctionName": 0,
|
||||
"FunctionReservedWord": 0,
|
||||
"IfStatementClosingBrace": 1,
|
||||
"IfStatementConditionalClosing": 0,
|
||||
"IfStatementConditionalOpening": 0,
|
||||
"IfStatementOpeningBrace": 1,
|
||||
"LogicalExpressionOperator": 1,
|
||||
"MemberExpressionOpening": 0,
|
||||
"ObjectExpressionClosingBrace": 0,
|
||||
"ObjectExpressionOpeningBrace": 1,
|
||||
"ParameterComma": 1,
|
||||
"ParameterList": 0,
|
||||
"PropertyName": 0,
|
||||
"PropertyValue": 0,
|
||||
"SwitchDiscriminantClosing": 1,
|
||||
"SwitchDiscriminantOpening": 0,
|
||||
"ThrowKeyword": 1,
|
||||
"TryClosingBrace": 1,
|
||||
"TryKeyword": -1,
|
||||
"TryOpeningBrace": 1,
|
||||
"UnaryExpressionOperator": 0,
|
||||
"VariableName": 1,
|
||||
"WhileStatementClosingBrace": 1,
|
||||
"WhileStatementConditionalClosing": 1,
|
||||
"WhileStatementConditionalOpening": 0,
|
||||
"WhileStatementOpeningBrace": 1
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
**/JsLibraries/**
|
||||
**/*.css.d.ts
|
||||
|
|
293
frontend/.eslintrc
Normal file
293
frontend/.eslintrc
Normal file
|
@ -0,0 +1,293 @@
|
|||
{
|
||||
"parser": "babel-eslint",
|
||||
|
||||
"env": {
|
||||
"browser": true,
|
||||
"commonjs": true,
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
|
||||
"globals": {
|
||||
"expect": false,
|
||||
"chai": false,
|
||||
"sinon": false
|
||||
},
|
||||
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"modules": true,
|
||||
"impliedStrict": true
|
||||
}
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"filenames",
|
||||
"react"
|
||||
],
|
||||
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"filenames/match-exported": ["error"],
|
||||
|
||||
# ECMAScript 6
|
||||
|
||||
"arrow-body-style": [0],
|
||||
"arrow-parens": ["error", "always"],
|
||||
"arrow-spacing": ["error", { "before": true, "after": true }],
|
||||
"constructor-super": "error",
|
||||
"generator-star-spacing": "off",
|
||||
"no-class-assign": "error",
|
||||
"no-confusing-arrow": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-new-symbol": "error",
|
||||
"no-this-before-super": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-var": "warn",
|
||||
"object-shorthand": ["error", "properties"],
|
||||
"prefer-arrow-callback": "error",
|
||||
"prefer-const": "warn",
|
||||
"prefer-reflect": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"prefer-spread": "warn",
|
||||
"prefer-template": "error",
|
||||
"require-yield": "off",
|
||||
"template-curly-spacing": ["error", "never"],
|
||||
"yield-star-spacing": "off",
|
||||
|
||||
# Possible Errors
|
||||
|
||||
"comma-dangle": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-console": "off",
|
||||
"no-constant-condition": "warn",
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "off",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-empty": "warn",
|
||||
"no-empty-character-class": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-extra-parens": ["error", "functions"],
|
||||
"no-extra-semi": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-inner-declarations": "error",
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-negated-in-lhs": "error",
|
||||
"no-obj-calls": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unreachable": "warn",
|
||||
"no-unsafe-finally": "error",
|
||||
"use-isnan": "error",
|
||||
"valid-jsdoc": "off",
|
||||
"valid-typeof": "error",
|
||||
|
||||
# Best Practices
|
||||
|
||||
"accessor-pairs": "off",
|
||||
"array-callback-return": "warn",
|
||||
"block-scoped-var": "warn",
|
||||
"consistent-return": "off",
|
||||
"curly": "error",
|
||||
"default-case": "error",
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": "error",
|
||||
"eqeqeq": ["error", "smart"],
|
||||
"guard-for-in": "error",
|
||||
"no-alert": "warn",
|
||||
"no-caller": "error",
|
||||
"no-case-declarations": "error",
|
||||
"no-div-regex": "error",
|
||||
"no-else-return": "error",
|
||||
"no-empty-function": ["error", {"allow": ["arrowFunctions"]}],
|
||||
"no-empty-pattern": "error",
|
||||
"no-eval": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-floating-decimal": "error",
|
||||
"no-implicit-coercion": ["error", {
|
||||
"boolean": false,
|
||||
"number": true,
|
||||
"string": true,
|
||||
"allow": [/* "!!", "~", "*", "+" */]
|
||||
}],
|
||||
"no-implicit-globals": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-invalid-this": "off",
|
||||
"no-iterator": "error",
|
||||
"no-labels": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-loop-func": "error",
|
||||
"no-magic-numbers": ["off", {"ignoreArrayIndexes": true, "ignore": [0, 1] }],
|
||||
"no-multi-spaces": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-native-reassign": ["error", {"exceptions": ["console"]}],
|
||||
"no-new": "off",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-octal": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-param-reassign": "off",
|
||||
"no-process-env": "off",
|
||||
"no-proto": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-return-assign": "warn",
|
||||
"no-script-url": "error",
|
||||
"no-self-assign": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unused-labels": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-void": "error",
|
||||
"no-warning-comments": "off",
|
||||
"no-with": "error",
|
||||
"radix": ["error", "as-needed"],
|
||||
"vars-on-top": "off",
|
||||
"wrap-iife": ["error", "inside"],
|
||||
"yoda": "error",
|
||||
|
||||
# Strict Mode
|
||||
|
||||
"strict": ["error", "never"],
|
||||
|
||||
# Variables
|
||||
|
||||
"init-declarations": ["error", "always"],
|
||||
"no-catch-shadow": "error",
|
||||
"no-delete-var": "error",
|
||||
"no-label-var": "error",
|
||||
"no-restricted-globals": "off",
|
||||
"no-shadow": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-undef": "error",
|
||||
"no-undef-init": "off",
|
||||
"no-undefined": "off",
|
||||
"no-unused-vars": ["error", { "args": "none", "ignoreRestSiblings": true }],
|
||||
"no-use-before-define": "error",
|
||||
|
||||
# Node.js and CommonJS
|
||||
|
||||
"callback-return": "warn",
|
||||
"global-require": "error",
|
||||
"handle-callback-err": "warn",
|
||||
"no-mixed-requires": "error",
|
||||
"no-new-require": "error",
|
||||
"no-path-concat": "error",
|
||||
"no-process-exit": "error",
|
||||
|
||||
# Stylistic Issues
|
||||
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
"block-spacing": ["error", "always"],
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
|
||||
"camelcase": "off",
|
||||
"comma-spacing": ["error", {"before": false, "after": true}],
|
||||
"comma-style": ["error", "last"],
|
||||
"computed-property-spacing": ["error", "never"],
|
||||
"consistent-this": ["error", "self"],
|
||||
"eol-last": "error",
|
||||
"func-names": "off",
|
||||
"func-style": ["error", "declaration"],
|
||||
"indent": ["error", 2, {"SwitchCase": 1}],
|
||||
"key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
|
||||
"keyword-spacing": ["error", { "before": true, "after": true}],
|
||||
"lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": false }],
|
||||
"max-depth": ["error", {"maximum": 5}],
|
||||
"max-nested-callbacks": ["error", 4],
|
||||
"max-statements": "off",
|
||||
"max-statements-per-line": ["error", { "max": 1 }],
|
||||
"new-cap": ["error", {"capIsNewExceptions": ["$.Deferred", "DragDropContext", "DragLayer", "DragSource", "DropTarget"]}],
|
||||
"new-parens": "error",
|
||||
"newline-after-var": "off",
|
||||
"newline-before-return": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"no-array-constructor": "error",
|
||||
"no-bitwise": "error",
|
||||
"no-continue": "error",
|
||||
"no-inline-comments": "off",
|
||||
"no-lonely-if": "warn",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"no-multiple-empty-lines": ["error", { "max": 1 }],
|
||||
"no-negated-condition": "warn",
|
||||
"no-nested-ternary": "error",
|
||||
"no-new-object": "error",
|
||||
"no-plusplus": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"no-spaced-func": "error",
|
||||
"no-ternary": "off",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-underscore-dangle": ["error", { "allowAfterThis": true }],
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"one-var": ["error", "never"],
|
||||
"one-var-declaration-per-line": ["error", "always"],
|
||||
"operator-assignment": ["off", "never"],
|
||||
"operator-linebreak": ["error", "after"],
|
||||
"quote-props": ["error", "as-needed"],
|
||||
"quotes": ["error", "single"],
|
||||
"require-jsdoc": "off",
|
||||
"semi": "error",
|
||||
"semi-spacing": ["error", { "before": false, "after": true }],
|
||||
"sort-vars": "off",
|
||||
"space-before-blocks": ["error", "always"],
|
||||
"space-before-function-paren": ["error", "never"],
|
||||
"space-in-parens": "off",
|
||||
"space-infix-ops": "off",
|
||||
"space-unary-ops": "off",
|
||||
"spaced-comment": "error",
|
||||
"wrap-regex": "error",
|
||||
|
||||
# React
|
||||
|
||||
"react/jsx-boolean-value": [2, "always"],
|
||||
"react/jsx-uses-vars": 2,
|
||||
"react/jsx-closing-bracket-location": 2,
|
||||
"react/jsx-tag-spacing": ["error"],
|
||||
"react/jsx-curly-spacing": [2, "never"],
|
||||
"react/jsx-equals-spacing": [2, "never"],
|
||||
"react/jsx-indent-props": [2, 2],
|
||||
"react/jsx-indent": [2, 2],
|
||||
"react/jsx-key": 2,
|
||||
"react/jsx-no-bind": [2, { "allowArrowFunctions": true }],
|
||||
"react/jsx-no-duplicate-props": [2, { "ignoreCase": true }],
|
||||
"react/jsx-max-props-per-line": [2, { "maximum": 2 }],
|
||||
"react/jsx-handler-names": [2, { "eventHandlerPrefix": "(on|dispatch)", "eventHandlerPropPrefix": "on" }],
|
||||
"react/jsx-no-undef": 2,
|
||||
"react/jsx-pascal-case": 2,
|
||||
"react/jsx-uses-react": 2,
|
||||
// Explicitly disabled in case we want to enable them again
|
||||
"react/no-did-mount-set-state": 0,
|
||||
"react/no-did-update-set-state": 0,
|
||||
"react/no-direct-mutation-state": 2,
|
||||
"react/no-multi-comp": [2, { "ignoreStateless": true }],
|
||||
"react/no-unknown-property": 2,
|
||||
"react/prefer-es6-class": 2,
|
||||
"react/prop-types": 2,
|
||||
"react/react-in-jsx-scope": 2,
|
||||
"react/self-closing-comp": 2,
|
||||
"react/sort-comp": 2,
|
||||
"react/jsx-wrap-multilines": 2
|
||||
}
|
||||
}
|
|
@ -1,393 +0,0 @@
|
|||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const typescriptEslintRecommended = require('@typescript-eslint/eslint-plugin').configs.recommended;
|
||||
|
||||
const frontendFolder = __dirname;
|
||||
|
||||
const dirs = fs
|
||||
.readdirSync(path.join(frontendFolder, 'src'), { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name)
|
||||
.join('|');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
|
||||
parser: '@babel/eslint-parser',
|
||||
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
node: true,
|
||||
es6: true
|
||||
},
|
||||
|
||||
globals: {
|
||||
expect: false,
|
||||
chai: false,
|
||||
sinon: false,
|
||||
JSX: true
|
||||
},
|
||||
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
sourceType: 'module',
|
||||
babelOptions: {
|
||||
configFile: `${frontendFolder}/babel.config.js`
|
||||
},
|
||||
ecmaFeatures: {
|
||||
modules: true,
|
||||
impliedStrict: true
|
||||
}
|
||||
},
|
||||
|
||||
plugins: [
|
||||
'filenames',
|
||||
'react',
|
||||
'react-hooks',
|
||||
'simple-import-sort',
|
||||
'import',
|
||||
'@typescript-eslint',
|
||||
'prettier'
|
||||
],
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
},
|
||||
|
||||
rules: {
|
||||
'filenames/match-exported': ['error'],
|
||||
|
||||
// ECMAScript 6
|
||||
|
||||
'arrow-body-style': [0],
|
||||
'arrow-parens': ['error', 'always'],
|
||||
'arrow-spacing': ['error', { before: true, after: true }],
|
||||
'constructor-super': 'error',
|
||||
'generator-star-spacing': 'off',
|
||||
'no-class-assign': 'error',
|
||||
'no-confusing-arrow': 'error',
|
||||
'no-const-assign': 'error',
|
||||
'no-dupe-class-members': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-new-symbol': 'error',
|
||||
'no-this-before-super': 'error',
|
||||
'no-useless-escape': 'error',
|
||||
'no-useless-computed-key': 'error',
|
||||
'no-useless-constructor': 'error',
|
||||
'no-var': 'warn',
|
||||
'object-shorthand': ['error', 'properties'],
|
||||
'prefer-arrow-callback': 'error',
|
||||
'prefer-const': 'warn',
|
||||
'prefer-reflect': 'off',
|
||||
'prefer-rest-params': 'off',
|
||||
'prefer-spread': 'warn',
|
||||
'prefer-template': 'error',
|
||||
'require-yield': 'off',
|
||||
'template-curly-spacing': ['error', 'never'],
|
||||
'yield-star-spacing': 'off',
|
||||
|
||||
// Possible Errors
|
||||
|
||||
'comma-dangle': 'error',
|
||||
'no-cond-assign': 'error',
|
||||
'no-console': 'off',
|
||||
'no-constant-condition': 'warn',
|
||||
'no-control-regex': 'error',
|
||||
'no-debugger': 'off',
|
||||
'no-dupe-args': 'error',
|
||||
'no-dupe-keys': 'error',
|
||||
'no-duplicate-case': 'error',
|
||||
'no-empty': 'warn',
|
||||
'no-empty-character-class': 'error',
|
||||
'no-ex-assign': 'error',
|
||||
'no-extra-boolean-cast': 'error',
|
||||
'no-extra-parens': ['error', 'functions'],
|
||||
'no-extra-semi': 'error',
|
||||
'no-func-assign': 'error',
|
||||
'no-inner-declarations': 'error',
|
||||
'no-invalid-regexp': 'error',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-negated-in-lhs': 'error',
|
||||
'no-obj-calls': 'error',
|
||||
'no-regex-spaces': 'error',
|
||||
'no-sparse-arrays': 'error',
|
||||
'no-unexpected-multiline': 'error',
|
||||
'no-unreachable': 'warn',
|
||||
'no-unsafe-finally': 'error',
|
||||
'use-isnan': 'error',
|
||||
'valid-jsdoc': 'off',
|
||||
'valid-typeof': 'error',
|
||||
|
||||
// Best Practices
|
||||
|
||||
'accessor-pairs': 'off',
|
||||
'array-callback-return': 'warn',
|
||||
'block-scoped-var': 'warn',
|
||||
'consistent-return': 'off',
|
||||
curly: 'error',
|
||||
'default-case': 'error',
|
||||
'dot-location': ['error', 'property'],
|
||||
'dot-notation': 'error',
|
||||
eqeqeq: ['error', 'smart'],
|
||||
'guard-for-in': 'error',
|
||||
'no-alert': 'warn',
|
||||
'no-caller': 'error',
|
||||
'no-case-declarations': 'error',
|
||||
'no-div-regex': 'error',
|
||||
'no-else-return': 'error',
|
||||
'no-empty-function': ['error', { allow: ['arrowFunctions'] }],
|
||||
'no-empty-pattern': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-extra-bind': 'error',
|
||||
'no-fallthrough': 'error',
|
||||
'no-floating-decimal': 'error',
|
||||
'no-implicit-coercion': ['error', {
|
||||
boolean: false,
|
||||
number: true,
|
||||
string: true,
|
||||
allow: [/* "!!", "~", "*", "+" */]
|
||||
}],
|
||||
'no-implicit-globals': 'error',
|
||||
'no-implied-eval': 'error',
|
||||
'no-invalid-this': 'off',
|
||||
'no-iterator': 'error',
|
||||
'no-labels': 'error',
|
||||
'no-lone-blocks': 'error',
|
||||
'no-loop-func': 'error',
|
||||
'no-magic-numbers': ['off', { ignoreArrayIndexes: true, ignore: [0, 1] }],
|
||||
'no-multi-spaces': 'error',
|
||||
'no-multi-str': 'error',
|
||||
'no-native-reassign': ['error', { exceptions: ['console'] }],
|
||||
'no-new': 'off',
|
||||
'no-new-func': 'error',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-octal': 'error',
|
||||
'no-octal-escape': 'error',
|
||||
'no-param-reassign': 'off',
|
||||
'no-process-env': 'off',
|
||||
'no-proto': 'error',
|
||||
'no-redeclare': 'error',
|
||||
'no-return-assign': 'warn',
|
||||
'no-script-url': 'error',
|
||||
'no-self-assign': 'error',
|
||||
'no-self-compare': 'error',
|
||||
'no-sequences': 'error',
|
||||
'no-throw-literal': 'error',
|
||||
'no-unmodified-loop-condition': 'error',
|
||||
'no-unused-expressions': 'error',
|
||||
'no-unused-labels': 'error',
|
||||
'no-useless-call': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'no-void': 'error',
|
||||
'no-warning-comments': 'off',
|
||||
'no-with': 'error',
|
||||
radix: ['error', 'as-needed'],
|
||||
'vars-on-top': 'off',
|
||||
'wrap-iife': ['error', 'inside'],
|
||||
yoda: 'error',
|
||||
|
||||
// Strict Mode
|
||||
|
||||
strict: ['error', 'never'],
|
||||
|
||||
// Variables
|
||||
|
||||
'init-declarations': ['error', 'always'],
|
||||
'no-catch-shadow': 'error',
|
||||
'no-delete-var': 'error',
|
||||
'no-label-var': 'error',
|
||||
'no-restricted-globals': 'off',
|
||||
'no-shadow': 'error',
|
||||
'no-shadow-restricted-names': 'error',
|
||||
'no-undef': 'error',
|
||||
'no-undef-init': 'off',
|
||||
'no-undefined': 'off',
|
||||
'no-unused-vars': ['error', { args: 'none', ignoreRestSiblings: true }],
|
||||
'no-use-before-define': 'error',
|
||||
|
||||
// Node.js and CommonJS
|
||||
|
||||
'callback-return': 'warn',
|
||||
'global-require': 'error',
|
||||
'handle-callback-err': 'warn',
|
||||
'no-mixed-requires': 'error',
|
||||
'no-new-require': 'error',
|
||||
'no-path-concat': 'error',
|
||||
'no-process-exit': 'error',
|
||||
|
||||
// Stylistic Issues
|
||||
|
||||
'array-bracket-spacing': ['error', 'never'],
|
||||
'block-spacing': ['error', 'always'],
|
||||
'brace-style': ['error', '1tbs', { allowSingleLine: false }],
|
||||
camelcase: 'off',
|
||||
'comma-spacing': ['error', { before: false, after: true }],
|
||||
'comma-style': ['error', 'last'],
|
||||
'computed-property-spacing': ['error', 'never'],
|
||||
'consistent-this': ['error', 'self'],
|
||||
'eol-last': 'error',
|
||||
'func-names': 'off',
|
||||
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
|
||||
indent: ['error', 2, { SwitchCase: 1 }],
|
||||
'key-spacing': ['error', { beforeColon: false, afterColon: true }],
|
||||
'keyword-spacing': ['error', { before: true, after: true }],
|
||||
'lines-around-comment': ['error', { beforeBlockComment: true, afterBlockComment: false }],
|
||||
'max-depth': ['error', { maximum: 5 }],
|
||||
'max-nested-callbacks': ['error', 4],
|
||||
'max-statements': 'off',
|
||||
'max-statements-per-line': ['error', { max: 1 }],
|
||||
'new-cap': ['error', { capIsNewExceptions: ['$.Deferred', 'DragDropContext', 'DragLayer', 'DragSource', 'DropTarget'] }],
|
||||
'new-parens': 'error',
|
||||
'newline-after-var': 'off',
|
||||
'newline-before-return': 'off',
|
||||
'newline-per-chained-call': 'off',
|
||||
'no-array-constructor': 'error',
|
||||
'no-bitwise': 'error',
|
||||
'no-continue': 'error',
|
||||
'no-inline-comments': 'off',
|
||||
'no-lonely-if': 'warn',
|
||||
'no-mixed-spaces-and-tabs': 'error',
|
||||
'no-multiple-empty-lines': ['error', { max: 1 }],
|
||||
'no-negated-condition': 'warn',
|
||||
'no-nested-ternary': 'error',
|
||||
'no-new-object': 'error',
|
||||
'no-plusplus': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
'no-spaced-func': 'error',
|
||||
'no-ternary': 'off',
|
||||
'no-trailing-spaces': 'error',
|
||||
'no-underscore-dangle': ['error', { allowAfterThis: true }],
|
||||
'no-unneeded-ternary': 'error',
|
||||
'no-whitespace-before-property': 'error',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'one-var': ['error', 'never'],
|
||||
'one-var-declaration-per-line': ['error', 'always'],
|
||||
'operator-assignment': ['off', 'never'],
|
||||
'operator-linebreak': ['error', 'after'],
|
||||
'quote-props': ['error', 'as-needed'],
|
||||
quotes: ['error', 'single'],
|
||||
'require-jsdoc': 'off',
|
||||
semi: 'error',
|
||||
'semi-spacing': ['error', { before: false, after: true }],
|
||||
'sort-vars': 'off',
|
||||
'space-before-blocks': ['error', 'always'],
|
||||
'space-before-function-paren': ['error', 'never'],
|
||||
'space-in-parens': 'off',
|
||||
'space-infix-ops': 'off',
|
||||
'space-unary-ops': 'off',
|
||||
'spaced-comment': 'error',
|
||||
'wrap-regex': 'error',
|
||||
|
||||
// ImportSort
|
||||
|
||||
'simple-import-sort/imports': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
|
||||
// React
|
||||
|
||||
'react/jsx-boolean-value': [2, 'always'],
|
||||
'react/jsx-uses-vars': 2,
|
||||
'react/jsx-closing-bracket-location': 2,
|
||||
'react/jsx-tag-spacing': ['error'],
|
||||
'react/jsx-curly-spacing': [2, 'never'],
|
||||
'react/jsx-equals-spacing': [2, 'never'],
|
||||
'react/jsx-indent-props': [2, 2],
|
||||
'react/jsx-indent': [2, 2, { indentLogicalExpressions: true }],
|
||||
'react/jsx-key': 2,
|
||||
'react/jsx-no-bind': [2, { allowArrowFunctions: true }],
|
||||
'react/jsx-no-duplicate-props': [2, { ignoreCase: true }],
|
||||
'react/jsx-max-props-per-line': [2, { maximum: 2 }],
|
||||
'react/jsx-handler-names': [2, { eventHandlerPrefix: '(on|dispatch)', eventHandlerPropPrefix: 'on' }],
|
||||
'react/jsx-no-undef': 2,
|
||||
'react/jsx-pascal-case': 2,
|
||||
'react/jsx-uses-react': 2,
|
||||
// Explicitly disabled in case we want to enable them again
|
||||
'react/no-did-mount-set-state': 0,
|
||||
'react/no-did-update-set-state': 0,
|
||||
'react/no-direct-mutation-state': 2,
|
||||
'react/no-multi-comp': [2, { ignoreStateless: true }],
|
||||
'react/no-unknown-property': 2,
|
||||
'react/prefer-es6-class': 2,
|
||||
'react/prop-types': 2,
|
||||
'react/react-in-jsx-scope': 2,
|
||||
'react/self-closing-comp': 2,
|
||||
'react/sort-comp': 2,
|
||||
'react/jsx-wrap-multilines': 2,
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'react-hooks/exhaustive-deps': 'error'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'*.js'
|
||||
],
|
||||
rules: {
|
||||
'simple-import-sort/imports': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
// Packages
|
||||
// Absolute Paths
|
||||
// Relative Paths
|
||||
// Css
|
||||
['^@?\\w', `^(${dirs})(/.*|$)`, '^\\.', '^\\..*css$']
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'*.ts',
|
||||
'*.tsx'
|
||||
],
|
||||
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: './tsconfig.json'
|
||||
},
|
||||
|
||||
extends: [
|
||||
'prettier'
|
||||
],
|
||||
|
||||
rules: Object.assign(typescriptEslintRecommended.rules, {
|
||||
'no-shadow': 'off',
|
||||
// These should be enabled after cleaning things up
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'react/prop-types': 'off',
|
||||
'prettier/prettier': 'error',
|
||||
'simple-import-sort/imports': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
// Packages
|
||||
// Absolute Paths
|
||||
// Relative Paths
|
||||
// Css
|
||||
['^@?\\w', `^(${dirs})(/.*|$)`, '^\\.', '^\\..*css$']
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'*.css.d.ts'
|
||||
],
|
||||
rules: {
|
||||
'filenames/match-exported': 'off',
|
||||
'init-declarations': 'off',
|
||||
'prettier/prettier': 'off'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
12
frontend/.jsbeautifyrc
Normal file
12
frontend/.jsbeautifyrc
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"js": {
|
||||
"indent_size": 2,
|
||||
"indent_char": " ",
|
||||
"indent_level": 2,
|
||||
"indent_with_tabs": false,
|
||||
"preserve_newlines": true,
|
||||
"brace_style": "collapse",
|
||||
"max_preserve_newlines": 2,
|
||||
"jslint_happy": true
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# Ignore everything recursively
|
||||
*
|
||||
|
||||
# But not the .ts files
|
||||
!*.ts*
|
||||
|
||||
*css.d.ts
|
||||
|
||||
# Check subdirectories too
|
||||
!*/
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "auto",
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"plugins": [
|
||||
"stylelint-order"
|
||||
],
|
||||
"ignoreFiles": [
|
||||
"frontend/src/Styles/scaffolding.css",
|
||||
"**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
"plugins": [
|
||||
"stylelint-order"
|
||||
],
|
||||
"ignoreFiles": [
|
||||
"frontend/src/Styles/scaffolding.css",
|
||||
"**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
"at-rule-empty-line-before": [
|
||||
"always",
|
||||
{
|
||||
|
@ -15,6 +15,9 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"at-rule-name-case": "lower",
|
||||
"at-rule-name-newline-after": "always-multi-line",
|
||||
"at-rule-name-space-after": "always",
|
||||
"at-rule-no-unknown": [
|
||||
true,
|
||||
{
|
||||
|
@ -25,36 +28,83 @@
|
|||
}
|
||||
],
|
||||
"at-rule-no-vendor-prefix": true,
|
||||
"at-rule-semicolon-newline-after": "always",
|
||||
"at-rule-semicolon-space-before": "never",
|
||||
"block-closing-brace-empty-line-before": "never",
|
||||
"block-closing-brace-newline-after": "always",
|
||||
"block-closing-brace-newline-before": "always",
|
||||
"block-closing-brace-space-after": "always-single-line",
|
||||
"block-closing-brace-space-before": "always-single-line",
|
||||
"block-no-empty": true,
|
||||
"block-opening-brace-newline-after": "always",
|
||||
"block-opening-brace-newline-before": "never-single-line",
|
||||
"block-opening-brace-space-after": "always-single-line",
|
||||
"block-opening-brace-space-before": "always",
|
||||
"color-hex-case": "lower",
|
||||
"color-hex-length": "short",
|
||||
"color-named": "never",
|
||||
"color-no-invalid-hex": true,
|
||||
"comment-whitespace-inside": "always",
|
||||
"declaration-bang-space-after": "never",
|
||||
"declaration-bang-space-before": "always",
|
||||
"declaration-block-no-duplicate-properties": [
|
||||
true,
|
||||
{
|
||||
"ignoreProperties": [
|
||||
"composes"
|
||||
"composes"
|
||||
]
|
||||
}
|
||||
],
|
||||
"declaration-block-no-redundant-longhand-properties": true,
|
||||
"declaration-block-no-shorthand-property-overrides": true,
|
||||
"declaration-block-semicolon-newline-after": "always",
|
||||
"declaration-block-semicolon-newline-before": "never-multi-line",
|
||||
"declaration-block-semicolon-space-before": "never",
|
||||
"declaration-block-single-line-max-declarations": 1,
|
||||
"declaration-block-trailing-semicolon": "always",
|
||||
"declaration-colon-space-after": "always",
|
||||
"declaration-colon-space-before": "never",
|
||||
"font-family-name-quotes": "always-unless-keyword",
|
||||
"function-calc-no-unspaced-operator": true,
|
||||
"function-comma-newline-after": "never-multi-line",
|
||||
"function-comma-newline-before": "never-multi-line",
|
||||
"function-comma-space-after": "always",
|
||||
"function-comma-space-before": "never",
|
||||
"function-linear-gradient-no-nonstandard-direction": true,
|
||||
"function-name-case": "lower",
|
||||
"function-parentheses-newline-inside": "never-multi-line",
|
||||
"function-parentheses-space-inside": "never",
|
||||
"function-url-quotes": "always",
|
||||
"function-url-scheme-disallowed-list": [
|
||||
"function-url-scheme-blacklist": [
|
||||
"data"
|
||||
],
|
||||
"function-whitespace-after": "always",
|
||||
"indentation": 2,
|
||||
"keyframe-declaration-no-important": true,
|
||||
"length-zero-no-unit": true,
|
||||
"max-empty-lines": 1,
|
||||
"max-line-length": [
|
||||
100,
|
||||
{
|
||||
"ignore": [
|
||||
"non-comments"
|
||||
]
|
||||
}
|
||||
],
|
||||
"max-nesting-depth": 2,
|
||||
"media-feature-colon-space-after": "always",
|
||||
"media-feature-colon-space-before": "never",
|
||||
"media-feature-name-case": "lower",
|
||||
"media-feature-name-no-vendor-prefix": true,
|
||||
"media-feature-range-operator-space-after": "always",
|
||||
"media-feature-range-operator-space-before": "always",
|
||||
"no-empty-source": true,
|
||||
"no-eol-whitespace": true,
|
||||
"no-extra-semicolons": true,
|
||||
"no-invalid-double-slash-comments": true,
|
||||
"no-missing-end-of-source-newline": true,
|
||||
"number-leading-zero": "always",
|
||||
"number-no-trailing-zeros": true,
|
||||
"order/order": [
|
||||
"custom-properties",
|
||||
"dollar-variables",
|
||||
|
@ -82,7 +132,6 @@
|
|||
"right",
|
||||
"bottom",
|
||||
"left",
|
||||
"inset",
|
||||
"z-index",
|
||||
"display",
|
||||
"visibility",
|
||||
|
@ -294,33 +343,54 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"property-case": "lower",
|
||||
"property-no-vendor-prefix": true,
|
||||
"rule-empty-line-before": [
|
||||
"always",
|
||||
{
|
||||
"except": [
|
||||
"first-nested"
|
||||
"first-nested"
|
||||
],
|
||||
"ignore": [
|
||||
"after-comment"
|
||||
"after-comment"
|
||||
]
|
||||
}
|
||||
],
|
||||
"selector-attribute-brackets-space-inside": "never",
|
||||
"selector-attribute-operator-space-after": "never",
|
||||
"selector-attribute-operator-space-before": "never",
|
||||
"selector-attribute-quotes": "never",
|
||||
"selector-class-pattern": "^[A-Za-z0-9]+$",
|
||||
"selector-combinator-space-after": "always",
|
||||
"selector-combinator-space-before": "always",
|
||||
"selector-descendant-combinator-no-non-space": true,
|
||||
"selector-list-comma-newline-after": "always",
|
||||
"selector-list-comma-newline-before": "never-multi-line",
|
||||
"selector-list-comma-space-before": "never",
|
||||
"selector-max-attribute": 0,
|
||||
"selector-max-class": 3,
|
||||
"selector-max-compound-selectors": 3,
|
||||
"selector-max-empty-lines": 0,
|
||||
"selector-max-id": 0,
|
||||
"selector-max-universal": 0,
|
||||
"selector-pseudo-class-case": "lower",
|
||||
"selector-pseudo-class-parentheses-space-inside": "never",
|
||||
"selector-pseudo-element-case": "lower",
|
||||
"selector-pseudo-element-colon-notation": "double",
|
||||
"selector-pseudo-element-no-unknown": true,
|
||||
"selector-type-case": "lower",
|
||||
"selector-type-no-unknown": true,
|
||||
"shorthand-property-no-redundant-values": true,
|
||||
"string-no-newline": true,
|
||||
"string-quotes": "single",
|
||||
"time-min-milliseconds": 100,
|
||||
"unit-case": "lower",
|
||||
"unit-no-unknown": true,
|
||||
"value-list-comma-newline-after": "never-multi-line",
|
||||
"value-list-comma-newline-before": "never-multi-line",
|
||||
"value-list-comma-space-after": "always",
|
||||
"value-list-comma-space-before": "never",
|
||||
"value-list-max-empty-lines": 0,
|
||||
"value-no-vendor-prefix": true
|
||||
}
|
||||
}
|
7
frontend/.vscode/extensions.json
vendored
7
frontend/.vscode/extensions.json
vendored
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"stylelint.vscode-stylelint",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
23
frontend/.vscode/settings.json
vendored
23
frontend/.vscode/settings.json
vendored
|
@ -1,23 +0,0 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.insertFinalNewline": true,
|
||||
|
||||
"files.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/*.d.css": true
|
||||
},
|
||||
|
||||
"editor.formatOnSave": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit"
|
||||
},
|
||||
|
||||
"typescript.preferences.quoteStyle": "single",
|
||||
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact"
|
||||
],
|
||||
}
|
|
@ -2,25 +2,22 @@ const loose = true;
|
|||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'@babel/plugin-transform-logical-assignment-operators',
|
||||
|
||||
// Stage 1
|
||||
'@babel/plugin-proposal-export-default-from',
|
||||
['@babel/plugin-transform-optional-chaining', { loose }],
|
||||
['@babel/plugin-transform-nullish-coalescing-operator', { loose }],
|
||||
['@babel/plugin-proposal-optional-chaining', { loose }],
|
||||
['@babel/plugin-proposal-nullish-coalescing-operator', { loose }],
|
||||
|
||||
// Stage 2
|
||||
'@babel/plugin-transform-export-namespace-from',
|
||||
'@babel/plugin-proposal-export-namespace-from',
|
||||
|
||||
// Stage 3
|
||||
['@babel/plugin-transform-class-properties', { loose }],
|
||||
['@babel/plugin-proposal-class-properties', { loose }],
|
||||
'@babel/plugin-syntax-dynamic-import'
|
||||
],
|
||||
env: {
|
||||
development: {
|
||||
presets: [
|
||||
['@babel/preset-react', { development: true }],
|
||||
'@babel/preset-typescript'
|
||||
['@babel/preset-react', { development: true }]
|
||||
],
|
||||
plugins: [
|
||||
'babel-plugin-inline-classnames'
|
||||
|
@ -28,8 +25,7 @@ module.exports = {
|
|||
},
|
||||
production: {
|
||||
presets: [
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript'
|
||||
'@babel/preset-react'
|
||||
],
|
||||
plugins: [
|
||||
'babel-plugin-transform-react-remove-prop-types'
|
||||
|
|
6
frontend/browsers.js
Normal file
6
frontend/browsers.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
module.exports = [
|
||||
'>0.25%',
|
||||
'not ie 11',
|
||||
'not op_mini all',
|
||||
'not chrome < 60'
|
||||
];
|
|
@ -1,291 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const FileManagerPlugin = require('filemanager-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const LiveReloadPlugin = require('webpack-livereload-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
|
||||
module.exports = (env) => {
|
||||
const uiFolder = 'UI';
|
||||
const frontendFolder = path.join(__dirname, '..');
|
||||
const srcFolder = path.join(frontendFolder, 'src');
|
||||
const isProduction = !!env.production;
|
||||
const isProfiling = isProduction && !!env.profile;
|
||||
const inlineWebWorkers = 'no-fallback';
|
||||
|
||||
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
|
||||
|
||||
console.log('Source Folder:', srcFolder);
|
||||
console.log('Output Folder:', distFolder);
|
||||
console.log('isProduction:', isProduction);
|
||||
console.log('isProfiling:', isProfiling);
|
||||
|
||||
const config = {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
devtool: isProduction ? 'source-map' : 'eval-source-map',
|
||||
target: 'web',
|
||||
|
||||
stats: {
|
||||
children: false
|
||||
},
|
||||
|
||||
watchOptions: {
|
||||
ignored: /node_modules/
|
||||
},
|
||||
|
||||
entry: {
|
||||
index: 'index.ts'
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: [
|
||||
'.ts',
|
||||
'.tsx',
|
||||
'.js'
|
||||
],
|
||||
modules: [
|
||||
srcFolder,
|
||||
path.join(srcFolder, 'Shims'),
|
||||
'node_modules'
|
||||
],
|
||||
alias: {
|
||||
jquery: 'jquery/dist/jquery.min',
|
||||
'react-middle-truncate': 'react-middle-truncate/lib/react-middle-truncate'
|
||||
},
|
||||
fallback: {
|
||||
buffer: false,
|
||||
http: false,
|
||||
https: false,
|
||||
url: false,
|
||||
util: false,
|
||||
net: false
|
||||
}
|
||||
},
|
||||
|
||||
output: {
|
||||
path: distFolder,
|
||||
publicPath: '/',
|
||||
filename: isProduction ? '[name]-[contenthash].js' : '[name].js',
|
||||
sourceMapFilename: '[file].map'
|
||||
},
|
||||
|
||||
optimization: {
|
||||
moduleIds: 'deterministic',
|
||||
chunkIds: isProduction ? 'deterministic' : 'named'
|
||||
},
|
||||
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
|
||||
experiments: {
|
||||
topLevelAwait: true
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: !isProduction,
|
||||
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
|
||||
}),
|
||||
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'Content/styles.css',
|
||||
chunkFilename: isProduction ? 'Content/[id]-[chunkhash].css' : 'Content/[id].css'
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'frontend/src/index.ejs',
|
||||
filename: 'index.html',
|
||||
publicPath: '/',
|
||||
inject: false
|
||||
}),
|
||||
|
||||
new FileManagerPlugin({
|
||||
events: {
|
||||
onEnd: {
|
||||
copy: [
|
||||
// HTML
|
||||
{
|
||||
source: 'frontend/src/*.html',
|
||||
destination: distFolder
|
||||
},
|
||||
|
||||
// Fonts
|
||||
{
|
||||
source: 'frontend/src/Content/Fonts/*.*',
|
||||
destination: path.join(distFolder, 'Content/Fonts')
|
||||
},
|
||||
|
||||
// Icon Images
|
||||
{
|
||||
source: 'frontend/src/Content/Images/Icons/*.*',
|
||||
destination: path.join(distFolder, 'Content/Images/Icons')
|
||||
},
|
||||
|
||||
// Images
|
||||
{
|
||||
source: 'frontend/src/Content/Images/*.*',
|
||||
destination: path.join(distFolder, 'Content/Images')
|
||||
},
|
||||
|
||||
// Robots
|
||||
{
|
||||
source: 'frontend/src/Content/robots.txt',
|
||||
destination: path.join(distFolder, 'Content/robots.txt')
|
||||
},
|
||||
|
||||
// manifest.json and browserconfig.xml
|
||||
{
|
||||
source: 'frontend/src/Content/*.(json|xml)',
|
||||
destination: path.join(distFolder, 'Content')
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
new ForkTsCheckerWebpackPlugin(),
|
||||
|
||||
new LiveReloadPlugin()
|
||||
],
|
||||
|
||||
resolveLoader: {
|
||||
modules: [
|
||||
'node_modules',
|
||||
'frontend/build/webpack/'
|
||||
]
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.worker\.js$/,
|
||||
use: {
|
||||
loader: 'worker-loader',
|
||||
options: {
|
||||
filename: '[name].js',
|
||||
inline: inlineWebWorkers
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: [/\.jsx?$/, /\.tsx?$/],
|
||||
exclude: /(node_modules|JsLibraries)/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
configFile: `${frontendFolder}/babel.config.js`,
|
||||
envName: isProduction ? 'production' : 'development',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false,
|
||||
loose: true,
|
||||
debug: false,
|
||||
useBuiltIns: 'entry',
|
||||
corejs: '3.41'
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// CSS Modules
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /(node_modules|globals.css)/,
|
||||
use: [
|
||||
{ loader: MiniCssExtractPlugin.loader },
|
||||
{ loader: 'css-modules-typescript-loader' },
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
modules: {
|
||||
localIdentName: isProduction ? '[name]/[local]/[hash:base64:5]' : '[name]/[local]'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
postcssOptions: {
|
||||
config: 'frontend/postcss.config.js'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Global styles
|
||||
{
|
||||
test: /\.css$/,
|
||||
include: /(node_modules|globals.css)/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Fonts
|
||||
{
|
||||
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10240,
|
||||
mimetype: 'application/font-woff',
|
||||
emitFile: false,
|
||||
name: 'Content/Fonts/[name].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
emitFile: false,
|
||||
name: 'Content/Fonts/[name].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
if (isProfiling) {
|
||||
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
|
||||
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
|
||||
|
||||
config.optimization = {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
sourceMap: true, // Must be set to true if using source-maps in production
|
||||
mangle: false,
|
||||
keep_classnames: true,
|
||||
keep_fnames: true
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
17
frontend/gulp/build.js
Normal file
17
frontend/gulp/build.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const gulp = require('gulp');
|
||||
|
||||
require('./clean');
|
||||
require('./copy');
|
||||
require('./webpack');
|
||||
|
||||
gulp.task('build',
|
||||
gulp.series('clean',
|
||||
gulp.parallel(
|
||||
'webpack',
|
||||
'copyHtml',
|
||||
'copyFonts',
|
||||
'copyImages',
|
||||
'copyJs'
|
||||
)
|
||||
)
|
||||
);
|
8
frontend/gulp/clean.js
Normal file
8
frontend/gulp/clean.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
const gulp = require('gulp');
|
||||
const del = require('del');
|
||||
|
||||
const paths = require('./helpers/paths');
|
||||
|
||||
gulp.task('clean', () => {
|
||||
return del([paths.dest.root]);
|
||||
});
|
45
frontend/gulp/copy.js
Normal file
45
frontend/gulp/copy.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const path = require('path');
|
||||
const gulp = require('gulp');
|
||||
const print = require('gulp-print').default;
|
||||
const cache = require('gulp-cached');
|
||||
const livereload = require('gulp-livereload');
|
||||
const paths = require('./helpers/paths.js');
|
||||
|
||||
gulp.task('copyJs', () => {
|
||||
return gulp.src(
|
||||
[
|
||||
path.join(paths.src.root, 'polyfills.js')
|
||||
], { base: paths.src.root })
|
||||
.pipe(cache('copyJs'))
|
||||
.pipe(print())
|
||||
.pipe(gulp.dest(paths.dest.root))
|
||||
.pipe(livereload());
|
||||
});
|
||||
|
||||
gulp.task('copyHtml', () => {
|
||||
return gulp.src(paths.src.html, { base: paths.src.root })
|
||||
.pipe(cache('copyHtml'))
|
||||
.pipe(print())
|
||||
.pipe(gulp.dest(paths.dest.root))
|
||||
.pipe(livereload());
|
||||
});
|
||||
|
||||
gulp.task('copyFonts', () => {
|
||||
return gulp.src(
|
||||
path.join(paths.src.fonts, '**', '*.*'), { base: paths.src.root }
|
||||
)
|
||||
.pipe(cache('copyFonts'))
|
||||
.pipe(print())
|
||||
.pipe(gulp.dest(paths.dest.root))
|
||||
.pipe(livereload());
|
||||
});
|
||||
|
||||
gulp.task('copyImages', () => {
|
||||
return gulp.src(
|
||||
path.join(paths.src.images, '**', '*.*'), { base: paths.src.root }
|
||||
)
|
||||
.pipe(cache('copyImages'))
|
||||
.pipe(print())
|
||||
.pipe(gulp.dest(paths.dest.root))
|
||||
.pipe(livereload());
|
||||
});
|
5
frontend/gulp/gulpFile.js
Normal file
5
frontend/gulp/gulpFile.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
require('./build.js');
|
||||
require('./clean.js');
|
||||
require('./copy.js');
|
||||
require('./watch.js');
|
||||
require('./webpack.js');
|
6
frontend/gulp/helpers/errorHandler.js
Normal file
6
frontend/gulp/helpers/errorHandler.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
const colors = require('ansi-colors');
|
||||
|
||||
module.exports = function errorHandler(error) {
|
||||
console.log(colors.red(`Error (${error.plugin}): ${error.message}`));
|
||||
this.emit('end');
|
||||
};
|
23
frontend/gulp/helpers/paths.js
Normal file
23
frontend/gulp/helpers/paths.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const root = './frontend/src';
|
||||
|
||||
const paths = {
|
||||
src: {
|
||||
root,
|
||||
html: `${root}/*.html`,
|
||||
scripts: `${root}/**/*.js`,
|
||||
content: `${root}/Content/`,
|
||||
fonts: `${root}/Content/Fonts/`,
|
||||
images: `${root}/Content/Images/`,
|
||||
exclude: {
|
||||
libs: `!${root}/JsLibraries/**`
|
||||
}
|
||||
},
|
||||
dest: {
|
||||
root: './_output/UI/',
|
||||
content: './_output/UI/Content/',
|
||||
fonts: './_output/UI/Content/Fonts/',
|
||||
images: './_output/UI/Content/Images/'
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = paths;
|
18
frontend/gulp/watch.js
Normal file
18
frontend/gulp/watch.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const gulp = require('gulp');
|
||||
const livereload = require('gulp-livereload');
|
||||
const gulpWatch = require('gulp-watch');
|
||||
const paths = require('./helpers/paths.js');
|
||||
|
||||
require('./copy.js');
|
||||
require('./webpack.js');
|
||||
|
||||
function watch() {
|
||||
livereload.listen({ start: true });
|
||||
|
||||
gulp.task('webpackWatch')();
|
||||
gulpWatch(paths.src.html, gulp.series('copyHtml'));
|
||||
gulpWatch(`${paths.src.fonts}**/*.*`, gulp.series('copyFonts'));
|
||||
gulpWatch(`${paths.src.images}**/*.*`, gulp.series('copyImages'));
|
||||
}
|
||||
|
||||
gulp.task('watch', gulp.series('build', watch));
|
201
frontend/gulp/webpack.js
Normal file
201
frontend/gulp/webpack.js
Normal file
|
@ -0,0 +1,201 @@
|
|||
const gulp = require('gulp');
|
||||
const webpackStream = require('webpack-stream');
|
||||
const livereload = require('gulp-livereload');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const errorHandler = require('./helpers/errorHandler');
|
||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const browsers = require('../browsers');
|
||||
|
||||
const uiFolder = 'UI';
|
||||
const frontendFolder = path.join(__dirname, '..');
|
||||
const srcFolder = path.join(frontendFolder, 'src');
|
||||
const isProduction = process.argv.indexOf('--production') > -1;
|
||||
|
||||
console.log('Source Folder:', srcFolder);
|
||||
console.log('isProduction:', isProduction);
|
||||
|
||||
const cssVarsFiles = [
|
||||
'../src/Styles/Variables/colors',
|
||||
'../src/Styles/Variables/dimensions',
|
||||
'../src/Styles/Variables/fonts',
|
||||
'../src/Styles/Variables/animations'
|
||||
].map(require.resolve);
|
||||
|
||||
const plugins = [
|
||||
new OptimizeCssAssetsPlugin({}),
|
||||
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: !isProduction,
|
||||
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
|
||||
}),
|
||||
|
||||
new MiniCssExtractPlugin({
|
||||
filename: path.join('_output', uiFolder, 'Content', 'styles.css')
|
||||
})
|
||||
];
|
||||
|
||||
const config = {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
devtool: '#source-map',
|
||||
|
||||
stats: {
|
||||
children: false
|
||||
},
|
||||
|
||||
watchOptions: {
|
||||
ignored: /node_modules/
|
||||
},
|
||||
|
||||
entry: {
|
||||
preload: 'preload.js',
|
||||
vendor: 'vendor.js',
|
||||
index: 'index.js'
|
||||
},
|
||||
|
||||
resolve: {
|
||||
modules: [
|
||||
srcFolder,
|
||||
path.join(srcFolder, 'Shims'),
|
||||
'node_modules'
|
||||
],
|
||||
alias: {
|
||||
jquery: 'jquery/src/jquery'
|
||||
}
|
||||
},
|
||||
|
||||
output: {
|
||||
filename: path.join('_output', uiFolder, '[name].js'),
|
||||
sourceMapFilename: '[file].map'
|
||||
},
|
||||
|
||||
optimization: {
|
||||
chunkIds: 'named'
|
||||
},
|
||||
|
||||
plugins,
|
||||
|
||||
resolveLoader: {
|
||||
modules: [
|
||||
'node_modules',
|
||||
'frontend/gulp/webpack/'
|
||||
]
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js?$/,
|
||||
exclude: /(node_modules|JsLibraries)/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
configFile: `${frontendFolder}/babel.config.js`,
|
||||
envName: isProduction ? 'production' : 'development',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false,
|
||||
loose: true,
|
||||
debug: false,
|
||||
useBuiltIns: 'entry',
|
||||
targets: browsers
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// CSS Modules
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /(node_modules|globals.css)/,
|
||||
use: [
|
||||
{ loader: MiniCssExtractPlugin.loader },
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
localIdentName: '[name]/[local]/[hash:base64:5]',
|
||||
modules: true
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
ident: 'postcss',
|
||||
config: {
|
||||
ctx: {
|
||||
cssVarsFiles
|
||||
},
|
||||
path: 'frontend/postcss.config.js'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Global styles
|
||||
{
|
||||
test: /\.css$/,
|
||||
include: /(node_modules|globals.css)/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Fonts
|
||||
{
|
||||
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10240,
|
||||
mimetype: 'application/font-woff',
|
||||
emitFile: false,
|
||||
name: 'Content/Fonts/[name].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
emitFile: false,
|
||||
name: 'Content/Fonts/[name].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
gulp.task('webpack', () => {
|
||||
return webpackStream(config, webpack)
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
gulp.task('webpackWatch', () => {
|
||||
config.watch = true;
|
||||
|
||||
return webpackStream(config, webpack)
|
||||
.on('error', errorHandler)
|
||||
.pipe(gulp.dest('./'))
|
||||
.on('error', errorHandler)
|
||||
.pipe(livereload())
|
||||
.on('error', errorHandler);
|
||||
});
|
|
@ -1,4 +1,3 @@
|
|||
// eslint-disable-next-line filenames/match-exported
|
||||
const loaderUtils = require('loader-utils');
|
||||
|
||||
module.exports = function cssVariablesLoader(source) {
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"checkJs": false,
|
||||
"baseUrl": "src",
|
||||
"jsx": "react",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"*": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
]
|
||||
}
|
|
@ -1,32 +1,27 @@
|
|||
const reload = require('require-nocache')(module);
|
||||
const browsers = require('./browsers');
|
||||
|
||||
const cssVarsFiles = [
|
||||
'./src/Styles/Variables/dimensions',
|
||||
'./src/Styles/Variables/fonts',
|
||||
'./src/Styles/Variables/animations',
|
||||
'./src/Styles/Variables/zIndexes'
|
||||
].map(require.resolve);
|
||||
module.exports = (ctx, configPath, options) => {
|
||||
const config = {
|
||||
plugins: {
|
||||
'postcss-mixins': {
|
||||
mixinsDir: [
|
||||
'frontend/src/Styles/Mixins'
|
||||
]
|
||||
},
|
||||
'postcss-simple-vars': {
|
||||
variables: () =>
|
||||
ctx.options.cssVarsFiles.reduce((acc, vars) => {
|
||||
return Object.assign(acc, reload(vars));
|
||||
}, {})
|
||||
},
|
||||
'postcss-color-function': {},
|
||||
'postcss-nested': {},
|
||||
autoprefixer: {
|
||||
browsers
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const mixinsFiles = [
|
||||
'frontend/src/Styles/Mixins/cover.css',
|
||||
'frontend/src/Styles/Mixins/linkOverlay.css',
|
||||
'frontend/src/Styles/Mixins/scroller.css',
|
||||
'frontend/src/Styles/Mixins/truncate.css'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'autoprefixer',
|
||||
['postcss-mixins', {
|
||||
mixinsFiles
|
||||
}],
|
||||
['postcss-simple-vars', {
|
||||
variables: () =>
|
||||
cssVarsFiles.reduce((acc, vars) => {
|
||||
return Object.assign(acc, reload(vars));
|
||||
}, {})
|
||||
}],
|
||||
'postcss-color-function',
|
||||
'postcss-nested'
|
||||
]
|
||||
return config;
|
||||
};
|
||||
|
|
4
frontend/src/.vscode/settings.json
vendored
Normal file
4
frontend/src/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.insertFinalNewline": true
|
||||
}
|
123
frontend/src/Activity/Blacklist/Blacklist.js
Normal file
123
frontend/src/Activity/Blacklist/Blacklist.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import TablePager from 'Components/Table/TablePager';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import BlacklistRowConnector from './BlacklistRowConnector';
|
||||
|
||||
class Blacklist extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items,
|
||||
columns,
|
||||
totalRecords,
|
||||
isClearingBlacklistExecuting,
|
||||
onClearBlacklistPress,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<PageContent title="Blacklist">
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Clear"
|
||||
iconName={icons.CLEAR}
|
||||
isSpinning={isClearingBlacklistExecuting}
|
||||
onPress={onClearBlacklistPress}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
<TableOptionsModalWrapper
|
||||
{...otherProps}
|
||||
columns={columns}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
</PageToolbarSection>
|
||||
</PageToolbar>
|
||||
|
||||
<PageContentBodyConnector>
|
||||
{
|
||||
isFetching && !isPopulated &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to load blacklist</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !error && !items.length &&
|
||||
<div>
|
||||
No history blacklist
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !error && !!items.length &&
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
{...otherProps}
|
||||
>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<BlacklistRowConnector
|
||||
key={item.id}
|
||||
columns={columns}
|
||||
{...item}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<TablePager
|
||||
totalRecords={totalRecords}
|
||||
isFetching={isFetching}
|
||||
{...otherProps}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</PageContentBodyConnector>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Blacklist.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
totalRecords: PropTypes.number,
|
||||
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
|
||||
onClearBlacklistPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default Blacklist;
|
154
frontend/src/Activity/Blacklist/BlacklistConnector.js
Normal file
154
frontend/src/Activity/Blacklist/BlacklistConnector.js
Normal file
|
@ -0,0 +1,154 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import * as blacklistActions from 'Store/Actions/blacklistActions';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import Blacklist from './Blacklist';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.blacklist,
|
||||
createCommandExecutingSelector(commandNames.CLEAR_BLACKLIST),
|
||||
(blacklist, isClearingBlacklistExecuting) => {
|
||||
return {
|
||||
isClearingBlacklistExecuting,
|
||||
...blacklist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
...blacklistActions,
|
||||
executeCommand
|
||||
};
|
||||
|
||||
class BlacklistConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
useCurrentPage,
|
||||
fetchBlacklist,
|
||||
gotoBlacklistFirstPage
|
||||
} = this.props;
|
||||
|
||||
registerPagePopulator(this.repopulate);
|
||||
|
||||
if (useCurrentPage) {
|
||||
fetchBlacklist();
|
||||
} else {
|
||||
gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.isClearingBlacklistExecuting && !this.props.isClearingBlacklistExecuting) {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.clearBlacklist();
|
||||
unregisterPagePopulator(this.repopulate);
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
repopulate = () => {
|
||||
this.props.fetchBlacklist();
|
||||
}
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onFirstPagePress = () => {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
|
||||
onPreviousPagePress = () => {
|
||||
this.props.gotoBlacklistPreviousPage();
|
||||
}
|
||||
|
||||
onNextPagePress = () => {
|
||||
this.props.gotoBlacklistNextPage();
|
||||
}
|
||||
|
||||
onLastPagePress = () => {
|
||||
this.props.gotoBlacklistLastPage();
|
||||
}
|
||||
|
||||
onPageSelect = (page) => {
|
||||
this.props.gotoBlacklistPage({ page });
|
||||
}
|
||||
|
||||
onSortPress = (sortKey) => {
|
||||
this.props.setBlacklistSort({ sortKey });
|
||||
}
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setBlacklistTableOption(payload);
|
||||
|
||||
if (payload.pageSize) {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
onClearBlacklistPress = () => {
|
||||
this.props.executeCommand({ name: commandNames.CLEAR_BLACKLIST });
|
||||
}
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setBlacklistTableOption(payload);
|
||||
|
||||
if (payload.pageSize) {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Blacklist
|
||||
onFirstPagePress={this.onFirstPagePress}
|
||||
onPreviousPagePress={this.onPreviousPagePress}
|
||||
onNextPagePress={this.onNextPagePress}
|
||||
onLastPagePress={this.onLastPagePress}
|
||||
onPageSelect={this.onPageSelect}
|
||||
onSortPress={this.onSortPress}
|
||||
onTableOptionChange={this.onTableOptionChange}
|
||||
onClearBlacklistPress={this.onClearBlacklistPress}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BlacklistConnector.propTypes = {
|
||||
useCurrentPage: PropTypes.bool.isRequired,
|
||||
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fetchBlacklist: PropTypes.func.isRequired,
|
||||
gotoBlacklistFirstPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistPreviousPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistNextPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistLastPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistPage: PropTypes.func.isRequired,
|
||||
setBlacklistSort: PropTypes.func.isRequired,
|
||||
setBlacklistTableOption: PropTypes.func.isRequired,
|
||||
clearBlacklist: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default withCurrentPage(
|
||||
connect(createMapStateToProps, mapDispatchToProps)(BlacklistConnector)
|
||||
);
|
89
frontend/src/Activity/Blacklist/BlacklistDetailsModal.js
Normal file
89
frontend/src/Activity/Blacklist/BlacklistDetailsModal.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Button from 'Components/Link/Button';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
|
||||
class BlacklistDetailsModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
sourceTitle,
|
||||
protocol,
|
||||
indexer,
|
||||
message,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<ModalContent
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<ModalHeader>
|
||||
Details
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Protocol"
|
||||
data={protocol}
|
||||
/>
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title="Indexer"
|
||||
data={indexer}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title="Message"
|
||||
data={message}
|
||||
/>
|
||||
}
|
||||
</DescriptionList>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BlacklistDetailsModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
indexer: PropTypes.string,
|
||||
message: PropTypes.string,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default BlacklistDetailsModal;
|
18
frontend/src/Activity/Blacklist/BlacklistRow.css
Normal file
18
frontend/src/Activity/Blacklist/BlacklistRow.css
Normal file
|
@ -0,0 +1,18 @@
|
|||
.language,
|
||||
.quality {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.indexer {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 70px;
|
||||
}
|
185
frontend/src/Activity/Blacklist/BlacklistRow.js
Normal file
185
frontend/src/Activity/Blacklist/BlacklistRow.js
Normal file
|
@ -0,0 +1,185 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TrackLanguage from 'Album/TrackLanguage';
|
||||
import TrackQuality from 'Album/TrackQuality';
|
||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
||||
import BlacklistDetailsModal from './BlacklistDetailsModal';
|
||||
import styles from './BlacklistRow.css';
|
||||
|
||||
class BlacklistRow extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isDetailsModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onDetailsPress = () => {
|
||||
this.setState({ isDetailsModalOpen: true });
|
||||
}
|
||||
|
||||
onDetailsModalClose = () => {
|
||||
this.setState({ isDetailsModalOpen: false });
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
artist,
|
||||
sourceTitle,
|
||||
language,
|
||||
quality,
|
||||
date,
|
||||
protocol,
|
||||
indexer,
|
||||
message,
|
||||
columns,
|
||||
onRemovePress
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
{
|
||||
columns.map((column) => {
|
||||
const {
|
||||
name,
|
||||
isVisible
|
||||
} = column;
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name === 'artist.sortName') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
<ArtistNameLink
|
||||
foreignArtistId={artist.foreignArtistId}
|
||||
artistName={artist.artistName}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'sourceTitle') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
{sourceTitle}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'language') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.language}
|
||||
>
|
||||
<TrackLanguage
|
||||
language={language}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'quality') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.quality}
|
||||
>
|
||||
<TrackQuality
|
||||
quality={quality}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'date') {
|
||||
return (
|
||||
<RelativeDateCellConnector
|
||||
key={name}
|
||||
date={date}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'indexer') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.indexer}
|
||||
>
|
||||
{indexer}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'actions') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.actions}
|
||||
>
|
||||
<IconButton
|
||||
name={icons.INFO}
|
||||
onPress={this.onDetailsPress}
|
||||
/>
|
||||
<IconButton
|
||||
title="Remove from blacklist"
|
||||
name={icons.REMOVE}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onRemovePress}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
}
|
||||
|
||||
<BlacklistDetailsModal
|
||||
isOpen={this.state.isDetailsModalOpen}
|
||||
sourceTitle={sourceTitle}
|
||||
protocol={protocol}
|
||||
indexer={indexer}
|
||||
message={message}
|
||||
onModalClose={this.onDetailsModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BlacklistRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
artist: PropTypes.object.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
language: PropTypes.object.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
date: PropTypes.string.isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
indexer: PropTypes.string,
|
||||
message: PropTypes.string,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onRemovePress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default BlacklistRow;
|
26
frontend/src/Activity/Blacklist/BlacklistRowConnector.js
Normal file
26
frontend/src/Activity/Blacklist/BlacklistRowConnector.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||
import { removeFromBlacklist } from 'Store/Actions/blacklistActions';
|
||||
import BlacklistRow from './BlacklistRow';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createArtistSelector(),
|
||||
(artist) => {
|
||||
return {
|
||||
artist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onRemovePress() {
|
||||
dispatch(removeFromBlacklist({ id: props.id }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(BlacklistRow);
|
|
@ -1,268 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import TablePager from 'Components/Table/TablePager';
|
||||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import getRemovedItems from 'Utilities/Object/getRemovedItems';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
import BlocklistRowConnector from './BlocklistRowConnector';
|
||||
|
||||
class Blocklist extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
allSelected: false,
|
||||
allUnselected: false,
|
||||
lastToggled: null,
|
||||
selectedState: {},
|
||||
isConfirmRemoveModalOpen: false,
|
||||
isConfirmClearModalOpen: false,
|
||||
items: props.items
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
items
|
||||
} = this.props;
|
||||
|
||||
if (hasDifferentItems(prevProps.items, items)) {
|
||||
this.setState((state) => {
|
||||
return {
|
||||
...removeOldSelectedState(state, getRemovedItems(prevProps.items, items)),
|
||||
items
|
||||
};
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
getSelectedIds = () => {
|
||||
return getSelectedIds(this.state.selectedState);
|
||||
};
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onSelectAllChange = ({ value }) => {
|
||||
this.setState(selectAll(this.state.selectedState, value));
|
||||
};
|
||||
|
||||
onSelectedChange = ({ id, value, shiftKey = false }) => {
|
||||
this.setState((state) => {
|
||||
return toggleSelected(state, this.props.items, id, value, shiftKey);
|
||||
});
|
||||
};
|
||||
|
||||
onRemoveSelectedPress = () => {
|
||||
this.setState({ isConfirmRemoveModalOpen: true });
|
||||
};
|
||||
|
||||
onRemoveSelectedConfirmed = () => {
|
||||
this.props.onRemoveSelected(this.getSelectedIds());
|
||||
this.setState({ isConfirmRemoveModalOpen: false });
|
||||
};
|
||||
|
||||
onConfirmRemoveModalClose = () => {
|
||||
this.setState({ isConfirmRemoveModalOpen: false });
|
||||
};
|
||||
|
||||
onClearBlocklistPress = () => {
|
||||
this.setState({ isConfirmClearModalOpen: true });
|
||||
};
|
||||
|
||||
onClearBlocklistConfirmed = () => {
|
||||
this.props.onClearBlocklistPress();
|
||||
this.setState({ isConfirmClearModalOpen: false });
|
||||
};
|
||||
|
||||
onConfirmClearModalClose = () => {
|
||||
this.setState({ isConfirmClearModalOpen: false });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
isArtistFetching,
|
||||
isArtistPopulated,
|
||||
error,
|
||||
items,
|
||||
columns,
|
||||
totalRecords,
|
||||
isRemoving,
|
||||
isClearingBlocklistExecuting,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const isAllPopulated = isPopulated && isArtistPopulated;
|
||||
const isAnyFetching = isFetching || isArtistFetching;
|
||||
|
||||
const {
|
||||
allSelected,
|
||||
allUnselected,
|
||||
selectedState,
|
||||
isConfirmRemoveModalOpen,
|
||||
isConfirmClearModalOpen
|
||||
} = this.state;
|
||||
|
||||
const selectedIds = this.getSelectedIds();
|
||||
|
||||
return (
|
||||
<PageContent title={translate('Blocklist')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label={translate('RemoveSelected')}
|
||||
iconName={icons.REMOVE}
|
||||
isDisabled={!selectedIds.length}
|
||||
isSpinning={isRemoving}
|
||||
onPress={this.onRemoveSelectedPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('Clear')}
|
||||
iconName={icons.CLEAR}
|
||||
isDisabled={!items.length}
|
||||
isSpinning={isClearingBlocklistExecuting}
|
||||
onPress={this.onClearBlocklistPress}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
<TableOptionsModalWrapper
|
||||
{...otherProps}
|
||||
columns={columns}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label={translate('Options')}
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
</PageToolbarSection>
|
||||
</PageToolbar>
|
||||
|
||||
<PageContentBody>
|
||||
{
|
||||
isAnyFetching && !isAllPopulated &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isAnyFetching && !!error &&
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadBlocklist')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
isAllPopulated && !error && !items.length &&
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('NoHistoryBlocklist')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
isAllPopulated && !error && !!items.length &&
|
||||
<div>
|
||||
<Table
|
||||
selectAll={true}
|
||||
allSelected={allSelected}
|
||||
allUnselected={allUnselected}
|
||||
columns={columns}
|
||||
{...otherProps}
|
||||
onSelectAllChange={this.onSelectAllChange}
|
||||
>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<BlocklistRowConnector
|
||||
key={item.id}
|
||||
isSelected={selectedState[item.id] || false}
|
||||
columns={columns}
|
||||
{...item}
|
||||
onSelectedChange={this.onSelectedChange}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<TablePager
|
||||
totalRecords={totalRecords}
|
||||
isFetching={isFetching}
|
||||
{...otherProps}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</PageContentBody>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isConfirmRemoveModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('RemoveSelected')}
|
||||
message={translate('RemoveSelectedItemBlocklistMessageText')}
|
||||
confirmLabel={translate('RemoveSelected')}
|
||||
onConfirm={this.onRemoveSelectedConfirmed}
|
||||
onCancel={this.onConfirmRemoveModalClose}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isConfirmClearModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('ClearBlocklist')}
|
||||
message={translate('ClearBlocklistMessageText')}
|
||||
confirmLabel={translate('Clear')}
|
||||
onConfirm={this.onClearBlocklistConfirmed}
|
||||
onCancel={this.onConfirmClearModalClose}
|
||||
/>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Blocklist.propTypes = {
|
||||
isArtistFetching: PropTypes.bool.isRequired,
|
||||
isArtistPopulated: PropTypes.bool.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
totalRecords: PropTypes.number,
|
||||
isRemoving: PropTypes.bool.isRequired,
|
||||
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
|
||||
onRemoveSelected: PropTypes.func.isRequired,
|
||||
onClearBlocklistPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default Blocklist;
|
|
@ -1,155 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import * as blocklistActions from 'Store/Actions/blocklistActions';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
import Blocklist from './Blocklist';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.blocklist,
|
||||
(state) => state.artist,
|
||||
createCommandExecutingSelector(commandNames.CLEAR_BLOCKLIST),
|
||||
(blocklist, artist, isClearingBlocklistExecuting) => {
|
||||
return {
|
||||
isArtistFetching: artist.isFetching,
|
||||
isArtistPopulated: artist.isPopulated,
|
||||
isClearingBlocklistExecuting,
|
||||
...blocklist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
...blocklistActions,
|
||||
executeCommand
|
||||
};
|
||||
|
||||
class BlocklistConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
useCurrentPage,
|
||||
fetchBlocklist,
|
||||
gotoBlocklistFirstPage
|
||||
} = this.props;
|
||||
|
||||
registerPagePopulator(this.repopulate);
|
||||
|
||||
if (useCurrentPage) {
|
||||
fetchBlocklist();
|
||||
} else {
|
||||
gotoBlocklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.isClearingBlocklistExecuting && !this.props.isClearingBlocklistExecuting) {
|
||||
this.props.gotoBlocklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.clearBlocklist();
|
||||
unregisterPagePopulator(this.repopulate);
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
repopulate = () => {
|
||||
this.props.fetchBlocklist();
|
||||
};
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onFirstPagePress = () => {
|
||||
this.props.gotoBlocklistFirstPage();
|
||||
};
|
||||
|
||||
onPreviousPagePress = () => {
|
||||
this.props.gotoBlocklistPreviousPage();
|
||||
};
|
||||
|
||||
onNextPagePress = () => {
|
||||
this.props.gotoBlocklistNextPage();
|
||||
};
|
||||
|
||||
onLastPagePress = () => {
|
||||
this.props.gotoBlocklistLastPage();
|
||||
};
|
||||
|
||||
onPageSelect = (page) => {
|
||||
this.props.gotoBlocklistPage({ page });
|
||||
};
|
||||
|
||||
onRemoveSelected = (ids) => {
|
||||
this.props.removeBlocklistItems({ ids });
|
||||
};
|
||||
|
||||
onSortPress = (sortKey) => {
|
||||
this.props.setBlocklistSort({ sortKey });
|
||||
};
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setBlocklistTableOption(payload);
|
||||
|
||||
if (payload.pageSize) {
|
||||
this.props.gotoBlocklistFirstPage();
|
||||
}
|
||||
};
|
||||
|
||||
onClearBlocklistPress = () => {
|
||||
this.props.executeCommand({ name: commandNames.CLEAR_BLOCKLIST });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Blocklist
|
||||
onFirstPagePress={this.onFirstPagePress}
|
||||
onPreviousPagePress={this.onPreviousPagePress}
|
||||
onNextPagePress={this.onNextPagePress}
|
||||
onLastPagePress={this.onLastPagePress}
|
||||
onPageSelect={this.onPageSelect}
|
||||
onRemoveSelected={this.onRemoveSelected}
|
||||
onSortPress={this.onSortPress}
|
||||
onTableOptionChange={this.onTableOptionChange}
|
||||
onClearBlocklistPress={this.onClearBlocklistPress}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BlocklistConnector.propTypes = {
|
||||
useCurrentPage: PropTypes.bool.isRequired,
|
||||
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fetchBlocklist: PropTypes.func.isRequired,
|
||||
gotoBlocklistFirstPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistPreviousPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistNextPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistLastPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistPage: PropTypes.func.isRequired,
|
||||
removeBlocklistItems: PropTypes.func.isRequired,
|
||||
setBlocklistSort: PropTypes.func.isRequired,
|
||||
setBlocklistTableOption: PropTypes.func.isRequired,
|
||||
clearBlocklist: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default withCurrentPage(
|
||||
connect(createMapStateToProps, mapDispatchToProps)(BlocklistConnector)
|
||||
);
|
|
@ -1,90 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import Button from 'Components/Link/Button';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class BlocklistDetailsModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
sourceTitle,
|
||||
protocol,
|
||||
indexer,
|
||||
message,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<ModalContent
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<ModalHeader>
|
||||
Details
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title={translate('Protocol')}
|
||||
data={protocol}
|
||||
/>
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title={translate('Indexer')}
|
||||
data={indexer}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title={translate('Message')}
|
||||
data={message}
|
||||
/>
|
||||
}
|
||||
</DescriptionList>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BlocklistDetailsModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
indexer: PropTypes.string,
|
||||
message: PropTypes.string,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default BlocklistDetailsModal;
|
|
@ -1,17 +0,0 @@
|
|||
.quality {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.indexer {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 70px;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'actions': string;
|
||||
'indexer': string;
|
||||
'quality': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
|
@ -1,200 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import AlbumFormats from 'Album/AlbumFormats';
|
||||
import TrackQuality from 'Album/TrackQuality';
|
||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BlocklistDetailsModal from './BlocklistDetailsModal';
|
||||
import styles from './BlocklistRow.css';
|
||||
|
||||
class BlocklistRow extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isDetailsModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onDetailsPress = () => {
|
||||
this.setState({ isDetailsModalOpen: true });
|
||||
};
|
||||
|
||||
onDetailsModalClose = () => {
|
||||
this.setState({ isDetailsModalOpen: false });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
artist,
|
||||
sourceTitle,
|
||||
quality,
|
||||
customFormats,
|
||||
date,
|
||||
protocol,
|
||||
indexer,
|
||||
message,
|
||||
isSelected,
|
||||
columns,
|
||||
onSelectedChange,
|
||||
onRemovePress
|
||||
} = this.props;
|
||||
|
||||
if (!artist) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableSelectCell
|
||||
id={id}
|
||||
isSelected={isSelected}
|
||||
onSelectedChange={onSelectedChange}
|
||||
/>
|
||||
|
||||
{
|
||||
columns.map((column) => {
|
||||
const {
|
||||
name,
|
||||
isVisible
|
||||
} = column;
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name === 'artists.sortName') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
<ArtistNameLink
|
||||
foreignArtistId={artist.foreignArtistId}
|
||||
artistName={artist.artistName}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'sourceTitle') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
{sourceTitle}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'quality') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.quality}
|
||||
>
|
||||
<TrackQuality
|
||||
quality={quality}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'customFormats') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
<AlbumFormats
|
||||
formats={customFormats}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'date') {
|
||||
return (
|
||||
<RelativeDateCellConnector
|
||||
key={name}
|
||||
date={date}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'indexer') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.indexer}
|
||||
>
|
||||
{indexer}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'actions') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
className={styles.actions}
|
||||
>
|
||||
<IconButton
|
||||
name={icons.INFO}
|
||||
onPress={this.onDetailsPress}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
title={translate('RemoveFromBlocklist')}
|
||||
name={icons.REMOVE}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onRemovePress}
|
||||
/>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
}
|
||||
|
||||
<BlocklistDetailsModal
|
||||
isOpen={this.state.isDetailsModalOpen}
|
||||
sourceTitle={sourceTitle}
|
||||
protocol={protocol}
|
||||
indexer={indexer}
|
||||
message={message}
|
||||
onModalClose={this.onDetailsModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BlocklistRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
artist: PropTypes.object.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
date: PropTypes.string.isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
indexer: PropTypes.string,
|
||||
message: PropTypes.string,
|
||||
isSelected: PropTypes.bool.isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onSelectedChange: PropTypes.func.isRequired,
|
||||
onRemovePress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default BlocklistRow;
|
|
@ -1,26 +0,0 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { removeBlocklistItem } from 'Store/Actions/blocklistActions';
|
||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||
import BlocklistRow from './BlocklistRow';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createArtistSelector(),
|
||||
(artist) => {
|
||||
return {
|
||||
artist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onRemovePress() {
|
||||
dispatch(removeBlocklistItem({ id: props.id }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(BlocklistRow);
|
|
@ -1,7 +0,0 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'description': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
|
@ -1,16 +1,14 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription';
|
||||
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
|
||||
import Icon from 'Components/Icon';
|
||||
import Link from 'Components/Link/Link';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import formatAge from 'Utilities/Number/formatAge';
|
||||
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import Link from 'Components/Link/Link';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
|
||||
import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import Icon from 'Components/Icon';
|
||||
import styles from './HistoryDetails.css';
|
||||
|
||||
function getDetailedList(statusMessages) {
|
||||
|
@ -49,9 +47,7 @@ function formatMissing(value) {
|
|||
|
||||
function formatChange(oldValue, newValue) {
|
||||
return (
|
||||
<div>
|
||||
{formatMissing(oldValue)} <Icon name={icons.ARROW_RIGHT_NO_CIRCLE} size={12} /> {formatMissing(newValue)}
|
||||
</div>
|
||||
<div> {formatMissing(oldValue)} <Icon name={icons.ARROW_RIGHT_NO_CIRCLE} size={12} /> {formatMissing(newValue)} </div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -60,7 +56,6 @@ function HistoryDetails(props) {
|
|||
eventType,
|
||||
sourceTitle,
|
||||
data,
|
||||
downloadId,
|
||||
shortDateFormat,
|
||||
timeFormat
|
||||
} = props;
|
||||
|
@ -69,102 +64,83 @@ function HistoryDetails(props) {
|
|||
const {
|
||||
indexer,
|
||||
releaseGroup,
|
||||
customFormatScore,
|
||||
nzbInfoUrl,
|
||||
downloadClient,
|
||||
downloadClientName,
|
||||
downloadId,
|
||||
age,
|
||||
ageHours,
|
||||
ageMinutes,
|
||||
publishedDate
|
||||
} = data;
|
||||
|
||||
const downloadClientNameInfo = downloadClientName ?? downloadClient;
|
||||
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
indexer ?
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title={translate('Indexer')}
|
||||
title="Indexer"
|
||||
data={indexer}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
releaseGroup ?
|
||||
!!releaseGroup &&
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('ReleaseGroup')}
|
||||
title="Release Group"
|
||||
data={releaseGroup}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
customFormatScore && customFormatScore !== '0' ?
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(customFormatScore)}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
nzbInfoUrl ?
|
||||
!!nzbInfoUrl &&
|
||||
<span>
|
||||
<DescriptionListItemTitle>
|
||||
{translate('InfoUrl')}
|
||||
Info URL
|
||||
</DescriptionListItemTitle>
|
||||
|
||||
<DescriptionListItemDescription>
|
||||
<Link to={nzbInfoUrl}>{nzbInfoUrl}</Link>
|
||||
</DescriptionListItemDescription>
|
||||
</span> :
|
||||
null
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
downloadClientNameInfo ?
|
||||
!!downloadClient &&
|
||||
<DescriptionListItem
|
||||
title={translate('DownloadClient')}
|
||||
data={downloadClientNameInfo}
|
||||
/> :
|
||||
null
|
||||
title="Download Client"
|
||||
data={downloadClient}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
downloadId ?
|
||||
!!downloadId &&
|
||||
<DescriptionListItem
|
||||
title={translate('GrabId')}
|
||||
title="Grab ID"
|
||||
data={downloadId}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
age || ageHours || ageMinutes ?
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title={translate('AgeWhenGrabbed')}
|
||||
title="Age (when grabbed)"
|
||||
data={formatAge(age, ageHours, ageMinutes)}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
publishedDate ?
|
||||
!!publishedDate &&
|
||||
<DescriptionListItem
|
||||
title={translate('PublishedDate')}
|
||||
title="Published Date"
|
||||
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
|
@ -172,42 +148,23 @@ function HistoryDetails(props) {
|
|||
|
||||
if (eventType === 'downloadFailed') {
|
||||
const {
|
||||
message,
|
||||
indexer
|
||||
message
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
downloadId ?
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title={translate('GrabId')}
|
||||
data={downloadId}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
indexer ? (
|
||||
<DescriptionListItem
|
||||
title={translate('Indexer')}
|
||||
data={indexer}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{
|
||||
message ?
|
||||
<DescriptionListItem
|
||||
title={translate('Message')}
|
||||
title="Message"
|
||||
data={message}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
|
@ -215,7 +172,6 @@ function HistoryDetails(props) {
|
|||
|
||||
if (eventType === 'trackFileImported') {
|
||||
const {
|
||||
customFormatScore,
|
||||
droppedPath,
|
||||
importedPath
|
||||
} = data;
|
||||
|
@ -224,37 +180,26 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
droppedPath ?
|
||||
!!droppedPath &&
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Source')}
|
||||
title="Source"
|
||||
data={droppedPath}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
importedPath ?
|
||||
!!importedPath &&
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('ImportedTo')}
|
||||
title="Imported To"
|
||||
data={importedPath}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
customFormatScore && customFormatScore !== '0' ?
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(customFormatScore)}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
|
@ -262,8 +207,7 @@ function HistoryDetails(props) {
|
|||
|
||||
if (eventType === 'trackFileDeleted') {
|
||||
const {
|
||||
reason,
|
||||
customFormatScore
|
||||
reason
|
||||
} = data;
|
||||
|
||||
let reasonMessage = '';
|
||||
|
@ -273,7 +217,7 @@ function HistoryDetails(props) {
|
|||
reasonMessage = 'File was deleted by via UI';
|
||||
break;
|
||||
case 'MissingFromDisk':
|
||||
reasonMessage = 'Lidarr was unable to find the file on disk so the file was unlinked from the album/track in the database';
|
||||
reasonMessage = 'Lidarr was unable to find the file on disk so it was removed';
|
||||
break;
|
||||
case 'Upgrade':
|
||||
reasonMessage = 'File was deleted to import an upgrade';
|
||||
|
@ -285,23 +229,14 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title={translate('Reason')}
|
||||
title="Reason"
|
||||
data={reasonMessage}
|
||||
/>
|
||||
|
||||
{
|
||||
customFormatScore && customFormatScore !== '0' ?
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(customFormatScore)}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
}
|
||||
|
@ -309,20 +244,32 @@ function HistoryDetails(props) {
|
|||
if (eventType === 'trackFileRenamed') {
|
||||
const {
|
||||
sourcePath,
|
||||
path
|
||||
sourceRelativePath,
|
||||
path,
|
||||
relativePath
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title={translate('SourcePath')}
|
||||
title="Source Path"
|
||||
data={sourcePath}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title={translate('DestinationPath')}
|
||||
title="Source Relative Path"
|
||||
data={sourceRelativePath}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Destination Path"
|
||||
data={path}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Destination Relative Path"
|
||||
data={relativePath}
|
||||
/>
|
||||
</DescriptionList>
|
||||
);
|
||||
}
|
||||
|
@ -336,7 +283,7 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title={translate('Path')}
|
||||
title="Path"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
{
|
||||
|
@ -351,7 +298,7 @@ function HistoryDetails(props) {
|
|||
})
|
||||
}
|
||||
<DescriptionListItem
|
||||
title={translate('ExistingTagsScrubbed')}
|
||||
title="Existing tags scrubbed"
|
||||
data={tagsScrubbed === 'True' ? <Icon name={icons.CHECK} /> : <Icon name={icons.REMOVE} />}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
@ -366,14 +313,14 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
!!statusMessages &&
|
||||
<DescriptionListItem
|
||||
title={translate('ImportFailures')}
|
||||
title="Import failures"
|
||||
data={getDetailedList(JSON.parse(statusMessages))}
|
||||
/>
|
||||
}
|
||||
|
@ -385,9 +332,9 @@ function HistoryDetails(props) {
|
|||
const {
|
||||
indexer,
|
||||
releaseGroup,
|
||||
customFormatScore,
|
||||
nzbInfoUrl,
|
||||
downloadClient,
|
||||
downloadId,
|
||||
age,
|
||||
ageHours,
|
||||
ageMinutes,
|
||||
|
@ -397,119 +344,69 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
indexer ?
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title={translate('Indexer')}
|
||||
title="Indexer"
|
||||
data={indexer}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
releaseGroup ?
|
||||
!!releaseGroup &&
|
||||
<DescriptionListItem
|
||||
title={translate('ReleaseGroup')}
|
||||
title="Release Group"
|
||||
data={releaseGroup}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
customFormatScore && customFormatScore !== '0' ?
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(customFormatScore)}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
nzbInfoUrl ?
|
||||
!!nzbInfoUrl &&
|
||||
<span>
|
||||
<DescriptionListItemTitle>
|
||||
{translate('InfoUrl')}
|
||||
Info URL
|
||||
</DescriptionListItemTitle>
|
||||
|
||||
<DescriptionListItemDescription>
|
||||
<Link to={nzbInfoUrl}>{nzbInfoUrl}</Link>
|
||||
</DescriptionListItemDescription>
|
||||
</span> :
|
||||
null
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
downloadClient ?
|
||||
!!downloadClient &&
|
||||
<DescriptionListItem
|
||||
title={translate('DownloadClient')}
|
||||
title="Download Client"
|
||||
data={downloadClient}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
downloadId ?
|
||||
!!downloadId &&
|
||||
<DescriptionListItem
|
||||
title={translate('GrabId')}
|
||||
title="Grab ID"
|
||||
data={downloadId}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
age || ageHours || ageMinutes ?
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title={translate('AgeWhenGrabbed')}
|
||||
title="Age (when grabbed)"
|
||||
data={formatAge(age, ageHours, ageMinutes)}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
publishedDate ?
|
||||
!!publishedDate &&
|
||||
<DescriptionListItem
|
||||
title={translate('PublishedDate')}
|
||||
title="Published Date"
|
||||
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
}
|
||||
|
||||
if (eventType === 'downloadIgnored') {
|
||||
const {
|
||||
message
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
downloadId ?
|
||||
<DescriptionListItem
|
||||
title={translate('GrabId')}
|
||||
data={downloadId}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
message ?
|
||||
<DescriptionListItem
|
||||
title={translate('Message')}
|
||||
data={message}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
|
@ -519,7 +416,7 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title={translate('Name')}
|
||||
title="Name"
|
||||
data={sourceTitle}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
@ -530,7 +427,6 @@ HistoryDetails.propTypes = {
|
|||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
downloadId: PropTypes.string,
|
||||
shortDateFormat: PropTypes.string.isRequired,
|
||||
timeFormat: PropTypes.string.isRequired
|
||||
};
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'markAsFailedButton': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
|
@ -1,13 +1,13 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import Button from 'Components/Link/Button';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import HistoryDetails from './HistoryDetails';
|
||||
import styles from './HistoryDetailsModal.css';
|
||||
|
||||
|
@ -29,8 +29,6 @@ function getHeaderTitle(eventType) {
|
|||
return 'Album Import Incomplete';
|
||||
case 'downloadImported':
|
||||
return 'Download Completed';
|
||||
case 'downloadIgnored':
|
||||
return 'Download Ignored';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
|
@ -42,7 +40,6 @@ function HistoryDetailsModal(props) {
|
|||
eventType,
|
||||
sourceTitle,
|
||||
data,
|
||||
downloadId,
|
||||
isMarkingAsFailed,
|
||||
shortDateFormat,
|
||||
timeFormat,
|
||||
|
@ -65,7 +62,6 @@ function HistoryDetailsModal(props) {
|
|||
eventType={eventType}
|
||||
sourceTitle={sourceTitle}
|
||||
data={data}
|
||||
downloadId={downloadId}
|
||||
shortDateFormat={shortDateFormat}
|
||||
timeFormat={timeFormat}
|
||||
/>
|
||||
|
@ -100,7 +96,6 @@ HistoryDetailsModal.propTypes = {
|
|||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
downloadId: PropTypes.string,
|
||||
isMarkingAsFailed: PropTypes.bool.isRequired,
|
||||
shortDateFormat: PropTypes.string.isRequired,
|
||||
timeFormat: PropTypes.string.isRequired,
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import TablePager from 'Components/Table/TablePager';
|
||||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import HistoryFilterModal from './HistoryFilterModal';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||
import HistoryRowConnector from './HistoryRowConnector';
|
||||
|
||||
class History extends Component {
|
||||
|
@ -53,10 +50,7 @@ class History extends Component {
|
|||
columns,
|
||||
selectedFilterKey,
|
||||
filters,
|
||||
customFilters,
|
||||
totalRecords,
|
||||
isArtistFetching,
|
||||
isArtistPopulated,
|
||||
isAlbumsFetching,
|
||||
isAlbumsPopulated,
|
||||
albumsError,
|
||||
|
@ -65,16 +59,16 @@ class History extends Component {
|
|||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const isFetchingAny = isFetching || isArtistFetching || isAlbumsFetching;
|
||||
const isAllPopulated = isPopulated && ((isArtistPopulated && isAlbumsPopulated) || !items.length);
|
||||
const isFetchingAny = isFetching || isAlbumsFetching;
|
||||
const isAllPopulated = isPopulated && (isAlbumsPopulated || !items.length);
|
||||
const hasError = error || albumsError;
|
||||
|
||||
return (
|
||||
<PageContent title={translate('History')}>
|
||||
<PageContent title="History">
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label={translate('Refresh')}
|
||||
label="Refresh"
|
||||
iconName={icons.REFRESH}
|
||||
isSpinning={isFetching}
|
||||
onPress={onFirstPagePress}
|
||||
|
@ -87,7 +81,7 @@ class History extends Component {
|
|||
columns={columns}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label={translate('Options')}
|
||||
label="Options"
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
|
@ -96,14 +90,13 @@ class History extends Component {
|
|||
alignMenu={align.RIGHT}
|
||||
selectedFilterKey={selectedFilterKey}
|
||||
filters={filters}
|
||||
customFilters={customFilters}
|
||||
filterModalConnectorComponent={HistoryFilterModal}
|
||||
customFilters={[]}
|
||||
onFilterSelect={onFilterSelect}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
</PageToolbar>
|
||||
|
||||
<PageContentBody>
|
||||
<PageContentBodyConnector>
|
||||
{
|
||||
isFetchingAny && !isAllPopulated &&
|
||||
<LoadingIndicator />
|
||||
|
@ -111,9 +104,7 @@ class History extends Component {
|
|||
|
||||
{
|
||||
!isFetchingAny && hasError &&
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadHistory')}
|
||||
</Alert>
|
||||
<div>Unable to load history</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -121,9 +112,9 @@ class History extends Component {
|
|||
// wait for the albums to populate because they are never coming.
|
||||
|
||||
isPopulated && !hasError && !items.length &&
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('NoHistory')}
|
||||
</Alert>
|
||||
<div>
|
||||
No history found
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -156,7 +147,7 @@ class History extends Component {
|
|||
/>
|
||||
</div>
|
||||
}
|
||||
</PageContentBody>
|
||||
</PageContentBodyConnector>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
@ -168,12 +159,9 @@ History.propTypes = {
|
|||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
selectedFilterKey: PropTypes.string.isRequired,
|
||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
customFilters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
totalRecords: PropTypes.number,
|
||||
isArtistFetching: PropTypes.bool.isRequired,
|
||||
isArtistPopulated: PropTypes.bool.isRequired,
|
||||
isAlbumsFetching: PropTypes.bool.isRequired,
|
||||
isAlbumsPopulated: PropTypes.bool.isRequired,
|
||||
albumsError: PropTypes.object,
|
||||
|
|
|
@ -2,34 +2,28 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import { clearAlbums, fetchAlbums } from 'Store/Actions/albumActions';
|
||||
import * as historyActions from 'Store/Actions/historyActions';
|
||||
import { clearTracks, fetchTracks } from 'Store/Actions/trackActions';
|
||||
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import * as historyActions from 'Store/Actions/historyActions';
|
||||
import { fetchAlbums, clearAlbums } from 'Store/Actions/albumActions';
|
||||
import { fetchTracks, clearTracks } from 'Store/Actions/trackActions';
|
||||
import History from './History';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.history,
|
||||
(state) => state.artist,
|
||||
(state) => state.albums,
|
||||
(state) => state.tracks,
|
||||
createCustomFiltersSelector('history'),
|
||||
(history, artist, albums, tracks, customFilters) => {
|
||||
(history, albums, tracks) => {
|
||||
return {
|
||||
isArtistFetching: artist.isFetching,
|
||||
isArtistPopulated: artist.isPopulated,
|
||||
isAlbumsFetching: albums.isFetching,
|
||||
isAlbumsPopulated: albums.isPopulated,
|
||||
albumsError: albums.error,
|
||||
isTracksFetching: tracks.isFetching,
|
||||
isTracksPopulated: tracks.isPopulated,
|
||||
tracksError: tracks.error,
|
||||
customFilters,
|
||||
...history
|
||||
};
|
||||
}
|
||||
|
@ -94,38 +88,38 @@ class HistoryConnector extends Component {
|
|||
|
||||
repopulate = () => {
|
||||
this.props.fetchHistory();
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onFirstPagePress = () => {
|
||||
this.props.gotoHistoryFirstPage();
|
||||
};
|
||||
}
|
||||
|
||||
onPreviousPagePress = () => {
|
||||
this.props.gotoHistoryPreviousPage();
|
||||
};
|
||||
}
|
||||
|
||||
onNextPagePress = () => {
|
||||
this.props.gotoHistoryNextPage();
|
||||
};
|
||||
}
|
||||
|
||||
onLastPagePress = () => {
|
||||
this.props.gotoHistoryLastPage();
|
||||
};
|
||||
}
|
||||
|
||||
onPageSelect = (page) => {
|
||||
this.props.gotoHistoryPage({ page });
|
||||
};
|
||||
}
|
||||
|
||||
onSortPress = (sortKey) => {
|
||||
this.props.setHistorySort({ sortKey });
|
||||
};
|
||||
}
|
||||
|
||||
onFilterSelect = (selectedFilterKey) => {
|
||||
this.props.setHistoryFilter({ selectedFilterKey });
|
||||
};
|
||||
}
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setHistoryTableOption(payload);
|
||||
|
@ -133,7 +127,7 @@ class HistoryConnector extends Component {
|
|||
if (payload.pageSize) {
|
||||
this.props.gotoHistoryFirstPage();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'cell': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
|
@ -1,12 +1,11 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import Icon from 'Components/Icon';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './HistoryEventTypeCell.css';
|
||||
|
||||
function getIconName(eventType, data) {
|
||||
function getIconName(eventType) {
|
||||
switch (eventType) {
|
||||
case 'grabbed':
|
||||
return icons.DOWNLOADING;
|
||||
|
@ -17,7 +16,7 @@ function getIconName(eventType, data) {
|
|||
case 'downloadFailed':
|
||||
return icons.DOWNLOADING;
|
||||
case 'trackFileDeleted':
|
||||
return data.reason === 'MissingFromDisk' ? icons.FILE_MISSING : icons.DELETE;
|
||||
return icons.DELETE;
|
||||
case 'trackFileRenamed':
|
||||
return icons.ORGANIZE;
|
||||
case 'trackFileRetagged':
|
||||
|
@ -26,8 +25,6 @@ function getIconName(eventType, data) {
|
|||
return icons.DOWNLOADED;
|
||||
case 'downloadImported':
|
||||
return icons.DOWNLOADED;
|
||||
case 'downloadIgnored':
|
||||
return icons.IGNORE;
|
||||
default:
|
||||
return icons.UNKNOWN;
|
||||
}
|
||||
|
@ -55,24 +52,22 @@ function getTooltip(eventType, data) {
|
|||
case 'downloadFailed':
|
||||
return 'Album download failed';
|
||||
case 'trackFileDeleted':
|
||||
return data.reason === 'MissingFromDisk' ? translate('TrackFileMissingTooltip') : translate('TrackFileDeletedTooltip');
|
||||
return 'Track file deleted';
|
||||
case 'trackFileRenamed':
|
||||
return translate('TrackFileRenamedTooltip');
|
||||
return 'Track file renamed';
|
||||
case 'trackFileRetagged':
|
||||
return translate('TrackFileTagsUpdatedTooltip');
|
||||
return 'Track file tags updated';
|
||||
case 'albumImportIncomplete':
|
||||
return 'Files downloaded but not all could be imported';
|
||||
case 'downloadImported':
|
||||
return 'Download completed and successfully imported';
|
||||
case 'downloadIgnored':
|
||||
return 'Album Download Ignored';
|
||||
default:
|
||||
return 'Unknown event';
|
||||
}
|
||||
}
|
||||
|
||||
function HistoryEventTypeCell({ eventType, data }) {
|
||||
const iconName = getIconName(eventType, data);
|
||||
const iconName = getIconName(eventType);
|
||||
const iconKind = getIconKind(eventType);
|
||||
const tooltip = getTooltip(eventType, data);
|
||||
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import AppState from 'App/State/AppState';
|
||||
import FilterModal from 'Components/Filter/FilterModal';
|
||||
import { setHistoryFilter } from 'Store/Actions/historyActions';
|
||||
|
||||
function createHistorySelector() {
|
||||
return createSelector(
|
||||
(state: AppState) => state.history.items,
|
||||
(queueItems) => {
|
||||
return queueItems;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createFilterBuilderPropsSelector() {
|
||||
return createSelector(
|
||||
(state: AppState) => state.history.filterBuilderProps,
|
||||
(filterBuilderProps) => {
|
||||
return filterBuilderProps;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
interface HistoryFilterModalProps {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default function HistoryFilterModal(props: HistoryFilterModalProps) {
|
||||
const sectionItems = useSelector(createHistorySelector());
|
||||
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
|
||||
const customFilterType = 'history';
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const dispatchSetFilter = useCallback(
|
||||
(payload: unknown) => {
|
||||
dispatch(setHistoryFilter(payload));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<FilterModal
|
||||
// TODO: Don't spread all the props
|
||||
{...props}
|
||||
sectionItems={sectionItems}
|
||||
filterBuilderProps={filterBuilderProps}
|
||||
customFilterType={customFilterType}
|
||||
dispatchSetFilter={dispatchSetFilter}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -10,12 +10,6 @@
|
|||
width: 80px;
|
||||
}
|
||||
|
||||
.customFormatScore {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 55px;
|
||||
}
|
||||
|
||||
.releaseGroup {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'customFormatScore': string;
|
||||
'details': string;
|
||||
'downloadClient': string;
|
||||
'indexer': string;
|
||||
'releaseGroup': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue