mirror of
https://github.com/gosticks/web.git
synced 2026-10-06 22:57:01 +00:00
Merge branch 'development' into optimize-image
This commit is contained in:
@@ -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" }}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Details": "Детайли / детайли",
|
||||
"Status": "Статус / статус",
|
||||
"DNS": "DNS / ДНС",
|
||||
"Donate": "Дарят",
|
||||
|
||||
@@ -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}}": "Уверете се, че бисквитките са разрешени за {{хост}}"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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í"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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}}"
|
||||
}
|
||||
@@ -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)"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -7,5 +7,8 @@
|
||||
"Wildcard": "Wildcard",
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"Regex": "Regex"
|
||||
"Regex": "Regex",
|
||||
"Settings": "Settings",
|
||||
"Networking": "Networking",
|
||||
"Versions": "Versions"
|
||||
}
|
||||
@@ -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}}"
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Details": "Detalles",
|
||||
"Status": "Estado",
|
||||
"DNS": "DNS",
|
||||
"Donate": "Donar",
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Details": "Detalhes",
|
||||
"Status": "Status",
|
||||
"DNS": "DNS",
|
||||
"Donate": "Doar",
|
||||
|
||||
@@ -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}}"
|
||||
}
|
||||
@@ -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 => (
|
||||
<div className="card border-0 bg-primary stat-mid-height-lock">
|
||||
<div className="card-block">
|
||||
<div className="card-icon">
|
||||
<i className={props.icon}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-img-overlay">
|
||||
<h3>{props.name}</h3>
|
||||
<pre>
|
||||
<br/>
|
||||
{props.t("Branch")}: {props.branch}<br/>
|
||||
{props.t("Hash")}: {props.hash}<br/>
|
||||
{props.t("Tag")}: {props.tag}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
VersionCard.propTypes = {
|
||||
branch: PropTypes.string.isRequired,
|
||||
hash: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
tag: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default translate(['settings'])(VersionCard);
|
||||
@@ -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")}
|
||||
</p>
|
||||
<br/>
|
||||
<span style={{ textTransform: "initial", paddingLeft: "15px" }}>
|
||||
@@ -84,4 +84,4 @@ const Sidebar = ({ items, ...props }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default translate("location")(Sidebar);
|
||||
export default translate(["common", "location"])(Sidebar);
|
||||
@@ -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" } });
|
||||
@@ -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 = {
|
||||
@@ -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 {
|
||||
+1
-1
@@ -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 }) => (
|
||||
+1
-1
@@ -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 = {
|
||||
@@ -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 = {
|
||||
@@ -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 }) => (
|
||||
@@ -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 = {
|
||||
@@ -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 }) => (
|
||||
@@ -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 }) => (
|
||||
@@ -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 }) => (
|
||||
@@ -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 = {
|
||||
@@ -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 = {
|
||||
@@ -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';
|
||||
@@ -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) {
|
||||
@@ -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',
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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 (
|
||||
<div className="card border-0 bg-success stat-dbl-height-lock">
|
||||
<div className="card-body">
|
||||
<div className="card-icon">
|
||||
<i className="fa fa-cogs fa-2x"/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-img-overlay">
|
||||
<h3>{t("DHCP")}</h3>
|
||||
<pre>
|
||||
{t("DHCP Active")}: {this.state.active.toString()}<br/>
|
||||
{t("Start IP")}: {this.state.ip_start}<br/>
|
||||
{t("End IP")}: {this.state.ip_end}<br/>
|
||||
{t("Router IP")}: {this.state.router_ip}<br/>
|
||||
{t("Lease Time")}: {this.state.lease_time} h<br/>
|
||||
{t("Domain")}: {this.state.domain}<br/>
|
||||
{t("IPv6 Support")}: {this.state.ipv6_support.toString()}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
{t("DHCP Active")}: {this.state.active.toString()}<br/>
|
||||
{t("Start IP")}: {this.state.ip_start}<br/>
|
||||
{t("End IP")}: {this.state.ip_end}<br/>
|
||||
{t("Router IP")}: {this.state.router_ip}<br/>
|
||||
{t("Lease Time")}: {this.state.lease_time} h<br/>
|
||||
{t("Domain")}: {this.state.domain}<br/>
|
||||
{t("IPv6 Support")}: {this.state.ipv6_support.toString()}<br/>
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 (
|
||||
<div className="card border-0 bg-success stat-dbl-height-lock">
|
||||
<div className="card-body">
|
||||
<div className="card-icon">
|
||||
<i className="fa fa-binoculars fa-2x"/>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-lg-4 col-sm-4 col-xs-4">
|
||||
<pre>
|
||||
<br/>
|
||||
{t("Upstream DNS Servers")}:<br/>
|
||||
{this.state.upstream_dns.map(item => item + "\n")}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
<div className="card-img-overlay">
|
||||
<h3>{t("DNS")}</h3>
|
||||
<div className="row">
|
||||
<div className="col-lg-4 col-sm-4 col-xs-4">
|
||||
<pre>
|
||||
<br/>
|
||||
{t("Upstream DNS Servers")}:<br/>
|
||||
{this.state.upstream_dns.map(item => item + "\n")}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
<div className="col-lg-4 col-sm-4 col-xs-4">
|
||||
<pre>
|
||||
<br/>
|
||||
{t("Interface listening behaviour")}: {this.state.options.listening_type}<br/>
|
||||
{t("Forward FQDNs only")}: {this.state.options.fqdn_required.toString()}<br/>
|
||||
{t("Only forward public reverse lookups")}:{this.state.options.bogus_priv.toString()}<br/>
|
||||
{t("Use DNSSEC")}: {this.state.options.dnssec.toString()}
|
||||
</pre>
|
||||
</div>
|
||||
<div className="col-lg-4 col-sm-4 col-xs-4">
|
||||
<pre>
|
||||
<br/>
|
||||
{t("Conditional Forwarding")}<br/>
|
||||
{t("Enabled")}: {this.state.conditional_forwarding.enabled.toString()}<br/>
|
||||
{t("Router IP")}: {this.state.conditional_forwarding.router_ip.toString()}<br/>
|
||||
{t("Local Domain Name")}: {this.state.conditional_forwarding.domain.toString()}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-4 col-sm-4 col-xs-4">
|
||||
<pre>
|
||||
<br/>
|
||||
{t("Interface listening behavior")}: {this.state.options.listening_type}<br/>
|
||||
{t("Forward FQDNs only")}: {this.state.options.fqdn_required.toString()}<br/>
|
||||
{t("Only forward public reverse lookups")}:{this.state.options.bogus_priv.toString()}<br/>
|
||||
{t("Use DNSSEC")}: {this.state.options.dnssec.toString()}
|
||||
</pre>
|
||||
</div>
|
||||
<div className="col-lg-4 col-sm-4 col-xs-4">
|
||||
<pre>
|
||||
<br/>
|
||||
{t("Conditional Forwarding")}<br/>
|
||||
{t("Enabled")}: {this.state.conditional_forwarding.enabled.toString()}<br/>
|
||||
{t("Router IP")}: {this.state.conditional_forwarding.router_ip.toString()}<br/>
|
||||
{t("Local Domain Name")}: {this.state.conditional_forwarding.domain.toString()}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -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 (
|
||||
<div className="card border-0 bg-success stat-dbl-height-lock">
|
||||
<div className="card-block">
|
||||
<div className="card-icon">
|
||||
<i className="fa fa-database fa-2x"/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-img-overlay">
|
||||
<h3>
|
||||
{t("FTL Database")}
|
||||
</h3>
|
||||
<pre>
|
||||
{t("Queries")}: {this.state.queries}<br/>
|
||||
{t("Filesize")}: {this.state.filesize} B<br/>
|
||||
{t("SQLite version")}: {this.state.sqlite_version}<br/>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
{t("Queries")}: {this.state.queries}<br/>
|
||||
{t("Filesize")}: {this.state.filesize} B<br/>
|
||||
{t("SQLite version")}: {this.state.sqlite_version}<br/>
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 (
|
||||
<div className="card border-0 bg-success stat-dbl-height-lock">
|
||||
<div className="card-block">
|
||||
<div className="card-icon">
|
||||
<i className="fa fa-sitemap fa-2x"/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-img-overlay">
|
||||
<h3>{t("Network")}</h3>
|
||||
<pre>
|
||||
{t("Interface")}: {this.state.interface}<br/>
|
||||
{t("IPv4 address")}: {this.state.ipv4_address}<br/>
|
||||
{t("IPv6 address")}: {this.state.ipv6_address}<br/>
|
||||
{t("Hostname")}: {this.state.hostname}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<Fragment>
|
||||
<Form>
|
||||
<FormGroup row>
|
||||
<Label className="bold" for="interface" sm={4}>{t("Interface")}</Label>
|
||||
<Col sm={8}>
|
||||
<Input plaintext id="interface">{this.state.interface}</Input>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
<FormGroup row>
|
||||
<Label className="bold" for="ipv4_address" sm={4}>{t("IPv4 address")}</Label>
|
||||
<Col sm={8}>
|
||||
<Input plaintext id="ipv4_address">{this.state.ipv4_address}</Input>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
<FormGroup row>
|
||||
<Label className="bold" for="ipv6_address" sm={4}>{t("IPv6 address")}</Label>
|
||||
<Col sm={8}>
|
||||
<Input plaintext id="ipv6_address">{this.state.ipv6_address}</Input>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
<FormGroup row>
|
||||
<Label className="bold" for="hostname" sm={4}>{t("Hostname")}</Label>
|
||||
<Col sm={8}>
|
||||
<Input plaintext id="hostname">{this.state.hostname}</Input>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 (
|
||||
<div className="card border-0 bg-primary">
|
||||
<div className="card-block">
|
||||
<div className="card-icon">
|
||||
<i className={this.props.icon}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<h3>{this.props.name}</h3>
|
||||
<p>
|
||||
{t("Version")}: {this.props.branch === "master" ? this.props.tag : "vDev"}
|
||||
</p>
|
||||
<button className="btn btn-secondary"
|
||||
type="button"
|
||||
onClick={() => this.setState({ collapsed: !this.state.collapsed })}>
|
||||
{t("Details")}
|
||||
</button>
|
||||
<Collapse isOpen={!this.state.collapsed}>
|
||||
<table className="table table-borderless table-sm table-condensed"
|
||||
style={{ marginTop: "1rem", marginBottom: "0" }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{t("Branch")}</td>
|
||||
<td>{this.props.branch}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("Tag")}</td>
|
||||
<td>{this.props.tag}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("Hash")}</td>
|
||||
<td>{this.props.hash}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
VersionCard.propTypes = {
|
||||
branch: PropTypes.string.isRequired,
|
||||
hash: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
tag: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default translate(["common", "settings"])(VersionCard);
|
||||
@@ -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 (
|
||||
<div className="row">
|
||||
<div className="col-lg-3 col-xs-12">
|
||||
<div className="col-xl-3 col-md-6 col-xs-12">
|
||||
<VersionCard name={t("Core")} icon="fa fa-dot-circle-o fa-2x"
|
||||
branch={this.state.core.branch} hash={this.state.core.hash} tag={this.state.core.tag} t={t}/>
|
||||
</div>
|
||||
<div className="col-lg-3 col-xs-12">
|
||||
<div className="col-xl-3 col-md-6 col-xs-12">
|
||||
<VersionCard name={t("FTL")} icon="fa fa-industry fa-2x"
|
||||
branch={this.state.ftl.branch} hash={this.state.ftl.hash} tag={this.state.ftl.tag} t={t}/>
|
||||
</div>
|
||||
<div className="col-lg-3 col-xs-12">
|
||||
<div className="col-xl-3 col-md-6 col-xs-12">
|
||||
<VersionCard name={t("API")} icon="fa fa-bullseye fa-2x"
|
||||
branch={this.state.api.branch} hash={this.state.api.hash} tag={this.state.api.tag} t={t}/>
|
||||
</div>
|
||||
<div className="col-lg-3 col-xs-12">
|
||||
<div className="col-xl-3 col-md-6 col-xs-12">
|
||||
<VersionCard name={t("Web")} icon="fa fa-list-alt fa-2x"
|
||||
branch={this.state.web.branch} hash={this.state.web.hash} tag={this.state.web.tag} t={t}/>
|
||||
</div>
|
||||
+20
-21
@@ -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 => (
|
||||
<main className="main" onClick={mobileSidebarHide}>
|
||||
<div className="container-fluid" style={{"marginTop": "1.5rem"}}>
|
||||
<Switch>
|
||||
<Route path="/dashboard" name="Dashboard" component={Dashboard}/>
|
||||
<Redirect exact from="/" to="/dashboard"/>
|
||||
<AuthRoute path="/query-log" name="Query Log" component={QueryLog}/>
|
||||
<Route path="/whitelist" name="Whitelist" component={Whitelist}/>
|
||||
<Route path="/blacklist/exact" name="Blacklist" component={Blacklist}/>
|
||||
<Route path="/blacklist/regex" name="Regexlist" component={Regexlist}/>
|
||||
<Route path="/settings/versions" name="Versions" component={Versions}/>
|
||||
<Route path="/settings/networking" name="Networking" component={Networking}/>
|
||||
<Route path="/login" name="Login" component={Login}/>
|
||||
<AuthRoute path="/logout" name="Logout" component={Logout}/>
|
||||
{nav.map(createRoute)}
|
||||
</Switch>
|
||||
</div>
|
||||
</main>
|
||||
@@ -51,6 +34,22 @@ export default props => (
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* 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
|
||||
? <AuthRoute key={routeData.url} path={routeData.url} component={routeData.component}/>
|
||||
: <Route key={routeData.url} path={routeData.url} component={routeData.component}/>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a route which requires authentication.
|
||||
* If the user is unauthenticated, they will be redirected to the login page.
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+3
-3
@@ -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(
|
||||
(
|
||||
<HashRouter>
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route path="/" name="Home" component={Full}/>
|
||||
</Switch>
|
||||
</HashRouter>
|
||||
</BrowserRouter>
|
||||
),
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -113,6 +113,10 @@
|
||||
text-decoration: line-through !important;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.background-image {
|
||||
background: url("../img/backgroundLight.png") repeat fixed;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 () => (
|
||||
|
||||
+28
-19
@@ -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 (
|
||||
<div className="mainbox col-md-8 offset-md-2 col-lg-6 offset-lg-3" style={{'float': 'none'}}>
|
||||
<div className="mainbox col-md-8 offset-md-2 col-lg-6 offset-lg-3" style={{ "float": "none" }}>
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
<div style={{'textAlign': 'center'}}>
|
||||
<div style={{ "textAlign": "center" }}>
|
||||
<img src={logo} alt="Logo" width="30%"/>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div className="card-title text-center" style={{'marginBottom': 0}}>
|
||||
<span className="logo-lg" style={{'fontSize': '25px'}}>
|
||||
<div className="card-title text-center" style={{ "marginBottom": 0 }}>
|
||||
<span className="logo-lg" style={{ "fontSize": "25px" }}>
|
||||
Pi-<b>hole</b>
|
||||
</span>
|
||||
</div>
|
||||
@@ -106,7 +115,7 @@ class Login extends Component {
|
||||
<Fragment>
|
||||
<br/>
|
||||
{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] }
|
||||
)}
|
||||
</Fragment>
|
||||
@@ -115,7 +124,7 @@ class Login extends Component {
|
||||
{
|
||||
// If cookies are not enabled (or detected), show a warning
|
||||
!this.state.cookiesEnabled ?
|
||||
<div className="text-center" style={{'color': '#F00'}}>
|
||||
<div className="text-center" style={{ "color": "#F00" }}>
|
||||
{t("Verify that cookies are allowed for {{host}}", { host: window.location.host })}
|
||||
</div>
|
||||
: null
|
||||
@@ -135,7 +144,7 @@ class Login extends Component {
|
||||
|
||||
<div className="card-body">
|
||||
<form id="loginform">
|
||||
<div className={'input-group' + (this.state.error ? ' has-error' : '')}>
|
||||
<div className={"input-group" + (this.state.error ? " has-error" : "")}>
|
||||
<input type="password" className="form-control"
|
||||
value={this.state.password} onChange={this.handlePasswordChange}
|
||||
placeholder={t("Password")} autoFocus/>
|
||||
|
||||
+9
-1
@@ -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() {
|
||||
|
||||
+72
-24
@@ -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 () => (
|
||||
<div className="animated fadeIn">
|
||||
<div className="container-flex">
|
||||
<div className="row">
|
||||
<div className="col-lg-6 col-xs-6">
|
||||
<NetworkInfo/>
|
||||
</div>
|
||||
<div className="col-lg-6 col-xs-6">
|
||||
<DHCPInfo/>
|
||||
</div>
|
||||
<div className="col-lg-12 col-xs-12">
|
||||
<DNSInfo/>
|
||||
</div>
|
||||
<div className="col-lg-3 col-xs-3">
|
||||
<FTLInfo/>
|
||||
</div>
|
||||
/**
|
||||
* 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) => (
|
||||
<NavItem>
|
||||
<NavLink active={this.state.activeTab === id} onClick={() => this.setTab(id)}>
|
||||
{name}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
);
|
||||
|
||||
/**
|
||||
* 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) => (
|
||||
<TabPane tabId={id}>{component}</TabPane>
|
||||
);
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<div className="animated fadeIn">
|
||||
<Nav tabs>
|
||||
{this.tab("network", t("Network"))}
|
||||
{this.tab("dhcp", t("DHCP"))}
|
||||
{this.tab("dns", t("DNS"))}
|
||||
{this.tab("ftl", t("FTL"))}
|
||||
</Nav>
|
||||
<TabContent activeTab={this.state.activeTab}>
|
||||
{this.tabContent("network", <NetworkInfo/>)}
|
||||
{this.tabContent("dhcp", <DHCPInfo/>)}
|
||||
{this.tabContent("dns", <DNSInfo/>)}
|
||||
{this.tabContent("ftl", <FTLInfo/>)}
|
||||
</TabContent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(["common", "settings"])(Networking);
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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 () => (
|
||||
<div className="animated fadeIn">
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
Reference in New Issue
Block a user