diff --git a/.circleci/config.yml b/.circleci/config.yml index a3a17b0..ee2764a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,10 +14,9 @@ version: 2 run: name: "Store Version" command: | - BRANCH=$([ -z "$CI_COMMIT_TAG" ] && echo "$CIRCLE_BRANCH" || echo "master") + BRANCH=$([ -z "$CIRCLE_TAG" ] && echo "$CIRCLE_BRANCH" || echo "master") echo "$CIRCLE_TAG $BRANCH ${CIRCLE_SHA1::7}" > build/VERSION cat build/VERSION - echo "export BRANCH=$BRANCH" >> $BASH_ENV jobs: build: @@ -41,10 +40,11 @@ jobs: name: "Upload" command: | [ -z "$FTL_SECRET" ] && exit 0 + FOLDER=$([ -z "$CIRCLE_TAG" ] && echo "$CIRCLE_BRANCH" || echo "$CIRCLE_TAG") tar -czvf pihole-web.tar.gz -C build . wget https://ftl.pi-hole.net:8080/FTL-client chmod +x ./FTL-client - ./FTL-client "$BRANCH" pihole-web.tar.gz "$FTL_SECRET" + ./FTL-client "$FOLDER" pihole-web.tar.gz "$FTL_SECRET" rm ./FTL-client - save_cache: key: v1-build-{{ checksum "package-lock.json" }} diff --git a/public/i18n/bg/common.json b/public/i18n/bg/common.json index 21ca0be..4760192 100644 --- a/public/i18n/bg/common.json +++ b/public/i18n/bg/common.json @@ -1,4 +1,5 @@ { + "Details": "Детайли / детайли", "Status": "Статус / статус", "DNS": "DNS / ДНС", "Donate": "Дарят", diff --git a/public/i18n/bg/login.json b/public/i18n/bg/login.json index 8dd16f7..9934915 100644 --- a/public/i18n/bg/login.json +++ b/public/i18n/bg/login.json @@ -5,6 +5,6 @@ "Forgot Password": "Забравена парола", "forgot_password_description": "забравена парола описание", "Wrong Password!": "Грешна парола!", - "You will be transferred to the {{page}}": "Ще бъдете прехвърлени на {{страницата}}", + "You will be transferred to the \"{{page}}\" page": "Ще бъдете прехвърлени на {{страницата}}", "Verify that cookies are allowed for {{host}}": "Уверете се, че бисквитките са разрешени за {{хост}}" } \ No newline at end of file diff --git a/public/i18n/ca/common.json b/public/i18n/ca/common.json new file mode 100644 index 0000000..47dbfdc --- /dev/null +++ b/public/i18n/ca/common.json @@ -0,0 +1,23 @@ +{ + "Details": "Detalls", + "Status": "Estat", + "DNS": "DNS", + "Donate": "Donatius", + "Domain": "Domini", + "Hits": "Consultes", + "Frequency": "freqüència", + "Client": "Client", + "Requests": "Consultes", + "Add": "Afegir", + "Time": "Tiempo", + "Type": "Tipus", + "Network": "Xarxa", + "Action": "Acció", + "Enabled": "Activat", + "Disabled": "Desactivat", + "DHCP": "DHCP", + "Core": "Core", + "FTL": "FTL", + "API": "API", + "Web": "Web" +} \ No newline at end of file diff --git a/public/i18n/ca/dashboard.json b/public/i18n/ca/dashboard.json new file mode 100644 index 0000000..cc38894 --- /dev/null +++ b/public/i18n/ca/dashboard.json @@ -0,0 +1,23 @@ +{ + "Domains On Blocklist": "Dominis bloquejats", + "Query Types": "Tipus de consultes", + "Forward Destinations": "DNS Remots", + "Top Permitted Domains": "Dominis principales", + "Top Blocked Domains": "Anunciants principals", + "Top Clients": "Clients principals", + "Total Queries ({{count}} clients)": "Consultes Totals ({{clients}} client)", + "Total Queries ({{count}} clients)_plural": "Consultes Totals ({{clients}} clients)", + "Queries Blocked": "Consultes Bloquejades", + "Percent Blocked": "Percentatge Bloquejat", + "Queries Over Last 24 Hours": "Consultes últimes 24 hores", + "Clients Over Last 24 Hours": "Clients últimes 24 hores", + "Queries Answered By": "Consultes contestades per", + "Queries from {{from}} to {{to}}": "Consultes de {{from}} a {{to}}", + "Total Queries": "Consultes totals", + "Blocked Queries": "Consultes bloquejades", + "Client activity from {{from}} to {{to}}": "Activitat de clients de {{from}} a {{to}}", + "{{percent}}% of {{total}}": "\n{{percent}}% de {{total}}\n", + "No Clients Found": "No s'ha trobat cap client", + "No Domains Found": "No s'ha trobat cap domini", + "Queries Answered By Destination": "Respostes per destí" +} \ No newline at end of file diff --git a/public/i18n/ca/footer.json b/public/i18n/ca/footer.json new file mode 100644 index 0000000..dfe8a0b --- /dev/null +++ b/public/i18n/ca/footer.json @@ -0,0 +1,5 @@ +{ + "if you found this useful": "si et sembla útil", + "Core Version": "Versió de Pi-hole", + "Web Version": "Versió del interface web" +} \ No newline at end of file diff --git a/public/i18n/ca/lists.json b/public/i18n/ca/lists.json new file mode 100644 index 0000000..aebcbda --- /dev/null +++ b/public/i18n/ca/lists.json @@ -0,0 +1,12 @@ +{ + "Adding {{domain}}...": "Afegint a", + "Successfully added {{domain}}": "¡Correcte! La llista se actualitzarà.", + "Failed to add {{domain}}": "¡S' ha produït un error!", + "Note: Whitelisting a subdomain of a wildcard blocked domain is not possible.": "Nota: Afegir a la llista blanca un domini bloquejat per comodí no es possible", + "Note: Only the domain and subdomains of the blocked domain will be blocked.": "Nota: Només el domini i subdominis del domini bloquejat seran bloquejats", + "Add a domain (example.com or sub.example.com)": "Afegir un domini ( example.com o sub.example.com)", + "{{domain}} is already added": "{{domain}} ja està afegit\n", + "Failed to remove {{domain}}": "Error en esborrar {{domain}}", + "There are no domains in this list": "No hi ha dominis en aquesta llista", + "Input a regular expression": "Escriu una expressió regular" +} \ No newline at end of file diff --git a/public/i18n/ca/location.json b/public/i18n/ca/location.json new file mode 100644 index 0000000..7bb0f41 --- /dev/null +++ b/public/i18n/ca/location.json @@ -0,0 +1,11 @@ +{ + "Query Log": "Log de consultes", + "Whitelist": "Llista blanca", + "Blacklist": "Llista negra", + "Dashboard": "Panell de Control", + "Exact": "Exacte", + "Wildcard": "Comodí", + "Login": "Entrar", + "Logout": "Sortir", + "Regex": "Regex" +} \ No newline at end of file diff --git a/public/i18n/ca/login.json b/public/i18n/ca/login.json new file mode 100644 index 0000000..7f89c37 --- /dev/null +++ b/public/i18n/ca/login.json @@ -0,0 +1,10 @@ +{ + "Password": "Clau", + "Sign in to start your session": "Identificat per iniciar sessió", + "Log in": "Entrar", + "Forgot Password": "He oblidat la clau", + "forgot_password_description": "Després de Instal·lar Pi-hole per primer cop, es genera una clau i es mostra al usuari.\nLa clau no pot eser recuperada mes tard, però es pot canviar (o esborrar-la explícitament establint una clau buida) utilitzant la comanda:", + "Wrong Password!": "Clau incorrecta", + "You will be transferred to the \"{{page}}\" page": "Serás redirigit a {{page}}", + "Verify that cookies are allowed for {{host}}": "Verifica que s'han permés les cookies per {{host}}" +} \ No newline at end of file diff --git a/public/i18n/ca/query-log.json b/public/i18n/ca/query-log.json new file mode 100644 index 0000000..acd3bbe --- /dev/null +++ b/public/i18n/ca/query-log.json @@ -0,0 +1,7 @@ +{ + "Blocked": "Bloquejat", + "Allowed (forwarded)": "Permès (reenviat)", + "Allowed (cached)": "Permès (al cau)", + "Blocked (regex)": "Bloquejat (comodí)", + "Blocked (blacklist)": "Bloquejat (Llista negra)" +} \ No newline at end of file diff --git a/public/i18n/ca/settings.json b/public/i18n/ca/settings.json new file mode 100644 index 0000000..0b0929b --- /dev/null +++ b/public/i18n/ca/settings.json @@ -0,0 +1,26 @@ +{ + "DHCP Active": "DHCP Actiu", + "Start IP": "IP inicial", + "End IP": "IP final", + "Router IP": "IP del router", + "Lease Time": "Temps de concessió", + "IPv6 Support": "Suport IPv6", + "Upstream DNS Servers": "Servidors DNS externs", + "Interface listening behavior": "Comportament del interface", + "Forward FQDNs only": "Reenviar només FQDN", + "Use DNSSEC": "Usar DNSSEC", + "Conditional Forwarding": "Reenviament condicional", + "Local Domain Name": "Domini local", + "FTL Database": "Base de dades FTL", + "Queries": "Consultes", + "Filesize": "Tamany", + "SQLite version": "Versió SQLite", + "Interface": "Interface", + "IPv4 address": "Adreça IPv4", + "IPv6 address": "Adreça IPv6", + "Hostname": "Hostname", + "Branch": "Branca", + "Hash": "Hash", + "Tag": "Tag", + "Only forward public reverse lookups": "Reenviar només les cerques inverses públiques" +} \ No newline at end of file diff --git a/public/i18n/en/common.json b/public/i18n/en/common.json index cc3f1c2..26338d8 100644 --- a/public/i18n/en/common.json +++ b/public/i18n/en/common.json @@ -1,4 +1,5 @@ { + "Details": "Details", "Status": "Status", "DNS": "DNS", "Donate": "Donate", @@ -10,7 +11,7 @@ "Add": "Add", "Time": "Time", "Type": "Type", - "Network": "Network\n", + "Network": "Network", "Action": "Action", "Enabled": "Enabled", "Disabled": "Disabled", @@ -18,5 +19,6 @@ "Core": "Core", "FTL": "FTL", "API": "API", - "Web": "Web" + "Web": "Web", + "Version": "Version" } \ No newline at end of file diff --git a/public/i18n/en/location.json b/public/i18n/en/location.json index d868287..d1ead97 100644 --- a/public/i18n/en/location.json +++ b/public/i18n/en/location.json @@ -7,5 +7,8 @@ "Wildcard": "Wildcard", "Login": "Login", "Logout": "Logout", - "Regex": "Regex" + "Regex": "Regex", + "Settings": "Settings", + "Networking": "Networking", + "Versions": "Versions" } \ No newline at end of file diff --git a/public/i18n/en/login.json b/public/i18n/en/login.json index c5a207b..7c76dcd 100644 --- a/public/i18n/en/login.json +++ b/public/i18n/en/login.json @@ -5,6 +5,6 @@ "Forgot Password": "Forgot Password", "forgot_password_description": "After installing Pi-hole for the first time, a password is generated and displayed to the user. The password cannot be retrieved later on, but it is possible to set a new password (or explicitly disable the password by setting an empty password) using the command:", "Wrong Password!": "Wrong Password!", - "You will be transferred to the {{page}}": "You will be transferred to the {{page}}", + "You will be transferred to the \"{{page}}\" page": "You will be transferred to the \"{{page}}\" page", "Verify that cookies are allowed for {{host}}": "Verify that cookies are allowed for {{host}}" } \ No newline at end of file diff --git a/public/i18n/es/common.json b/public/i18n/es/common.json index f48fe72..9f2b9e2 100644 --- a/public/i18n/es/common.json +++ b/public/i18n/es/common.json @@ -1,4 +1,5 @@ { + "Details": "Detalles", "Status": "Estado", "DNS": "DNS", "Donate": "Donar", diff --git a/public/i18n/es/login.json b/public/i18n/es/login.json index b09dc2b..8101805 100644 --- a/public/i18n/es/login.json +++ b/public/i18n/es/login.json @@ -5,6 +5,6 @@ "Forgot Password": "Olvidé la contraseña", "forgot_password_description": "Frase para recordar la contraseña", "Wrong Password!": "Contraseña incorrecta", - "You will be transferred to the {{page}}": "Será trasferido a la página: {{page}}", + "You will be transferred to the \"{{page}}\" page": "Será trasferido a la página: {{page}}", "Verify that cookies are allowed for {{host}}": "Verifique que {{host}} admite cookies." } \ No newline at end of file diff --git a/public/i18n/pt/common.json b/public/i18n/pt/common.json index 593dbea..c684678 100644 --- a/public/i18n/pt/common.json +++ b/public/i18n/pt/common.json @@ -1,4 +1,5 @@ { + "Details": "Detalhes", "Status": "Status", "DNS": "DNS", "Donate": "Doar", diff --git a/public/i18n/pt/login.json b/public/i18n/pt/login.json index f649f48..bc2c077 100644 --- a/public/i18n/pt/login.json +++ b/public/i18n/pt/login.json @@ -5,6 +5,6 @@ "Forgot Password": "Esqueceu a palavra passe", "forgot_password_description": "Esqueceu a palavra passe descrição", "Wrong Password!": "Palavra passe incorreta!", - "You will be transferred to the {{page}}": "Você será transferido para a {{página}}", + "You will be transferred to the \"{{page}}\" page": "Você será transferido para a {{página}}", "Verify that cookies are allowed for {{host}}": "Verifique se os cookies são permitidos para {{host}}" } \ No newline at end of file diff --git a/src/components/VersionCard.js b/src/components/VersionCard.js deleted file mode 100644 index 666f059..0000000 --- a/src/components/VersionCard.js +++ /dev/null @@ -1,41 +0,0 @@ -/* Pi-hole: A black hole for Internet advertisements -* (c) 2017 Pi-hole, LLC (https://pi-hole.net) -* Network-wide ad blocking via your own hardware. -* -* Web Interface -* Settings :: Version - Card component -* -* This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ - -import React from 'react'; -import { translate } from 'react-i18next'; -import PropTypes from 'prop-types'; - -const VersionCard = props => ( -
-
-
- -
-
-
-

{props.name}

-
-        
- {props.t("Branch")}: {props.branch}
- {props.t("Hash")}: {props.hash}
- {props.t("Tag")}: {props.tag}
-
-
-
-); - -VersionCard.propTypes = { - branch: PropTypes.string.isRequired, - hash: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - tag: PropTypes.string.isRequired -}; - -export default translate(['settings'])(VersionCard); diff --git a/src/components/Alert.js b/src/components/common/Alert.js similarity index 100% rename from src/components/Alert.js rename to src/components/common/Alert.js diff --git a/src/components/Alert.test.js b/src/components/common/Alert.test.js similarity index 100% rename from src/components/Alert.test.js rename to src/components/common/Alert.test.js diff --git a/src/components/BoxedLayoutButton.js b/src/components/common/BoxedLayoutButton.js similarity index 100% rename from src/components/BoxedLayoutButton.js rename to src/components/common/BoxedLayoutButton.js diff --git a/src/components/BoxedLayoutButton.test.js b/src/components/common/BoxedLayoutButton.test.js similarity index 100% rename from src/components/BoxedLayoutButton.test.js rename to src/components/common/BoxedLayoutButton.test.js diff --git a/src/components/Footer.js b/src/components/common/Footer.js similarity index 100% rename from src/components/Footer.js rename to src/components/common/Footer.js diff --git a/src/components/Footer.test.js b/src/components/common/Footer.test.js similarity index 100% rename from src/components/Footer.test.js rename to src/components/common/Footer.test.js diff --git a/src/components/Header.js b/src/components/common/Header.js similarity index 100% rename from src/components/Header.js rename to src/components/common/Header.js diff --git a/src/components/Sidebar.js b/src/components/common/Sidebar.js similarity index 94% rename from src/components/Sidebar.js rename to src/components/common/Sidebar.js index 19acdc5..b87468f 100644 --- a/src/components/Sidebar.js +++ b/src/components/common/Sidebar.js @@ -12,9 +12,9 @@ import React from "react"; import { translate } from "react-i18next"; import { NavLink } from "react-router-dom"; import { Nav, NavItem } from "reactstrap"; -import logo from "../img/logo.svg"; +import logo from "../../img/logo.svg"; import { mobileSidebarHide } from "./Header"; -import { api } from "../utils"; +import { api } from "../../utils"; import StatusBadge from "./StatusBadge"; const handleClick = (e) => { @@ -70,7 +70,7 @@ const Sidebar = ({ items, ...props }) => { paddingLeft: "15px", textTransform: "initial", fontSize: "14px", marginBottom: "initial", lineHeight: "14px", color: "white" }}> - Pi-hole + {props.t("Status")}


@@ -84,4 +84,4 @@ const Sidebar = ({ items, ...props }) => { ); }; -export default translate("location")(Sidebar); +export default translate(["common", "location"])(Sidebar); diff --git a/src/components/Sidebar.test.js b/src/components/common/Sidebar.test.js similarity index 98% rename from src/components/Sidebar.test.js rename to src/components/common/Sidebar.test.js index c34602d..5b41fd7 100644 --- a/src/components/Sidebar.test.js +++ b/src/components/common/Sidebar.test.js @@ -11,7 +11,7 @@ import React from "react"; import { shallow } from "enzyme"; import { dropDownClassList, navDropdown, navItem, navList } from "./Sidebar"; -import { api } from "../utils"; +import { api } from "../../utils"; it("expands active drop down items", () => { const classList = dropDownClassList("/testRoute", { location: { pathname: "/testRoute/page" } }); diff --git a/src/components/StatusBadge.js b/src/components/common/StatusBadge.js similarity index 93% rename from src/components/StatusBadge.js rename to src/components/common/StatusBadge.js index b116007..2901222 100644 --- a/src/components/StatusBadge.js +++ b/src/components/common/StatusBadge.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { translate } from 'react-i18next'; -import { api, makeCancelable, ignoreCancel } from '../utils'; +import { api, makeCancelable, ignoreCancel } from '../../utils'; class StatusBadge extends Component { state = { diff --git a/src/components/StatusBadge.test.js b/src/components/common/StatusBadge.test.js similarity index 100% rename from src/components/StatusBadge.test.js rename to src/components/common/StatusBadge.test.js diff --git a/src/components/ChartTooltip.js b/src/components/dashboard/ChartTooltip.js similarity index 100% rename from src/components/ChartTooltip.js rename to src/components/dashboard/ChartTooltip.js diff --git a/src/components/ClientsGraph.js b/src/components/dashboard/ClientsGraph.js similarity index 99% rename from src/components/ClientsGraph.js rename to src/components/dashboard/ClientsGraph.js index b617e5b..72c1797 100644 --- a/src/components/ClientsGraph.js +++ b/src/components/dashboard/ClientsGraph.js @@ -12,7 +12,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import { Line } from 'react-chartjs-2'; import { translate } from 'react-i18next'; -import { padNumber, api, makeCancelable, ignoreCancel } from '../utils'; +import { padNumber, api, makeCancelable, ignoreCancel } from '../../utils'; import ChartTooltip from "./ChartTooltip"; class ClientsGraph extends Component { diff --git a/src/components/ClientsGraph.test.js b/src/components/dashboard/ClientsGraph.test.js similarity index 100% rename from src/components/ClientsGraph.test.js rename to src/components/dashboard/ClientsGraph.test.js diff --git a/src/components/ForwardDestinationsChart.js b/src/components/dashboard/ForwardDestinationsChart.js similarity index 95% rename from src/components/ForwardDestinationsChart.js rename to src/components/dashboard/ForwardDestinationsChart.js index f1f9198..cd4cb24 100644 --- a/src/components/ForwardDestinationsChart.js +++ b/src/components/dashboard/ForwardDestinationsChart.js @@ -10,7 +10,7 @@ import React from "react"; import { translate } from "react-i18next"; -import { api } from "../utils"; +import { api } from "../../utils"; import GenericDoughnutChart from "./GenericDoughnutChart"; const ForwardDestinationsChart = ({ t }) => ( diff --git a/src/components/GenericDoughnutChart.js b/src/components/dashboard/GenericDoughnutChart.js similarity index 98% rename from src/components/GenericDoughnutChart.js rename to src/components/dashboard/GenericDoughnutChart.js index e18b4de..2eafdb2 100644 --- a/src/components/GenericDoughnutChart.js +++ b/src/components/dashboard/GenericDoughnutChart.js @@ -11,7 +11,7 @@ import React, { Component } from "react"; import { Doughnut } from "react-chartjs-2"; import PropTypes from "prop-types"; -import { makeCancelable, ignoreCancel } from "../utils"; +import { makeCancelable, ignoreCancel } from "../../utils"; class GenericDoughnutChart extends Component { state = { diff --git a/src/components/GenericDoughnutChart.test.js b/src/components/dashboard/GenericDoughnutChart.test.js similarity index 100% rename from src/components/GenericDoughnutChart.test.js rename to src/components/dashboard/GenericDoughnutChart.test.js diff --git a/src/components/QueriesGraph.js b/src/components/dashboard/QueriesGraph.js similarity index 99% rename from src/components/QueriesGraph.js rename to src/components/dashboard/QueriesGraph.js index bcffa14..e8a18a7 100644 --- a/src/components/QueriesGraph.js +++ b/src/components/dashboard/QueriesGraph.js @@ -11,7 +11,7 @@ import React, { Component } from 'react'; import { Line } from 'react-chartjs-2'; import { translate } from 'react-i18next'; -import { padNumber, api, makeCancelable, ignoreCancel } from '../utils'; +import { padNumber, api, makeCancelable, ignoreCancel } from '../../utils'; class QueriesGraph extends Component { state = { diff --git a/src/components/QueryTypesChart.js b/src/components/dashboard/QueryTypesChart.js similarity index 94% rename from src/components/QueryTypesChart.js rename to src/components/dashboard/QueryTypesChart.js index 7a41536..04448c3 100644 --- a/src/components/QueryTypesChart.js +++ b/src/components/dashboard/QueryTypesChart.js @@ -10,7 +10,7 @@ import React from 'react'; import { translate } from 'react-i18next'; -import { api } from "../utils"; +import { api } from "../../utils"; import GenericDoughnutChart from "./GenericDoughnutChart"; const QueryTypesChart = ({ t }) => ( diff --git a/src/components/SummaryStats.js b/src/components/dashboard/SummaryStats.js similarity index 98% rename from src/components/SummaryStats.js rename to src/components/dashboard/SummaryStats.js index b97c233..c0cd9ff 100644 --- a/src/components/SummaryStats.js +++ b/src/components/dashboard/SummaryStats.js @@ -10,7 +10,7 @@ import React, { Component, Fragment } from 'react'; import { translate } from 'react-i18next'; -import { api, ignoreCancel, makeCancelable } from "../utils"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; class SummaryStats extends Component { state = { diff --git a/src/components/SummaryStats.test.js b/src/components/dashboard/SummaryStats.test.js similarity index 100% rename from src/components/SummaryStats.test.js rename to src/components/dashboard/SummaryStats.test.js diff --git a/src/components/TopBlocked.js b/src/components/dashboard/TopBlocked.js similarity index 98% rename from src/components/TopBlocked.js rename to src/components/dashboard/TopBlocked.js index db611a4..ce92206 100644 --- a/src/components/TopBlocked.js +++ b/src/components/dashboard/TopBlocked.js @@ -10,7 +10,7 @@ import React from "react"; import { translate } from "react-i18next"; -import { api } from "../utils"; +import { api } from "../../utils"; import TopTable from "./TopTable"; const TopBlocked = ({ t, ...props }) => ( diff --git a/src/components/TopBlocked.test.js b/src/components/dashboard/TopBlocked.test.js similarity index 100% rename from src/components/TopBlocked.test.js rename to src/components/dashboard/TopBlocked.test.js diff --git a/src/components/TopClients.js b/src/components/dashboard/TopClients.js similarity index 98% rename from src/components/TopClients.js rename to src/components/dashboard/TopClients.js index a769d41..493c487 100644 --- a/src/components/TopClients.js +++ b/src/components/dashboard/TopClients.js @@ -10,7 +10,7 @@ import React from "react"; import { translate } from "react-i18next"; -import { api } from "../utils"; +import { api } from "../../utils"; import TopTable from "./TopTable"; const TopClients = ({ t, ...props }) => ( diff --git a/src/components/TopClients.test.js b/src/components/dashboard/TopClients.test.js similarity index 100% rename from src/components/TopClients.test.js rename to src/components/dashboard/TopClients.test.js diff --git a/src/components/TopDomains.js b/src/components/dashboard/TopDomains.js similarity index 98% rename from src/components/TopDomains.js rename to src/components/dashboard/TopDomains.js index 3273a10..db6dc06 100644 --- a/src/components/TopDomains.js +++ b/src/components/dashboard/TopDomains.js @@ -10,7 +10,7 @@ import React from "react"; import { translate } from "react-i18next"; -import { api } from "../utils"; +import { api } from "../../utils"; import TopTable from "./TopTable"; const TopDomains = ({ t, ...props }) => ( diff --git a/src/components/TopDomains.test.js b/src/components/dashboard/TopDomains.test.js similarity index 100% rename from src/components/TopDomains.test.js rename to src/components/dashboard/TopDomains.test.js diff --git a/src/components/TopTable.js b/src/components/dashboard/TopTable.js similarity index 97% rename from src/components/TopTable.js rename to src/components/dashboard/TopTable.js index e99c703..1bda899 100644 --- a/src/components/TopTable.js +++ b/src/components/dashboard/TopTable.js @@ -10,7 +10,7 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; -import { ignoreCancel, makeCancelable } from "../utils"; +import { ignoreCancel, makeCancelable } from "../../utils"; class TopTable extends Component { state = { diff --git a/src/components/TopTable.test.js b/src/components/dashboard/TopTable.test.js similarity index 100% rename from src/components/TopTable.test.js rename to src/components/dashboard/TopTable.test.js diff --git a/src/components/DomainInput.js b/src/components/list/DomainInput.js similarity index 98% rename from src/components/DomainInput.js rename to src/components/list/DomainInput.js index 025539b..4b357fe 100644 --- a/src/components/DomainInput.js +++ b/src/components/list/DomainInput.js @@ -11,7 +11,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { translate } from 'react-i18next'; -import { api } from "../utils"; +import { api } from "../../utils"; class DomainInput extends Component { state = { diff --git a/src/components/DomainInput.test.js b/src/components/list/DomainInput.test.js similarity index 98% rename from src/components/DomainInput.test.js rename to src/components/list/DomainInput.test.js index 78b4afe..38debeb 100644 --- a/src/components/DomainInput.test.js +++ b/src/components/list/DomainInput.test.js @@ -11,7 +11,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import DomainInput from './DomainInput'; -import { api } from "../utils"; +import { api } from "../../utils"; it('has a placeholder', () => { const placeholder = 'placeholder'; diff --git a/src/components/DomainList.js b/src/components/list/DomainList.js similarity index 97% rename from src/components/DomainList.js rename to src/components/list/DomainList.js index cf01964..a6260ff 100644 --- a/src/components/DomainList.js +++ b/src/components/list/DomainList.js @@ -11,7 +11,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { translate } from 'react-i18next'; -import { api, ignoreCancel, makeCancelable } from "../utils"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; class DomainList extends Component { onRemove(domain) { diff --git a/src/components/DomainList.test.js b/src/components/list/DomainList.test.js similarity index 98% rename from src/components/DomainList.test.js rename to src/components/list/DomainList.test.js index 765f490..75e5b34 100644 --- a/src/components/DomainList.test.js +++ b/src/components/list/DomainList.test.js @@ -11,7 +11,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import DomainList from './DomainList'; -import { api } from "../utils"; +import { api } from "../../utils"; const domains = [ 'domain1.com', diff --git a/src/components/ListPage.js b/src/components/list/ListPage.js similarity index 96% rename from src/components/ListPage.js rename to src/components/list/ListPage.js index 8699975..5049093 100644 --- a/src/components/ListPage.js +++ b/src/components/list/ListPage.js @@ -12,9 +12,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { translate } from 'react-i18next'; import DomainInput from "./DomainInput"; -import Alert from "./Alert"; +import Alert from "../common/Alert"; import DomainList from "./DomainList"; -import { ignoreCancel, makeCancelable } from "../utils"; +import { ignoreCancel, makeCancelable } from "../../utils"; class ListPage extends Component { state = { @@ -150,7 +150,7 @@ class ListPage extends Component { ListPage.propTypes = { title: PropTypes.string.isRequired, - note: PropTypes.object, + note: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), placeholder: PropTypes.string.isRequired, add: PropTypes.func.isRequired, refresh: PropTypes.func.isRequired, diff --git a/src/components/ListPage.test.js b/src/components/list/ListPage.test.js similarity index 100% rename from src/components/ListPage.test.js rename to src/components/list/ListPage.test.js diff --git a/src/components/QueryLog.js b/src/components/log/QueryLog.js similarity index 99% rename from src/components/QueryLog.js rename to src/components/log/QueryLog.js index 38a247f..723be74 100644 --- a/src/components/QueryLog.js +++ b/src/components/log/QueryLog.js @@ -11,7 +11,7 @@ import React, { Component } from 'react'; import ReactTable from 'react-table'; import { translate } from 'react-i18next'; -import { api, ignoreCancel, makeCancelable, padNumber } from '../utils'; +import { api, ignoreCancel, makeCancelable, padNumber } from '../../utils'; import 'react-table/react-table.css'; class QueryLog extends Component { diff --git a/src/components/ForgotPassword.js b/src/components/login/ForgotPassword.js similarity index 100% rename from src/components/ForgotPassword.js rename to src/components/login/ForgotPassword.js diff --git a/src/components/ForgotPassword.test.js b/src/components/login/ForgotPassword.test.js similarity index 100% rename from src/components/ForgotPassword.test.js rename to src/components/login/ForgotPassword.test.js diff --git a/src/components/DHCPInfo.js b/src/components/settings/DHCPInfo.js similarity index 66% rename from src/components/DHCPInfo.js rename to src/components/settings/DHCPInfo.js index bf43573..cdb2f68 100644 --- a/src/components/DHCPInfo.js +++ b/src/components/settings/DHCPInfo.js @@ -10,7 +10,7 @@ import React, { Component } from "react"; import { translate } from "react-i18next"; -import { api, ignoreCancel, makeCancelable } from "../utils"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; class DHCPInfo extends Component { state = { @@ -67,25 +67,15 @@ class DHCPInfo extends Component { const { t } = this.props; return ( -
-
-
- -
-
-
-

{t("DHCP")}

-
-            {t("DHCP Active")}: {this.state.active.toString()}
- {t("Start IP")}: {this.state.ip_start}
- {t("End IP")}: {this.state.ip_end}
- {t("Router IP")}: {this.state.router_ip}
- {t("Lease Time")}: {this.state.lease_time} h
- {t("Domain")}: {this.state.domain}
- {t("IPv6 Support")}: {this.state.ipv6_support.toString()}
-
-
-
+
+        {t("DHCP Active")}: {this.state.active.toString()}
+ {t("Start IP")}: {this.state.ip_start}
+ {t("End IP")}: {this.state.ip_end}
+ {t("Router IP")}: {this.state.router_ip}
+ {t("Lease Time")}: {this.state.lease_time} h
+ {t("Domain")}: {this.state.domain}
+ {t("IPv6 Support")}: {this.state.ipv6_support.toString()}
+
); } } diff --git a/src/components/DNSInfo.js b/src/components/settings/DNSInfo.js similarity index 51% rename from src/components/DNSInfo.js rename to src/components/settings/DNSInfo.js index 338ca98..a977ca9 100644 --- a/src/components/DNSInfo.js +++ b/src/components/settings/DNSInfo.js @@ -10,7 +10,7 @@ import React, { Component } from "react"; import { translate } from "react-i18next"; -import { api, ignoreCancel, makeCancelable } from "../utils"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; class DNSInfo extends Component { state = { @@ -69,41 +69,31 @@ class DNSInfo extends Component { const { t } = this.props; return ( -
-
-
- -
+
+
+
+            
+ {t("Upstream DNS Servers")}:
+ {this.state.upstream_dns.map(item => item + "\n")}
+
-
-

{t("DNS")}

-
-
-
-                
- {t("Upstream DNS Servers")}:
- {this.state.upstream_dns.map(item => item + "\n")}
-
-
-
-
-                
- {t("Interface listening behaviour")}: {this.state.options.listening_type}
- {t("Forward FQDNs only")}: {this.state.options.fqdn_required.toString()}
- {t("Only forward public reverse lookups")}:{this.state.options.bogus_priv.toString()}
- {t("Use DNSSEC")}: {this.state.options.dnssec.toString()} -
-
-
-
-                
- {t("Conditional Forwarding")}
- {t("Enabled")}: {this.state.conditional_forwarding.enabled.toString()}
- {t("Router IP")}: {this.state.conditional_forwarding.router_ip.toString()}
- {t("Local Domain Name")}: {this.state.conditional_forwarding.domain.toString()}
-
-
-
+
+
+            
+ {t("Interface listening behavior")}: {this.state.options.listening_type}
+ {t("Forward FQDNs only")}: {this.state.options.fqdn_required.toString()}
+ {t("Only forward public reverse lookups")}:{this.state.options.bogus_priv.toString()}
+ {t("Use DNSSEC")}: {this.state.options.dnssec.toString()} +
+
+
+
+            
+ {t("Conditional Forwarding")}
+ {t("Enabled")}: {this.state.conditional_forwarding.enabled.toString()}
+ {t("Router IP")}: {this.state.conditional_forwarding.router_ip.toString()}
+ {t("Local Domain Name")}: {this.state.conditional_forwarding.domain.toString()}
+
); diff --git a/src/components/FTLInfo.js b/src/components/settings/FTLInfo.js similarity index 69% rename from src/components/FTLInfo.js rename to src/components/settings/FTLInfo.js index 9013b4e..a332817 100644 --- a/src/components/FTLInfo.js +++ b/src/components/settings/FTLInfo.js @@ -10,7 +10,7 @@ import React, { Component } from "react"; import { translate } from "react-i18next"; -import { api, ignoreCancel, makeCancelable } from "../utils"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; class FTLInfo extends Component { state = { @@ -56,23 +56,11 @@ class FTLInfo extends Component { const { t } = this.props; return ( -
-
-
- -
-
-
-

- {t("FTL Database")} -

-
-            {t("Queries")}: {this.state.queries}
- {t("Filesize")}: {this.state.filesize} B
- {t("SQLite version")}: {this.state.sqlite_version}
-
-
-
+
+        {t("Queries")}: {this.state.queries}
+ {t("Filesize")}: {this.state.filesize} B
+ {t("SQLite version")}: {this.state.sqlite_version}
+
); } } diff --git a/src/components/NetworkInfo.js b/src/components/settings/NetworkInfo.js similarity index 53% rename from src/components/NetworkInfo.js rename to src/components/settings/NetworkInfo.js index 82b04d7..7f78b58 100644 --- a/src/components/NetworkInfo.js +++ b/src/components/settings/NetworkInfo.js @@ -8,9 +8,10 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -import React, { Component } from "react"; +import React, { Component, Fragment } from "react"; import { translate } from "react-i18next"; -import { api, ignoreCancel, makeCancelable } from "../utils"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; +import { Col, Form, FormGroup, Input, Label } from "reactstrap"; class NetworkInfo extends Component { state = { @@ -58,22 +59,34 @@ class NetworkInfo extends Component { const { t } = this.props; return ( -
-
-
- -
-
-
-

{t("Network")}

-
-            {t("Interface")}: {this.state.interface}
- {t("IPv4 address")}: {this.state.ipv4_address}
- {t("IPv6 address")}: {this.state.ipv6_address}
- {t("Hostname")}: {this.state.hostname} -
-
-
+ +
+ + + + {this.state.interface} + + + + + + {this.state.ipv4_address} + + + + + + {this.state.ipv6_address} + + + + + + {this.state.hostname} + + +
+
); } } diff --git a/src/components/settings/VersionCard.js b/src/components/settings/VersionCard.js new file mode 100644 index 0000000..213c70b --- /dev/null +++ b/src/components/settings/VersionCard.js @@ -0,0 +1,73 @@ +/* Pi-hole: A black hole for Internet advertisements +* (c) 2017 Pi-hole, LLC (https://pi-hole.net) +* Network-wide ad blocking via your own hardware. +* +* Web Interface +* Settings :: Version - Card component +* +* This file is copyright under the latest version of the EUPL. +* Please see LICENSE file for your rights under this license. */ + +import React, { Component } from "react"; +import { translate } from "react-i18next"; +import PropTypes from "prop-types"; +import { Collapse } from "reactstrap"; + +class VersionCard extends Component { + state = { + collapsed: true + }; + + render() { + const { t } = this.props; + + return ( +
+
+
+ +
+
+
+

{this.props.name}

+

+ {t("Version")}: {this.props.branch === "master" ? this.props.tag : "vDev"} +

+ + + + + + + + + + + + + + + + + +
{t("Branch")}{this.props.branch}
{t("Tag")}{this.props.tag}
{t("Hash")}{this.props.hash}
+
+
+
+ ); + } +} + +VersionCard.propTypes = { + branch: PropTypes.string.isRequired, + hash: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + tag: PropTypes.string.isRequired +}; + +export default translate(["common", "settings"])(VersionCard); diff --git a/src/components/VersionInfo.js b/src/components/settings/VersionInfo.js similarity index 89% rename from src/components/VersionInfo.js rename to src/components/settings/VersionInfo.js index b30ec10..cf27e51 100644 --- a/src/components/VersionInfo.js +++ b/src/components/settings/VersionInfo.js @@ -10,8 +10,8 @@ import React, { Component } from "react"; import { translate } from "react-i18next"; -import { api, ignoreCancel, makeCancelable } from "../utils"; -import VersionCard from "../components/VersionCard"; +import { api, ignoreCancel, makeCancelable } from "../../utils"; +import VersionCard from "./VersionCard"; class VersionInfo extends Component { state = { @@ -87,19 +87,19 @@ class VersionInfo extends Component { return (
-
+
-
+
-
+
-
+
diff --git a/src/containers/Full.js b/src/containers/Full.js index ac4506e..3b96f8c 100644 --- a/src/containers/Full.js +++ b/src/containers/Full.js @@ -10,18 +10,9 @@ import React from 'react'; import { Switch, Route, Redirect } from 'react-router-dom' -import Header, { mobileSidebarHide } from '../components/Header'; -import Sidebar from '../components/Sidebar'; -import Footer from '../components/Footer'; -import Dashboard from '../views/Dashboard'; -import QueryLog from '../components/QueryLog'; -import Whitelist from "../views/Whitelist"; -import Blacklist from "../views/Blacklist"; -import Regexlist from "../views/Regexlist"; -import Versions from "../views/Versions"; -import Networking from "../views/Networking"; -import Login from "../views/Login"; -import Logout from "../views/Logout"; +import Header, { mobileSidebarHide } from '../components/common/Header'; +import Sidebar from '../components/common/Sidebar'; +import Footer from '../components/common/Footer'; import { api } from "../utils"; import { nav } from "../routes"; @@ -33,16 +24,8 @@ export default props => (
- - - - - - - - - + {nav.map(createRoute)}
@@ -51,6 +34,22 @@ export default props => (
); +/** + * Create a route from the route data. + * If the route has children, an array of routes will be returned. + * + * @param routeData the route data (see routes.js) + */ +const createRoute = routeData => { + if(routeData.children) { + return routeData.children.map(createRoute); + } + + return routeData.auth + ? + : ; +}; + /** * Create a route which requires authentication. * If the user is unauthenticated, they will be redirected to the login page. diff --git a/src/i18n.js b/src/i18n.js index 025b51b..7069032 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -13,7 +13,7 @@ export function setupI18n() { fallbackLng: "en", ns: ['common'], defaultNS: "common", - fallbackNS: ['dashboard', 'footer', 'lists', 'location', 'login', 'query-log'], + fallbackNS: ["dashboard", "footer", "lists", "location", "login", "query-log", "settings"], nsSeparator: false, keySeparator: false, debug: config.developmentMode, diff --git a/src/index.js b/src/index.js index 396f4a0..01ff80a 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { HashRouter, Route, Switch } from 'react-router-dom' +import { BrowserRouter, Route, Switch } from 'react-router-dom' import "ionicons/dist/css/ionicons.min.css"; import "font-awesome/css/font-awesome.min.css"; import "simple-line-icons/css/simple-line-icons.css"; @@ -28,11 +28,11 @@ setupI18n(); ReactDOM.render( ( - + - + ), document.getElementById('root') ); diff --git a/src/routes.js b/src/routes.js index ca8fc76..9165897 100644 --- a/src/routes.js +++ b/src/routes.js @@ -8,6 +8,16 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ +import Dashboard from "./views/Dashboard"; +import QueryLog from "./components/log/QueryLog"; +import Whitelist from "./views/Whitelist"; +import Blacklist from "./views/Blacklist"; +import Regexlist from "./views/Regexlist"; +import Versions from "./views/Versions"; +import Networking from "./views/Networking"; +import Login from "./views/Login"; +import Logout from "./views/Logout"; + export const routes = t => ({ '/dashboard': t('Dashboard'), '/query-log': t('Query Log'), @@ -24,18 +34,21 @@ export const nav = [ { name: 'Dashboard', url: '/dashboard', + component: Dashboard, icon: 'fa fa-dashboard', auth: false }, { name: 'Query Log', url: '/query-log', + component: QueryLog, icon: 'fa fa-database', auth: true }, { name: 'Whitelist', url: '/whitelist', + component: Whitelist, icon: 'fa fa-check-circle-o', auth: false }, @@ -48,12 +61,14 @@ export const nav = [ { name: 'Exact', url: '/blacklist/exact', + component: Blacklist, icon: 'fa fa-ban', auth: false }, { name: 'Regex', url: '/blacklist/regex', + component: Regexlist, icon: 'fa fa-ban', auth: false } @@ -68,12 +83,14 @@ export const nav = [ { name: 'Versions', url: '/settings/versions', + component: Versions, icon: 'fa fa-download', auth: true }, { name: 'Networking', url: '/settings/networking', + component: Networking, icon: 'fa fa-sitemap', auth: true, } @@ -82,6 +99,7 @@ export const nav = [ { name: 'Login', url: '/login', + component: Login, icon: 'fa fa-user', auth: false, authStrict: true @@ -89,6 +107,7 @@ export const nav = [ { name: 'Logout', url: '/logout', + component: Logout, icon: 'fa fa-user-times', auth: true, authStrict: true diff --git a/src/scss/_custom.scss b/src/scss/_custom.scss index e460f4e..950615d 100644 --- a/src/scss/_custom.scss +++ b/src/scss/_custom.scss @@ -113,6 +113,10 @@ text-decoration: line-through !important; } +.bold { + font-weight: bold; +} + .background-image { background: url("../img/backgroundLight.png") repeat fixed; } diff --git a/src/views/Blacklist.js b/src/views/Blacklist.js index 3ebc757..8c07571 100644 --- a/src/views/Blacklist.js +++ b/src/views/Blacklist.js @@ -11,7 +11,7 @@ import React from 'react'; import { translate } from 'react-i18next'; import { api } from "../utils"; -import ListPage from "../components/ListPage"; +import ListPage from "../components/list/ListPage"; const Blacklist = props => { const { t } = props; diff --git a/src/views/Dashboard.js b/src/views/Dashboard.js index 4928138..5a625b7 100644 --- a/src/views/Dashboard.js +++ b/src/views/Dashboard.js @@ -9,14 +9,14 @@ * Please see LICENSE file for your rights under this license. */ import React, { Fragment } from 'react'; -import SummaryStats from '../components/SummaryStats'; -import QueriesGraph from '../components/QueriesGraph'; -import ClientsGraph from '../components/ClientsGraph'; -import QueryTypesChart from "../components/QueryTypesChart"; -import ForwardDestinationsChart from "../components/ForwardDestinationsChart"; -import TopDomains from '../components/TopDomains'; -import TopBlocked from '../components/TopBlocked'; -import TopClients from '../components/TopClients'; +import SummaryStats from '../components/dashboard/SummaryStats'; +import QueriesGraph from '../components/dashboard/QueriesGraph'; +import ClientsGraph from '../components/dashboard/ClientsGraph'; +import QueryTypesChart from "../components/dashboard/QueryTypesChart"; +import ForwardDestinationsChart from "../components/dashboard/ForwardDestinationsChart"; +import TopDomains from '../components/dashboard/TopDomains'; +import TopBlocked from '../components/dashboard/TopBlocked'; +import TopClients from '../components/dashboard/TopClients'; import { api } from "../utils"; export default () => ( diff --git a/src/views/Login.js b/src/views/Login.js index a676967..c00666d 100644 --- a/src/views/Login.js +++ b/src/views/Login.js @@ -8,18 +8,19 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -import React, { Component, Fragment } from 'react'; -import { Redirect } from 'react-router-dom'; -import sha from 'sha.js'; +import React, { Component, Fragment } from "react"; +import { Redirect } from "react-router-dom"; +import sha from "sha.js"; import { api } from "../utils"; -import logo from '../img/logo.svg'; +import logo from "../img/logo.svg"; import { routes } from "../routes"; -import ForgotPassword from "../components/ForgotPassword"; -import { translate } from 'react-i18next'; +import ForgotPassword from "../components/login/ForgotPassword"; +import { translate } from "react-i18next"; +import config from "../config"; class Login extends Component { state = { - password: '', + password: "", error: false, cookiesEnabled: false }; @@ -41,19 +42,22 @@ class Login extends Component { if(e.keyCode === 13) this.authenticate(); else - this.setState({ password: e.target.value }) + this.setState({ password: e.target.value }); }; /** * Try to authenticate the user */ - authenticate = () => { + authenticate = e => { + // Prevent the page from reloading when the user gets redirected + e.preventDefault(); + // Hash the password twice before sending to the API let hashedPassword = sha("sha256").update(this.state.password).digest("hex"); hashedPassword = sha("sha256").update(hashedPassword).digest("hex"); // Clear the state - this.setState({ password: '', error: false }); + this.setState({ password: "", error: false }); // Send the password to the API to authenticate the user api.authenticate(hashedPassword) @@ -67,9 +71,14 @@ class Login extends Component { api.loggedIn = true; + if(config.fakeAPI) { + // When using the fake API, set the cookie ourselves + document.cookie = "user_id=;"; + } + // Redirect to the page the user was originally going to, or if that doesn't exist, go to home - const redirect = this.props.location.state.from || '/'; - this.props.history.push(redirect); + const locationState = this.props.location.state || "/"; + this.props.history.push(locationState.from.pathname); }) // If there was an error, tell the user they used the wrong password .catch(() => this.setState({ error: true })); @@ -83,16 +92,16 @@ class Login extends Component { const { t } = this.props; return ( -
+
-
+
Logo

-
- +
+ Pi-hole
@@ -106,7 +115,7 @@ class Login extends Component {
{t( - "You will be transferred to the {{page}}", + "You will be transferred to the \"{{page}}\" page", { page: routes(t)[this.props.location.state.from.pathname] } )}
@@ -115,7 +124,7 @@ class Login extends Component { { // If cookies are not enabled (or detected), show a warning !this.state.cookiesEnabled ? -
+
{t("Verify that cookies are allowed for {{host}}", { host: window.location.host })}
: null @@ -135,7 +144,7 @@ class Login extends Component {
-
+
diff --git a/src/views/Logout.js b/src/views/Logout.js index 90244b5..eddda78 100644 --- a/src/views/Logout.js +++ b/src/views/Logout.js @@ -11,11 +11,19 @@ import React, { Component } from 'react'; import { Redirect } from 'react-router-dom'; import { api } from "../utils"; +import config from "../config"; export default class Logout extends Component { componentWillMount() { api.loggedIn = false; - api.logout(); + + if(config.fakeAPI) { + // When using the fake API, don't try deleting the resource + // (it results in an error). Instead, delete the cookie. + document.cookie = 'user_id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + } else { + api.logout(); + } } render() { diff --git a/src/views/Networking.js b/src/views/Networking.js index e528398..80547ac 100644 --- a/src/views/Networking.js +++ b/src/views/Networking.js @@ -8,30 +8,78 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -import React from 'react'; +import React, { Component } from "react"; +import { translate } from "react-i18next"; +import { Nav, NavItem, NavLink, TabContent, TabPane } from "reactstrap"; +import DHCPInfo from "../components/settings/DHCPInfo"; +import DNSInfo from "../components/settings/DNSInfo"; +import NetworkInfo from "../components/settings/NetworkInfo"; +import FTLInfo from "../components/settings/FTLInfo"; -import DHCPInfo from '../components/DHCPInfo'; -import DNSInfo from '../components/DNSInfo'; -import NetworkInfo from '../components/NetworkInfo'; -import FTLInfo from '../components/FTLInfo'; +class Networking extends Component { + state = { + activeTab: "network" + }; -export default () => ( -
-
-
-
- -
-
- -
-
- -
-
- -
+ /** + * Set the active tab to the input + * + * @param tab the tab ID to switch to + */ + setTab = tab => { + if(this.state.activeTab !== tab) { + this.setState({ + activeTab: tab + }); + } + }; + + /** + * Create a navigation tab + * + * @param id the tab's ID + * @param name the tab's display name + * @returns {NavItem} the tab component + */ + tab = (id, name) => ( + + this.setTab(id)}> + {name} + + + ); + + /** + * Create tab content + * + * @param id the tab's ID + * @param component the component to render in the tab + * @returns {TabPane} the tab content component + */ + tabContent = (id, component) => ( + {component} + ); + + render() { + const { t } = this.props; + + return ( +
+ + + {this.tabContent("network", )} + {this.tabContent("dhcp", )} + {this.tabContent("dns", )} + {this.tabContent("ftl", )} +
-
-
-); + ); + } +} + +export default translate(["common", "settings"])(Networking); diff --git a/src/views/Regexlist.js b/src/views/Regexlist.js index 26c8f9c..d88a444 100644 --- a/src/views/Regexlist.js +++ b/src/views/Regexlist.js @@ -10,7 +10,7 @@ import React from 'react'; import { translate } from 'react-i18next'; -import ListPage from "../components/ListPage"; +import ListPage from "../components/list/ListPage"; import { api } from "../utils"; const Regexlist = props => { diff --git a/src/views/Versions.js b/src/views/Versions.js index 952b706..1f2e993 100644 --- a/src/views/Versions.js +++ b/src/views/Versions.js @@ -9,7 +9,7 @@ * Please see LICENSE file for your rights under this license. */ import React from 'react'; -import VersionInfo from '../components/VersionInfo'; +import VersionInfo from '../components/settings/VersionInfo'; export default () => (
diff --git a/src/views/Whitelist.js b/src/views/Whitelist.js index f445d16..f27f321 100644 --- a/src/views/Whitelist.js +++ b/src/views/Whitelist.js @@ -10,7 +10,7 @@ import React from 'react'; import { translate } from 'react-i18next'; -import ListPage from "../components/ListPage"; +import ListPage from "../components/list/ListPage"; import { api } from "../utils"; const Whitelist = props => {