Merge remote-tracking branch 'origin/main' into main
1
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -2,6 +2,7 @@
|
|||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="HtmlRequiredLangAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JupyterPackageInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="LessResolvedByNameOnly" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
|
|
@ -167,19 +167,6 @@ class TestRepositoryPatch:
|
|||
|
||||
})
|
||||
assert r.status_code == 204
|
||||
'''
|
||||
def test_unknown_type(self, flask_client: Client, admin_headers):
|
||||
r = flask_client.patch(f'/api/v1/repositories/1', headers=admin_headers,
|
||||
json={
|
||||
"name": "string",
|
||||
"close": "string",
|
||||
"open": "string",
|
||||
"evaluation_mode": 99
|
||||
})
|
||||
assert r.status_code == 400
|
||||
assert r.json["result"] == "failure" '''
|
||||
|
||||
|
||||
|
||||
|
||||
class TestRepositoryDelete:
|
||||
|
|
|
@ -207,4 +207,3 @@ class TestOneAlertOfARepository:
|
|||
def test_delete_alert_for_success(self, flask_client: Client, user_headers):
|
||||
r = flask_client.delete(f'/api/v1/alert/1', headers=user_headers)
|
||||
assert r.status_code == 204
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from nest_backend.database import *
|
|||
import tweepy as tw
|
||||
from datetime import datetime, timedelta
|
||||
import smtplib
|
||||
from nest_backend.app import app, extension_sqlalchemy
|
||||
|
||||
ext.init_app(app=app)
|
||||
|
||||
|
@ -24,12 +25,13 @@ def authenticate():
|
|||
def search_repo_conditions(repository_id):
|
||||
api = authenticate()
|
||||
geocode = "44.3591600,11.7132000,20km"
|
||||
|
||||
repo = Repository.query.filter_by(id=repository_id).first()
|
||||
if repo is None:
|
||||
print("Non esiste una repository con questo id")
|
||||
return False
|
||||
conditions = [use for use in repo.conditions]
|
||||
if len(conditions) == 0:
|
||||
return False
|
||||
evaluation_mode = repo.evaluation_mode
|
||||
conditions_type = dict()
|
||||
# Dividing condition into condition types
|
||||
|
@ -234,7 +236,14 @@ def send_test_tweet():
|
|||
api = authenticate()
|
||||
api.update_status("Test")
|
||||
|
||||
def search_all_repo():
|
||||
active_repos = Repository.query.filter_by(is_active=True)
|
||||
for repo_id in [active_repo.id for active_repo in active_repos]:
|
||||
search_repo_conditions(repo_id)
|
||||
is_repo_alert_triggered(repo_id)
|
||||
|
||||
if __name__ == "__main__":
|
||||
search_repo_conditions(16)
|
||||
with app.app_context():
|
||||
ext.create_all(app=app)
|
||||
search_all_repo()
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react"
|
||||
import Layout from "./components/interactive/Layout"
|
||||
import { BrowserRouter } from "react-router-dom"
|
||||
import GlobalTheme from "./components/providers/GlobalTheme"
|
||||
import GlobalServer from "./components/providers/GlobalServer"
|
||||
|
@ -7,6 +6,10 @@ import GlobalUser from "./components/providers/GlobalUser"
|
|||
import PageSwitcher from "./PageSwitcher"
|
||||
import GlobalLanguage from "./components/providers/GlobalLanguage"
|
||||
import ErrorBoundary from "./components/boundaries/ErrorBoundary"
|
||||
import Sidebar from "./components/interactive/Sidebar"
|
||||
import WebsiteWithSidebar from "./components/base/layout/WebsiteWithSidebar"
|
||||
import Window from "./components/base/layout/Window"
|
||||
import RequireSize from "./components/base/RequireSize"
|
||||
|
||||
|
||||
/**
|
||||
|
@ -22,11 +25,17 @@ export default function App() {
|
|||
<GlobalUser>
|
||||
<GlobalTheme>
|
||||
<BrowserRouter>
|
||||
<Layout>
|
||||
<ErrorBoundary>
|
||||
<PageSwitcher/>
|
||||
</ErrorBoundary>
|
||||
</Layout>
|
||||
<Window>
|
||||
<RequireSize width={1366} height={768}>
|
||||
<WebsiteWithSidebar
|
||||
sidebar={<Sidebar/>}
|
||||
>
|
||||
<ErrorBoundary>
|
||||
<PageSwitcher/>
|
||||
</ErrorBoundary>
|
||||
</WebsiteWithSidebar>
|
||||
</RequireSize>
|
||||
</Window>
|
||||
</BrowserRouter>
|
||||
</GlobalTheme>
|
||||
</GlobalUser>
|
||||
|
|
|
@ -16,6 +16,9 @@ export default {
|
|||
appFullName: "Noi Estraiamo Statistiche Tweet",
|
||||
welcomeToNest: "Benvenuto a N.E.S.T.!",
|
||||
|
||||
resolutionTooSmall: "Per visualizzare correttamente questa applicazione è richiesto uno schermo con risoluzione 1366x768 o superiore.", // TODO: Tradurre
|
||||
ignore: "Visualizza comunque", // TODO: Tradurre
|
||||
|
||||
server: "Scegli un server",
|
||||
baseURL: "Base URL",
|
||||
notLoggedIn: "Accesso non effettuato",
|
||||
|
|
28
nest_frontend/components/base/RequireSize.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React, { useState } from "react"
|
||||
import { useWindowSize } from "@react-hook/window-size/throttled"
|
||||
import Alert from "./Alert"
|
||||
import useStrings from "../../hooks/useStrings"
|
||||
import Button from "./Button"
|
||||
import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons"
|
||||
import makeIcon from "../../utils/makeIcon"
|
||||
import BodyFlex from "./layout/BodyFlex"
|
||||
|
||||
|
||||
export default function RequireSize({ children, width, height, ...props }) {
|
||||
const [windowWidth, windowHeight] = useWindowSize()
|
||||
const [warn, setWarn] = useState(true)
|
||||
const strings = useStrings()
|
||||
|
||||
if(warn && (windowWidth < width || windowHeight < height)) {
|
||||
return <BodyFlex {...props}>
|
||||
<Alert color={"Red"}>
|
||||
{strings.resolutionTooSmall}
|
||||
</Alert>
|
||||
<Button color={"Yellow"} onClick={() => setWarn(false)} style={{alignSelf: "center"}}>
|
||||
{makeIcon(faExclamationTriangle)} {strings.ignore}
|
||||
</Button>
|
||||
</BodyFlex>
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
28
nest_frontend/components/base/layout/WebsiteWithSidebar.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React from "react"
|
||||
import Style from "./WebsiteWithSidebar.module.css"
|
||||
import classNames from "classnames"
|
||||
|
||||
|
||||
/**
|
||||
* The base page layout, consisting of a {@link Sidebar} on the left and the page contents on the remaining space.
|
||||
*
|
||||
* @param sidebar - The sidebar to display.
|
||||
* @param children - The page contents.
|
||||
* @param className - Additional class(es) to be added to the grid container.
|
||||
* @param props - Additional props to be passed to the grid container.
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
export default function WebsiteWithSidebar({ sidebar, children, className, ...props }) {
|
||||
|
||||
return (
|
||||
<div className={classNames(Style.WebsiteWithSidebar, className)} {...props}>
|
||||
<aside className={Style.Sidebar}>
|
||||
{sidebar}
|
||||
</aside>
|
||||
<main className={Style.Main}>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
.WebsiteWithSidebar {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"a b";
|
||||
grid-template-columns: auto 1fr;
|
||||
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.Sidebar {
|
||||
grid-area: a;
|
||||
}
|
||||
|
||||
.Main {
|
||||
grid-area: b;
|
||||
}
|
15
nest_frontend/components/base/layout/Window.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import React, { useContext } from "react"
|
||||
import Style from "./Window.module.css"
|
||||
import classNames from "classnames"
|
||||
import ContextTheme from "../../../contexts/ContextTheme"
|
||||
|
||||
|
||||
export default function Window({ children, className, ...props }) {
|
||||
const {theme} = useContext(ContextTheme)
|
||||
|
||||
return (
|
||||
<div className={classNames(Style.Window, theme, className)} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
9
nest_frontend/components/base/layout/Window.module.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
.Window {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
color: var(--fg-primary);
|
||||
background-color: var(--bg-primary);
|
||||
|
||||
padding: 10px;
|
||||
}
|
|
@ -1,15 +1,29 @@
|
|||
import React from "react"
|
||||
import React, { useMemo } from "react"
|
||||
import BoxFullScrollable from "../base/BoxFullScrollable"
|
||||
import SummaryAlert from "./SummaryAlert"
|
||||
import useStrings from "../../hooks/useStrings"
|
||||
import Empty from "./Empty"
|
||||
|
||||
|
||||
export default function BoxAlerts({ alerts, destroy, running, ...props }) {
|
||||
const strings = useStrings()
|
||||
|
||||
const content = useMemo(
|
||||
() => {
|
||||
if(alerts.length === 0) {
|
||||
return <Empty/>
|
||||
}
|
||||
|
||||
return alerts.map(alert => (
|
||||
<SummaryAlert alert={alert} destroy={() => destroy(alert["id"])} running={running}/>
|
||||
))
|
||||
},
|
||||
[alerts, running, destroy]
|
||||
)
|
||||
|
||||
return (
|
||||
<BoxFullScrollable header={strings.alertTitle} {...props}>
|
||||
{alerts.map(alert => <SummaryAlert alert={alert} destroy={() => destroy(alert["id"])} running={running}/>)}
|
||||
{content}
|
||||
</BoxFullScrollable>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import React, { useContext } from "react"
|
||||
import Style from "./Layout.module.css"
|
||||
import classNames from "classnames"
|
||||
import Sidebar from "../interactive/Sidebar"
|
||||
import ContextTheme from "../../contexts/ContextTheme"
|
||||
|
||||
|
||||
/**
|
||||
* The base page layout, consisting of a {@link Sidebar} on the left and the page contents on the remaining space.
|
||||
*
|
||||
* @param children - The page contents.
|
||||
* @param className - Additional class(es) to be added to the grid container.
|
||||
* @param props - Additional props to be passed to the grid container.
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
export default function Layout({ children, className, ...props }) {
|
||||
const { theme } = useContext(ContextTheme)
|
||||
|
||||
return (
|
||||
<div className={classNames(theme, Style.Layout, className)} {...props}>
|
||||
<Sidebar className={Style.LayoutSidebar}/>
|
||||
<main className={Style.LayoutContent}>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
.Layout {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
padding: 16px;
|
||||
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--fg-primary);
|
||||
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"a b";
|
||||
grid-template-columns: 250px 1fr;
|
||||
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.LayoutSidebar {
|
||||
grid-area: a;
|
||||
}
|
||||
|
||||
.LayoutContent {
|
||||
grid-area: b;
|
||||
}
|
|
@ -31,7 +31,7 @@ export default function Sidebar({ className, ...props }) {
|
|||
</>
|
||||
:
|
||||
<>
|
||||
<ButtonSidebar to={"/login"} icon={faKey}>{strings.login}</ButtonSidebar>
|
||||
<ButtonSidebar to={"/"} icon={faKey}>{strings.login}</ButtonSidebar>
|
||||
</>
|
||||
}
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
flex-direction: column;
|
||||
gap: 25px;
|
||||
|
||||
width: 100%;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
|
||||
background-color: var(--bg-light);
|
||||
|
|
|
@ -31,7 +31,7 @@ export default function SummaryTweet({ tweet, ...props }) {
|
|||
<SummaryLeft
|
||||
icon={icon}
|
||||
title={`@${tweet["poster"]}`}
|
||||
subtitle={new Date(tweet["insert_time"]).toLocaleString()}
|
||||
subtitle={tweet["post_time"] ? new Date(tweet["post_time"]).toLocaleString() : null}
|
||||
onClick={() => window.open(`https://twitter.com/${tweet["poster"]}/status/${tweet["snowflake"]}`)}
|
||||
/>
|
||||
<SummaryText>
|
||||
|
|
109
package-lock.json
generated
|
@ -13,6 +13,7 @@
|
|||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"@react-hook/window-size": "^3.0.7",
|
||||
"@react-leaflet/core": ">=1.0.0 <1.1.0 || ^1.1.1",
|
||||
"@steffo/nest-react-wordcloud": "1.2.11",
|
||||
"@testing-library/jest-dom": "^5.11.10",
|
||||
|
@ -2379,6 +2380,68 @@
|
|||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-hook/debounce": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-3.0.0.tgz",
|
||||
"integrity": "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==",
|
||||
"dependencies": {
|
||||
"@react-hook/latest": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-hook/event": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/event/-/event-1.2.3.tgz",
|
||||
"integrity": "sha512-WMBwLnYY2rubLeecsi4skl1imfx0oiXTgazV/1ByPT6WkmLvxUao3hC+mxps5D/+JK4Fq3uG9OWU/dn5jMtXyg==",
|
||||
"dependencies": {
|
||||
"@react-hook/passive-layout-effect": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-hook/latest": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
|
||||
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-hook/passive-layout-effect": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz",
|
||||
"integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-hook/throttle": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/throttle/-/throttle-2.2.0.tgz",
|
||||
"integrity": "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==",
|
||||
"dependencies": {
|
||||
"@react-hook/latest": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-hook/window-size": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/window-size/-/window-size-3.0.7.tgz",
|
||||
"integrity": "sha512-bK5ed/jN+cxy0s1jt2CelCnUt7jZRseUvPQ22ZJkUl/QDOsD+7CA/6wcqC3c0QweM/fPBRP6uI56TJ48SnlVww==",
|
||||
"dependencies": {
|
||||
"@react-hook/debounce": "^3.0.0",
|
||||
"@react-hook/event": "^1.2.1",
|
||||
"@react-hook/throttle": "^2.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-leaflet/core": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-1.0.2.tgz",
|
||||
|
@ -24512,6 +24575,52 @@
|
|||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz",
|
||||
"integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q=="
|
||||
},
|
||||
"@react-hook/debounce": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-3.0.0.tgz",
|
||||
"integrity": "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==",
|
||||
"requires": {
|
||||
"@react-hook/latest": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"@react-hook/event": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/event/-/event-1.2.3.tgz",
|
||||
"integrity": "sha512-WMBwLnYY2rubLeecsi4skl1imfx0oiXTgazV/1ByPT6WkmLvxUao3hC+mxps5D/+JK4Fq3uG9OWU/dn5jMtXyg==",
|
||||
"requires": {
|
||||
"@react-hook/passive-layout-effect": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@react-hook/latest": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
|
||||
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
|
||||
"requires": {}
|
||||
},
|
||||
"@react-hook/passive-layout-effect": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz",
|
||||
"integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==",
|
||||
"requires": {}
|
||||
},
|
||||
"@react-hook/throttle": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/throttle/-/throttle-2.2.0.tgz",
|
||||
"integrity": "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==",
|
||||
"requires": {
|
||||
"@react-hook/latest": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"@react-hook/window-size": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-hook/window-size/-/window-size-3.0.7.tgz",
|
||||
"integrity": "sha512-bK5ed/jN+cxy0s1jt2CelCnUt7jZRseUvPQ22ZJkUl/QDOsD+7CA/6wcqC3c0QweM/fPBRP6uI56TJ48SnlVww==",
|
||||
"requires": {
|
||||
"@react-hook/debounce": "^3.0.0",
|
||||
"@react-hook/event": "^1.2.1",
|
||||
"@react-hook/throttle": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@react-leaflet/core": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-1.0.2.tgz",
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"@react-hook/window-size": "^3.0.7",
|
||||
"@react-leaflet/core": ">=1.0.0 <1.1.0 || ^1.1.1",
|
||||
"@steffo/nest-react-wordcloud": "1.2.11",
|
||||
"@testing-library/jest-dom": "^5.11.10",
|
||||
|
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 30 KiB |
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link href="%PUBLIC_URL%/favicon.ico" rel="icon"/>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<meta content="#34607A" name="theme-color"/>
|
||||
<meta
|
||||
content="Tweet analyzer frontend"
|
||||
content="Tweet gatherer, analyzer and visualizer"
|
||||
name="description"
|
||||
/>
|
||||
<link href="%PUBLIC_URL%/logo192.png" rel="apple-touch-icon"/>
|
||||
|
|
BIN
public/logo1024.png
Normal file
After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 17 KiB |
BIN
public/logo670.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
public/logo768.png
Normal file
After Width: | Height: | Size: 39 KiB |
|
@ -1,3 +1,4 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Disallow: /
|
||||
|
||||
|
|