App directory refactoring
This commit is contained in:
parent
a53a26f4c0
commit
b312a8c862
153 changed files with 1532 additions and 1447 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, PropsWithChildren } from "react";
|
import { FC, PropsWithChildren } from "react";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useAppContext } from "./AppProvider";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Image from "next/legacy/image";
|
import Image from "next/legacy/image";
|
||||||
import { Grid, Box, GridSize } from "@mui/material";
|
import { Grid, Box, GridSize } from "@mui/material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Image from "next/legacy/image";
|
import Image from "next/legacy/image";
|
||||||
import { signOut } from "next-auth/react";
|
import { signOut } from "next-auth/react";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FC,
|
FC,
|
||||||
createContext,
|
createContext,
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Button as MUIButton } from "@mui/material";
|
import { Button as MUIButton } from "@mui/material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { Container, Grid, Box, Button } from "@mui/material";
|
import { Container, Grid, Box, Button } from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { Dialog, Box, Grid, Checkbox, IconButton } from "@mui/material";
|
import { Dialog, Box, Grid, Checkbox, IconButton } from "@mui/material";
|
||||||
import { Close as CloseIcon } from "@mui/icons-material";
|
import { Close as CloseIcon } from "@mui/icons-material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
|
|
@ -1,30 +1,23 @@
|
||||||
import { useEffect } from "react";
|
"use client";
|
||||||
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
|
|
||||||
|
import { useEffect, FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { getSession } from "next-auth/react";
|
|
||||||
import Head from "next/head";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import { Grid, Button } from "@mui/material";
|
import { Grid, Button } from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useCookies } from "react-cookie";
|
import { useCookies } from "react-cookie";
|
||||||
import { Layout } from "components/Layout";
|
import { Welcome } from "@/app/_components/Welcome";
|
||||||
import { getUserVisualizations } from "lib/opensearch";
|
import { WelcomeDialog } from "@/app/_components/WelcomeDialog";
|
||||||
import { Welcome } from "components/Welcome";
|
import { VisualizationCard } from "@/app/_components/VisualizationCard";
|
||||||
import { WelcomeDialog } from "components/WelcomeDialog";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { VisualizationCard } from "components/VisualizationCard";
|
|
||||||
import { useAppContext } from "components/AppProvider";
|
|
||||||
import { getEmbedded } from "lib/utils";
|
|
||||||
|
|
||||||
type MyVisualizationsProps = {
|
type HomeProps = {
|
||||||
visualizations: any;
|
visualizations: any;
|
||||||
embedded: boolean;
|
embedded: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MyVisualizations: NextPage<MyVisualizationsProps> = ({
|
export const Home: FC<HomeProps> = ({ visualizations, embedded }) => {
|
||||||
visualizations,
|
|
||||||
embedded,
|
|
||||||
}) => {
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const cookieName = "homeIntroComplete";
|
const cookieName = "homeIntroComplete";
|
||||||
const [cookies, setCookie] = useCookies([cookieName]);
|
const [cookies, setCookie] = useCookies([cookieName]);
|
||||||
|
|
@ -43,10 +36,7 @@ const MyVisualizations: NextPage<MyVisualizationsProps> = ({
|
||||||
}, [homeIntroComplete, router, setCookie]);
|
}, [homeIntroComplete, router, setCookie]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout embedded={embedded}>
|
<>
|
||||||
<Head>
|
|
||||||
<title>Digital Threat Dashboard – Leafcutter</title>
|
|
||||||
</Head>
|
|
||||||
<Welcome />
|
<Welcome />
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
|
|
@ -105,19 +95,6 @@ const MyVisualizations: NextPage<MyVisualizationsProps> = ({
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
<WelcomeDialog />
|
<WelcomeDialog />
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MyVisualizations;
|
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (
|
|
||||||
context: GetServerSidePropsContext
|
|
||||||
) => {
|
|
||||||
const session = (await getSession(context)) ?? null;
|
|
||||||
const visualizations = await getUserVisualizations(
|
|
||||||
session?.user?.email ?? "none",
|
|
||||||
20
|
|
||||||
);
|
|
||||||
return { props: { visualizations, embedded: getEmbedded(context) } };
|
|
||||||
};
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, PropsWithChildren } from "react";
|
import { FC, PropsWithChildren } from "react";
|
||||||
import getConfig from "next/config";
|
import getConfig from "next/config";
|
||||||
import { Grid, Container } from "@mui/material";
|
import { Grid, Container } from "@mui/material";
|
||||||
|
|
@ -13,7 +15,7 @@ type LayoutProps = PropsWithChildren<{
|
||||||
embedded?: boolean;
|
embedded?: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const Layout: FC<LayoutProps> = ({
|
export const InternalLayout: FC<LayoutProps> = ({
|
||||||
embedded = false,
|
embedded = false,
|
||||||
children,
|
children,
|
||||||
}: any) => {
|
}: any) => {
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { IconButton, Menu, MenuItem, Box } from "@mui/material";
|
import { IconButton, Menu, MenuItem, Box } from "@mui/material";
|
||||||
import { KeyboardArrowDown as KeyboardArrowDownIcon } from "@mui/icons-material";
|
import { KeyboardArrowDown as KeyboardArrowDownIcon } from "@mui/icons-material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useEffect, useState } from "react";
|
import { FC, useEffect, useState } from "react";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useAppContext } from "./AppProvider";
|
||||||
import { RawDataViewer } from "./RawDataViewer";
|
import { RawDataViewer } from "./RawDataViewer";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { Card, Grid } from "@mui/material";
|
import { Card, Grid } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
47
apps/leafcutter/app/_components/MultiProvider.tsx
Normal file
47
apps/leafcutter/app/_components/MultiProvider.tsx
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* eslint-disable react/jsx-props-no-spreading */
|
||||||
|
import { FC, PropsWithChildren } from "react";
|
||||||
|
import { SessionProvider } from "next-auth/react";
|
||||||
|
import { CssBaseline } from "@mui/material";
|
||||||
|
import { CookiesProvider } from "react-cookie";
|
||||||
|
import { I18n } from "react-polyglot";
|
||||||
|
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns";
|
||||||
|
("use client");
|
||||||
|
|
||||||
|
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
||||||
|
import { AppProvider } from "@/app/_components/AppProvider";
|
||||||
|
import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";
|
||||||
|
import en from "locales/en.json";
|
||||||
|
import fr from "locales/fr.json";
|
||||||
|
import "@fontsource/poppins/400.css";
|
||||||
|
import "@fontsource/poppins/700.css";
|
||||||
|
import "@fontsource/roboto/400.css";
|
||||||
|
import "@fontsource/roboto/700.css";
|
||||||
|
import "@fontsource/playfair-display/900.css";
|
||||||
|
import "styles/global.css";
|
||||||
|
import { LicenseInfo } from "@mui/x-data-grid-pro";
|
||||||
|
|
||||||
|
LicenseInfo.setLicenseKey(process.env.MUI_LICENSE_KEY ?? "");
|
||||||
|
|
||||||
|
const messages: any = { en, fr };
|
||||||
|
|
||||||
|
export const MultiProvider: FC<PropsWithChildren> = ({ children }: any) => {
|
||||||
|
// const { locale = "en" } = useRouter();
|
||||||
|
const locale = "en";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NextAppDirEmotionCacheProvider options={{ key: "css" }}>
|
||||||
|
<SessionProvider>
|
||||||
|
<CookiesProvider>
|
||||||
|
<CssBaseline />
|
||||||
|
<AppProvider>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
|
<I18n locale={locale} messages={messages[locale]}>
|
||||||
|
{children}
|
||||||
|
</I18n>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</AppProvider>
|
||||||
|
</CookiesProvider>
|
||||||
|
</SessionProvider>
|
||||||
|
</NextAppDirEmotionCacheProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
/* eslint-disable react/require-default-props */
|
/* eslint-disable react/require-default-props */
|
||||||
import { FC, PropsWithChildren } from "react";
|
import { FC, PropsWithChildren } from "react";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
|
@ -15,14 +17,14 @@ import {
|
||||||
Group as GroupIcon,
|
Group as GroupIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import taxonomy from "config/taxonomy.json";
|
import taxonomy from "app/_config/taxonomy.json";
|
||||||
import { QueryBuilderSection } from "./QueryBuilderSection";
|
import { QueryBuilderSection } from "./QueryBuilderSection";
|
||||||
import { QueryListSelector } from "./QueryListSelector";
|
import { QueryListSelector } from "./QueryListSelector";
|
||||||
import { QueryDateRangeSelector } from "./QueryDateRangeSelector";
|
import { QueryDateRangeSelector } from "./QueryDateRangeSelector";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useAppContext } from "./AppProvider";
|
||||||
import { Tooltip } from "./Tooltip";
|
import { Tooltip } from "./Tooltip";
|
||||||
|
|
||||||
interface QueryBuilderProps { }
|
interface QueryBuilderProps {}
|
||||||
|
|
||||||
export const QueryBuilder: FC<QueryBuilderProps> = () => {
|
export const QueryBuilder: FC<QueryBuilderProps> = () => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, PropsWithChildren, useState } from "react";
|
import { FC, PropsWithChildren, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState, useEffect } from "react";
|
import { FC, useState, useEffect } from "react";
|
||||||
import { Box, Grid, TextField, Select, MenuItem } from "@mui/material";
|
import { Box, Grid, TextField, Select, MenuItem } from "@mui/material";
|
||||||
import { DatePicker } from "@mui/x-date-pickers-pro";
|
import { DatePicker } from "@mui/x-date-pickers-pro";
|
||||||
|
|
@ -90,7 +92,7 @@ export const QueryDateRangeSelector: FC<QueryDateRangeSelectorProps> = () => {
|
||||||
endDate: { values: [date] },
|
endDate: { values: [date] },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField
|
<TextField
|
||||||
{...params}
|
{...params}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState, useEffect } from "react";
|
import { FC, useState, useEffect } from "react";
|
||||||
import { Box, Grid, Tooltip } from "@mui/material";
|
import { Box, Grid, Tooltip } from "@mui/material";
|
||||||
import { DataGridPro, GridColDef } from "@mui/x-data-grid-pro";
|
import { DataGridPro, GridColDef } from "@mui/x-data-grid-pro";
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState, useEffect } from "react";
|
import { FC, useState, useEffect } from "react";
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import taxonomy from "config/taxonomy.json";
|
import taxonomy from "app/_config/taxonomy.json";
|
||||||
import { colors } from "styles/theme";
|
import { colors } from "styles/theme";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useAppContext } from "./AppProvider";
|
||||||
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import {
|
import {
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { DataGridPro } from "@mui/x-data-grid-pro";
|
import { DataGridPro } from "@mui/x-data-grid-pro";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import DashboardMenuIcon from "images/dashboard-menu.png";
|
import DashboardMenuIcon from "images/dashboard-menu.png";
|
||||||
import AboutMenuIcon from "images/about-menu.png";
|
import AboutMenuIcon from "images/about-menu.png";
|
||||||
|
|
@ -18,8 +20,8 @@ import {
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { Tooltip } from "components/Tooltip";
|
import { Tooltip } from "@/app/_components/Tooltip";
|
||||||
// import { ArrowCircleRight as ArrowCircleRightIcon } from "@mui/icons-material";
|
// import { ArrowCircleRight as ArrowCircleRightIcon } from "@mui/icons-material";
|
||||||
|
|
||||||
const MenuItem = ({
|
const MenuItem = ({
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
/* eslint-disable react/require-default-props */
|
/* eslint-disable react/require-default-props */
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/legacy/image";
|
import Image from "next/legacy/image";
|
||||||
import { AppBar, Grid, Box } from "@mui/material";
|
import { AppBar, Grid, Box } from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import LeafcutterLogo from "images/leafcutter-logo.png";
|
import LeafcutterLogo from "images/leafcutter-logo.png";
|
||||||
import { AccountButton } from "components/AccountButton";
|
import { AccountButton } from "@/app/_components/AccountButton";
|
||||||
import { HelpButton } from "components/HelpButton";
|
import { HelpButton } from "@/app/_components/HelpButton";
|
||||||
import { Tooltip } from "components/Tooltip";
|
import { Tooltip } from "@/app/_components/Tooltip";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useAppContext } from "./AppProvider";
|
||||||
// import { LanguageSelect } from "./LanguageSelect";
|
// import { LanguageSelect } from "./LanguageSelect";
|
||||||
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState, useEffect } from "react";
|
import { FC, useState, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
|
@ -23,11 +25,11 @@ import {
|
||||||
RemoveCircle as RemoveCircleIcon,
|
RemoveCircle as RemoveCircleIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { QueryBuilder } from "components/QueryBuilder";
|
import { QueryBuilder } from "@/app/_components/QueryBuilder";
|
||||||
import { QueryText } from "components/QueryText";
|
import { QueryText } from "@/app/_components/QueryText";
|
||||||
import { LiveDataViewer } from "components/LiveDataViewer";
|
import { LiveDataViewer } from "@/app/_components/LiveDataViewer";
|
||||||
import { Tooltip } from "components/Tooltip";
|
import { Tooltip } from "@/app/_components/Tooltip";
|
||||||
import visualizationMap from "config/visualizationMap.json";
|
import visualizationMap from "app/_config/visualizationMap.json";
|
||||||
import { VisualizationSelectCard } from "./VisualizationSelectCard";
|
import { VisualizationSelectCard } from "./VisualizationSelectCard";
|
||||||
import { MetricSelectCard } from "./MetricSelectCard";
|
import { MetricSelectCard } from "./MetricSelectCard";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useAppContext } from "./AppProvider";
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { Grid, Card, Box } from "@mui/material";
|
import { Grid, Card, Box } from "@mui/material";
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { VisualizationDetailDialog } from "components/VisualizationDetailDialog";
|
import { VisualizationDetailDialog } from "@/app/_components/VisualizationDetailDialog";
|
||||||
|
|
||||||
interface VisualizationCardProps {
|
interface VisualizationCardProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
// import Link from "next/link";
|
// import Link from "next/link";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
|
|
||||||
interface VisualizationDetailProps {
|
interface VisualizationDetailProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
// import Link from "next/link";
|
// import Link from "next/link";
|
||||||
import {
|
import {
|
||||||
|
|
@ -9,7 +11,7 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { VisualizationDetail } from "./VisualizationDetail";
|
import { VisualizationDetail } from "./VisualizationDetail";
|
||||||
|
|
||||||
interface VisualizationDetailDialogProps {
|
interface VisualizationDetailDialogProps {
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Image from "next/legacy/image";
|
import Image from "next/legacy/image";
|
||||||
import { Card, Grid } from "@mui/material";
|
import { Card, Grid } from "@mui/material";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { Box, Grid, Dialog, Button } from "@mui/material";
|
import { Box, Grid, Dialog, Button } from "@mui/material";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// import { useSession } from "next-auth/react";
|
// import { useSession } from "next-auth/react";
|
||||||
|
|
@ -4,18 +4,17 @@ import Head from "next/head";
|
||||||
import Image from "next/legacy/image";
|
import Image from "next/legacy/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Grid, Container, Box, Button } from "@mui/material";
|
import { Grid, Container, Box, Button } from "@mui/material";
|
||||||
import { Layout } from "components/Layout";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { PageHeader } from "@/app/_components/PageHeader";
|
||||||
import { PageHeader } from "components/PageHeader";
|
import { AboutFeature } from "@/app/_components/AboutFeature";
|
||||||
import { AboutFeature } from "components/AboutFeature";
|
import { AboutBox } from "@/app/_components/AboutBox";
|
||||||
import { AboutBox } from "components/AboutBox";
|
|
||||||
import AbstractDiagram from "images/abstract-diagram.png";
|
import AbstractDiagram from "images/abstract-diagram.png";
|
||||||
import AboutHeader from "images/about-header.png";
|
import AboutHeader from "images/about-header.png";
|
||||||
import Globe from "images/globe.png";
|
import Globe from "images/globe.png";
|
||||||
import Controls from "images/controls.png";
|
import Controls from "images/controls.png";
|
||||||
import CommunityBackground from "images/community-background.png";
|
import CommunityBackground from "images/community-background.png";
|
||||||
import Bicycle from "images/bicycle.png";
|
import Bicycle from "images/bicycle.png";
|
||||||
import { getEmbedded } from "lib/utils";
|
import { getEmbedded } from "@/app/_lib/utils";
|
||||||
|
|
||||||
type AboutProps = {
|
type AboutProps = {
|
||||||
embedded: boolean;
|
embedded: boolean;
|
||||||
|
|
@ -29,10 +28,7 @@ const About: NextPage<AboutProps> = ({ embedded }) => {
|
||||||
} = useAppContext();
|
} = useAppContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout embedded={embedded}>
|
<>
|
||||||
<Head>
|
|
||||||
<title>Digital Threat Dashboard – Leafcutter</title>
|
|
||||||
</Head>
|
|
||||||
<PageHeader
|
<PageHeader
|
||||||
backgroundColor={leafcutterElectricBlue}
|
backgroundColor={leafcutterElectricBlue}
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -166,7 +162,7 @@ const About: NextPage<AboutProps> = ({ embedded }) => {
|
||||||
</Link>
|
</Link>
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@ import NextAuth from "next-auth";
|
||||||
import Google from "next-auth/providers/google";
|
import Google from "next-auth/providers/google";
|
||||||
import Apple from "next-auth/providers/apple";
|
import Apple from "next-auth/providers/apple";
|
||||||
|
|
||||||
export default NextAuth({
|
const handler = NextAuth({
|
||||||
providers: [
|
providers: [
|
||||||
Google({
|
Google({
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID ?? "",
|
clientId: process.env.GOOGLE_CLIENT_ID ?? "",
|
||||||
|
|
@ -15,3 +15,5 @@ export default NextAuth({
|
||||||
],
|
],
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export { handler as GET, handler as POST };
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { getUserMetadata, saveUserMetadata } from "lib/opensearch";
|
import { getUserMetadata, saveUserMetadata } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
export const POST = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
req,
|
req,
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
|
|
@ -27,7 +27,6 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
return res.json(updatedSavedSearches);
|
return res.json(updatedSavedSearches);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handler;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { getUserMetadata, saveUserMetadata } from "lib/opensearch";
|
import { getUserMetadata, saveUserMetadata } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { getUserMetadata } from "lib/opensearch";
|
import { getUserMetadata } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
20
apps/leafcutter/app/api/trends/recent.ts
Normal file
20
apps/leafcutter/app/api/trends/recent.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
// import { getToken } from "next-auth/jwt";
|
||||||
|
import { getTrends } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
|
export const GET = async () => {
|
||||||
|
/*
|
||||||
|
const session = await getToken({
|
||||||
|
req,
|
||||||
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return res.redirect("/login");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const results = await getTrends(5);
|
||||||
|
|
||||||
|
NextResponse.json(results);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { Client } from "@opensearch-project/opensearch";
|
import { Client } from "@opensearch-project/opensearch";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import taxonomy from "config/taxonomy.json";
|
import taxonomy from "app/_config/taxonomy.json";
|
||||||
import unRegions from "config/unRegions.json";
|
import unRegions from "app/_config/unRegions.json";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const { headers: { authorization }, body: { tickets } } = req;
|
const { headers: { authorization }, body: { tickets } } = req;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { createUserVisualization } from "lib/opensearch";
|
import { createUserVisualization } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { deleteUserVisualization } from "lib/opensearch";
|
import { deleteUserVisualization } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { performQuery } from "lib/opensearch";
|
import { performQuery } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
|
|
@ -16,7 +16,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const rawQuery = await JSON.parse(decodeURI(searchQuery as string));
|
const rawQuery = await JSON.parse(decodeURI(searchQuery as string));
|
||||||
const results = await performQuery(rawQuery, 1000);
|
const results = await performQuery(rawQuery, 1000);
|
||||||
|
|
||||||
return res.json(results)
|
return res.json(results);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handler;
|
export default handler;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { updateUserVisualization } from "lib/opensearch";
|
import { updateUserVisualization } from "@/app/_lib/opensearch";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const session = await getToken({
|
const session = await getToken({
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
import { FC, useEffect } from "react";
|
import { FC, useEffect } from "react";
|
||||||
import { GetServerSideProps, GetServerSidePropsContext } from "next";
|
import { GetServerSideProps, GetServerSidePropsContext } from "next";
|
||||||
import Head from "next/head";
|
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { useCookies } from "react-cookie";
|
import { useCookies } from "react-cookie";
|
||||||
import { getTemplates } from "lib/opensearch";
|
import { getTemplates } from "@/app/_lib/opensearch";
|
||||||
import { Layout } from "components/Layout";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { PageHeader } from "@/app/_components/PageHeader";
|
||||||
import { PageHeader } from "components/PageHeader";
|
import { VisualizationBuilder } from "@/app/_components/VisualizationBuilder";
|
||||||
import { VisualizationBuilder } from "components/VisualizationBuilder";
|
import { getEmbedded } from "@/app/_lib/utils";
|
||||||
import { getEmbedded } from "lib/utils";
|
|
||||||
|
|
||||||
type CreateProps = {
|
type CreateProps = {
|
||||||
templates: any;
|
templates: any;
|
||||||
|
|
@ -36,11 +34,7 @@ const Create: FC<CreateProps> = ({ templates, embedded }) => {
|
||||||
}, [searchIntroComplete, router, setCookie]);
|
}, [searchIntroComplete, router, setCookie]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout embedded={embedded}>
|
<>
|
||||||
<Head>
|
|
||||||
<title>Digital Threat Dashboard – Leafcutter</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<PageHeader backgroundColor={cdrLinkOrange}>
|
<PageHeader backgroundColor={cdrLinkOrange}>
|
||||||
<Grid container direction="row" spacing={2} alignItems="center">
|
<Grid container direction="row" spacing={2} alignItems="center">
|
||||||
{/* <Grid item xs={2} sx={{ textAlign: "center" }}>
|
{/* <Grid item xs={2} sx={{ textAlign: "center" }}>
|
||||||
|
|
@ -67,7 +61,7 @@ const Create: FC<CreateProps> = ({ templates, embedded }) => {
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<VisualizationBuilder templates={templates} />
|
<VisualizationBuilder templates={templates} />
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
import Head from "next/head";
|
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
|
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { Layout } from "components/Layout";
|
import { PageHeader } from "@/app/_components/PageHeader";
|
||||||
import { PageHeader } from "components/PageHeader";
|
import { Question } from "@/app/_components/Question";
|
||||||
import { Question } from "components/Question";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { useAppContext } from "components/AppProvider";
|
|
||||||
import FaqHeader from "images/faq-header.svg";
|
import FaqHeader from "images/faq-header.svg";
|
||||||
import { getEmbedded } from "lib/utils";
|
import { getEmbedded } from "@/app/_lib/utils";
|
||||||
|
|
||||||
type FAQProps = {
|
type FAQProps = {
|
||||||
embedded: boolean;
|
embedded: boolean;
|
||||||
|
|
@ -70,10 +68,7 @@ const FAQ: NextPage<FAQProps> = ({ embedded }) => {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout embedded={embedded}>
|
<>
|
||||||
<Head>
|
|
||||||
<title>Digital Threat Dashboard – Leafcutter</title>
|
|
||||||
</Head>
|
|
||||||
<PageHeader
|
<PageHeader
|
||||||
backgroundColor={lavender}
|
backgroundColor={lavender}
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -105,7 +100,7 @@ const FAQ: NextPage<FAQProps> = ({ embedded }) => {
|
||||||
{questions.map((q: any, index: number) => (
|
{questions.map((q: any, index: number) => (
|
||||||
<Question key={index} question={q.question} answer={q.answer} />
|
<Question key={index} question={q.question} answer={q.answer} />
|
||||||
))}
|
))}
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
36
apps/leafcutter/app/layout.tsx
Normal file
36
apps/leafcutter/app/layout.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import "./_styles/global.css";
|
||||||
|
import "@fontsource/poppins/400.css";
|
||||||
|
import "@fontsource/poppins/700.css";
|
||||||
|
import "@fontsource/roboto/400.css";
|
||||||
|
import "@fontsource/roboto/700.css";
|
||||||
|
import "@fontsource/playfair-display/900.css";
|
||||||
|
import "styles/global.css";
|
||||||
|
// import getConfig from "next/config";
|
||||||
|
// import { LicenseInfo } from "@mui/x-data-grid-pro";
|
||||||
|
import { MultiProvider } from "app/_components/MultiProvider";
|
||||||
|
import { InternalLayout } from "app/_components/InternalLayout";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Leafcutter",
|
||||||
|
};
|
||||||
|
|
||||||
|
type LayoutProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Layout({ children }: LayoutProps) {
|
||||||
|
// const { publicRuntimeConfig } = getConfig();
|
||||||
|
// LicenseInfo.setLicenseKey(publicRuntimeConfig.muiLicenseKey);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
<MultiProvider>
|
||||||
|
<InternalLayout>{children}</InternalLayout>
|
||||||
|
</MultiProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -5,10 +5,10 @@ import Image from "next/legacy/image";
|
||||||
import { Box, Grid, Container, IconButton } from "@mui/material";
|
import { Box, Grid, Container, IconButton } from "@mui/material";
|
||||||
import { Apple as AppleIcon, Google as GoogleIcon } from "@mui/icons-material";
|
import { Apple as AppleIcon, Google as GoogleIcon } from "@mui/icons-material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { LanguageSelect } from "components/LanguageSelect";
|
import { LanguageSelect } from "@/app/_components/LanguageSelect";
|
||||||
import LeafcutterLogoLarge from "images/leafcutter-logo-large.png";
|
import LeafcutterLogoLarge from "images/leafcutter-logo-large.png";
|
||||||
import { signIn, getSession } from "next-auth/react";
|
import { signIn, getSession } from "next-auth/react";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
|
|
||||||
type LoginProps = {
|
type LoginProps = {
|
||||||
session: any;
|
session: any;
|
||||||
16
apps/leafcutter/app/page.tsx
Normal file
16
apps/leafcutter/app/page.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { getSession } from "next-auth/react";
|
||||||
|
import { getUserVisualizations } from "@/app/_lib/opensearch";
|
||||||
|
import { getEmbedded } from "@/app/_lib/utils";
|
||||||
|
import { Home } from "@/app/_components/Home";
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
const context = undefined;
|
||||||
|
const session = (await getSession(context)) ?? null;
|
||||||
|
const visualizations = await getUserVisualizations(
|
||||||
|
session?.user?.email ?? "none",
|
||||||
|
20
|
||||||
|
);
|
||||||
|
const embedded = false; // getEmbedded(context);
|
||||||
|
|
||||||
|
return <Home visualizations={visualizations} embedded={embedded} />;
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
// import { Client } from "@opensearch-project/opensearch";
|
// import { Client } from "@opensearch-project/opensearch";
|
||||||
import { RawDataViewer } from "components/RawDataViewer";
|
import { RawDataViewer } from "@/app/_components/RawDataViewer";
|
||||||
import { VisualizationDetail } from "components/VisualizationDetail";
|
import { VisualizationDetail } from "@/app/_components/VisualizationDetail";
|
||||||
// import { createVisualization } from "lib/opensearch";
|
// import { createVisualization } from "lib/opensearch";
|
||||||
|
|
||||||
interface PreviewProps {
|
interface PreviewProps {
|
||||||
|
|
@ -3,7 +3,7 @@ import { NextPage } from "next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { Grid, CircularProgress } from "@mui/material";
|
import { Grid, CircularProgress } from "@mui/material";
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
|
|
||||||
const Setup: NextPage = () => {
|
const Setup: NextPage = () => {
|
||||||
const {
|
const {
|
||||||
|
|
@ -2,12 +2,11 @@ import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { Grid, Box } from "@mui/material";
|
import { Grid, Box } from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { Layout } from "components/Layout";
|
import { getTrends } from "@/app/_lib/opensearch";
|
||||||
import { getTrends } from "lib/opensearch";
|
import { PageHeader } from "@/app/_components/PageHeader";
|
||||||
import { PageHeader } from "components/PageHeader";
|
import { VisualizationCard } from "@/app/_components/VisualizationCard";
|
||||||
import { VisualizationCard } from "components/VisualizationCard";
|
import { useAppContext } from "@/app/_components/AppProvider";
|
||||||
import { useAppContext } from "components/AppProvider";
|
import { getEmbedded } from "@/app/_lib/utils";
|
||||||
import { getEmbedded } from "lib/utils";
|
|
||||||
|
|
||||||
type TrendsProps = {
|
type TrendsProps = {
|
||||||
visualizations: any;
|
visualizations: any;
|
||||||
|
|
@ -22,10 +21,7 @@ const Trends: NextPage<TrendsProps> = ({ visualizations, embedded }) => {
|
||||||
} = useAppContext();
|
} = useAppContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout embedded={embedded}>
|
<>
|
||||||
<Head>
|
|
||||||
<title>Digital Threat Dashboard – Leafcutter</title>
|
|
||||||
</Head>
|
|
||||||
<PageHeader backgroundColor={cdrLinkOrange}>
|
<PageHeader backgroundColor={cdrLinkOrange}>
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
|
|
@ -73,7 +69,7 @@ const Trends: NextPage<TrendsProps> = ({ visualizations, embedded }) => {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
|
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
|
||||||
import { Client } from "@opensearch-project/opensearch";
|
import { Client } from "@opensearch-project/opensearch";
|
||||||
import Head from "next/head";
|
import { VisualizationDetail } from "@/app/_components/VisualizationDetail";
|
||||||
import { Layout } from "components/Layout";
|
import { getEmbedded } from "@/app/_lib/utils";
|
||||||
import { VisualizationDetail } from "components/VisualizationDetail";
|
|
||||||
import { getEmbedded } from "lib/utils";
|
|
||||||
|
|
||||||
type VisualizationProps = {
|
type VisualizationProps = {
|
||||||
visualization: any;
|
visualization: any;
|
||||||
|
|
@ -14,14 +12,7 @@ type VisualizationProps = {
|
||||||
const Visualization: NextPage<VisualizationProps> = ({
|
const Visualization: NextPage<VisualizationProps> = ({
|
||||||
visualization,
|
visualization,
|
||||||
embedded,
|
embedded,
|
||||||
}) => (
|
}) => <VisualizationDetail {...visualization} />;
|
||||||
<Layout embedded={embedded}>
|
|
||||||
<Head>
|
|
||||||
<title>Digital Threat Dashboard – Leafcutter</title>
|
|
||||||
</Head>
|
|
||||||
<VisualizationDetail {...visualization} />
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Visualization;
|
export default Visualization;
|
||||||
|
|
||||||
|
|
@ -23,13 +23,13 @@
|
||||||
"@mui/icons-material": "^5",
|
"@mui/icons-material": "^5",
|
||||||
"@mui/lab": "^5.0.0-alpha.134",
|
"@mui/lab": "^5.0.0-alpha.134",
|
||||||
"@mui/material": "^5",
|
"@mui/material": "^5",
|
||||||
"@mui/x-data-grid-pro": "^6.8.0",
|
"@mui/x-data-grid-pro": "^6.9.0",
|
||||||
"@mui/x-date-pickers-pro": "^6.8.0",
|
"@mui/x-date-pickers-pro": "^6.9.0",
|
||||||
"@opensearch-project/opensearch": "^2.0.0",
|
"@opensearch-project/opensearch": "^2.0.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^2.0.6",
|
||||||
"material-ui-popup-state": "^5.0.9",
|
"material-ui-popup-state": "^5.0.9",
|
||||||
"next": "13.4.6",
|
"next": "13.4.7",
|
||||||
"next-auth": "^4.22.1",
|
"next-auth": "^4.22.1",
|
||||||
"next-http-proxy-middleware": "^1.2.5",
|
"next-http-proxy-middleware": "^1.2.5",
|
||||||
"nodemailer": "^6.9.3",
|
"nodemailer": "^6.9.3",
|
||||||
|
|
@ -41,18 +41,19 @@
|
||||||
"react-markdown": "^8.0.7",
|
"react-markdown": "^8.0.7",
|
||||||
"react-polyglot": "^0.7.2",
|
"react-polyglot": "^0.7.2",
|
||||||
"sharp": "^0.32.1",
|
"sharp": "^0.32.1",
|
||||||
"swr": "^2.1.5",
|
"swr": "^2.2.0",
|
||||||
|
"tss-react": "^4.8.6",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.22.5",
|
"@babel/core": "^7.22.5",
|
||||||
"@types/react": "18.2.13",
|
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
|
"@types/react": "18.2.14",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.43.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-next": "^13.4.6",
|
"eslint-config-next": "^13.4.7",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
/* eslint-disable react/jsx-props-no-spreading */
|
|
||||||
import { AppProps } from "next/app";
|
|
||||||
import { SessionProvider } from "next-auth/react";
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import Head from "next/head";
|
|
||||||
import { CssBaseline } from "@mui/material";
|
|
||||||
import { CacheProvider, EmotionCache } from "@emotion/react";
|
|
||||||
import { CookiesProvider } from "react-cookie";
|
|
||||||
import { I18n } from "react-polyglot";
|
|
||||||
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns";
|
|
||||||
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
|
||||||
import { AppProvider } from "components/AppProvider";
|
|
||||||
import createEmotionCache from "lib/createEmotionCache";
|
|
||||||
import Favicon from "images/favicon.ico";
|
|
||||||
import en from "locales/en.json";
|
|
||||||
import fr from "locales/fr.json";
|
|
||||||
import "@fontsource/poppins/400.css";
|
|
||||||
import "@fontsource/poppins/700.css";
|
|
||||||
import "@fontsource/roboto/400.css";
|
|
||||||
import "@fontsource/roboto/700.css";
|
|
||||||
import "@fontsource/playfair-display/900.css";
|
|
||||||
import "styles/global.css";
|
|
||||||
import { LicenseInfo } from "@mui/x-data-grid-pro";
|
|
||||||
|
|
||||||
LicenseInfo.setLicenseKey(process.env.MUI_LICENSE_KEY ?? "");
|
|
||||||
|
|
||||||
const clientSideEmotionCache: any = createEmotionCache();
|
|
||||||
|
|
||||||
const messages: any = { en, fr };
|
|
||||||
|
|
||||||
interface LeafcutterWebProps extends AppProps {
|
|
||||||
// eslint-disable-next-line react/require-default-props
|
|
||||||
emotionCache?: EmotionCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LeafcutterWeb = (props: LeafcutterWebProps) => {
|
|
||||||
const { locale = "en" } = useRouter();
|
|
||||||
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<link rel="icon" type="image/png" href={Favicon.src} />
|
|
||||||
</Head>
|
|
||||||
<SessionProvider session={(pageProps as any).session}>
|
|
||||||
<CacheProvider value={emotionCache}>
|
|
||||||
<CookiesProvider>
|
|
||||||
<CssBaseline />
|
|
||||||
<AppProvider>
|
|
||||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
|
||||||
<I18n locale={locale} messages={messages[locale]}>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</I18n>
|
|
||||||
</LocalizationProvider>
|
|
||||||
</AppProvider>
|
|
||||||
</CookiesProvider>
|
|
||||||
</CacheProvider>
|
|
||||||
</SessionProvider>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LeafcutterWeb;
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
// eslint-disable-next-line no-use-before-define
|
|
||||||
import * as React from "react";
|
|
||||||
import Document, { Html, Head, Main, NextScript } from "next/document";
|
|
||||||
import createEmotionServer from "@emotion/server/create-instance";
|
|
||||||
import createEmotionCache from "lib/createEmotionCache";
|
|
||||||
|
|
||||||
export default class LeafcutterDocument extends Document {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Html lang="en">
|
|
||||||
<Head />
|
|
||||||
<body>
|
|
||||||
<Main />
|
|
||||||
<NextScript />
|
|
||||||
</body>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LeafcutterDocument.getInitialProps = async (ctx): Promise<any> => {
|
|
||||||
const originalRenderPage = ctx.renderPage;
|
|
||||||
const cache = createEmotionCache();
|
|
||||||
const { extractCriticalToChunks } = createEmotionServer(cache as any);
|
|
||||||
|
|
||||||
ctx.renderPage = () =>
|
|
||||||
originalRenderPage({
|
|
||||||
enhanceApp: (App: any) => (props: any) =>
|
|
||||||
<App emotionCache={cache} {...props} />,
|
|
||||||
});
|
|
||||||
|
|
||||||
const initialProps = await Document.getInitialProps(ctx);
|
|
||||||
const emotionStyles = extractCriticalToChunks(initialProps.html);
|
|
||||||
const emotionStyleTags = emotionStyles.styles.map((style) => (
|
|
||||||
<style
|
|
||||||
data-emotion={`${style.key} ${style.ids.join(" ")}`}
|
|
||||||
key={style.key}
|
|
||||||
// eslint-disable-next-line react/no-danger
|
|
||||||
dangerouslySetInnerHTML={{ __html: style.css }}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
return {
|
|
||||||
...initialProps,
|
|
||||||
styles: [
|
|
||||||
...React.Children.toArray(initialProps.styles),
|
|
||||||
...emotionStyleTags,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
|
||||||
import { getToken } from "next-auth/jwt";
|
|
||||||
import { getTrends } from "lib/opensearch";
|
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|
||||||
const session = await getToken({
|
|
||||||
req,
|
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
return res.redirect("/login");
|
|
||||||
}
|
|
||||||
|
|
||||||
const results = await getTrends(5);
|
|
||||||
return res.json(results)
|
|
||||||
};
|
|
||||||
|
|
||||||
export default handler;
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Button as MUIButton } from "@mui/material";
|
import { Button as MUIButton } from "@mui/material";
|
||||||
22
apps/link/app/_components/DisplayError.tsx
Normal file
22
apps/link/app/_components/DisplayError.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Box, Grid } from "@mui/material";
|
||||||
|
|
||||||
|
type DisplayErrorProps = {
|
||||||
|
error: Error;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DisplayError: FC<DisplayErrorProps> = ({ error }) => (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
direction="column"
|
||||||
|
justifyContent="space-around"
|
||||||
|
alignItems="center"
|
||||||
|
style={{ height: 600, width: "100%", color: "red", fontSize: 20 }}
|
||||||
|
>
|
||||||
|
<Grid item>
|
||||||
|
<Box>{`Error: ${error.message}`}</Box>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
6
apps/link/app/_components/Home.tsx
Normal file
6
apps/link/app/_components/Home.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC } from "react";
|
||||||
|
import { ZammadWrapper } from "@/app/_components/ZammadWrapper";
|
||||||
|
|
||||||
|
export const Home: FC = () => <ZammadWrapper path="/#dashboard" hideSidebar />;
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { FC, useState } from "react";
|
"use client";
|
||||||
|
|
||||||
|
import { FC, PropsWithChildren, useState } from "react";
|
||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
import { Sidebar } from "./Sidebar";
|
import { Sidebar } from "./Sidebar";
|
||||||
|
|
||||||
export const Layout = ({ children }) => {
|
export const InternalLayout: FC<PropsWithChildren> = ({ children }) => {
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -12,7 +14,7 @@ export const Layout = ({ children }) => {
|
||||||
item
|
item
|
||||||
sx={{ ml: open ? "270px" : "100px", width: "100%", height: "100vh" }}
|
sx={{ ml: open ? "270px" : "100px", width: "100%", height: "100vh" }}
|
||||||
>
|
>
|
||||||
{children}
|
{children as any}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
57
apps/link/app/_components/MultiProvider.tsx
Normal file
57
apps/link/app/_components/MultiProvider.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC, PropsWithChildren, useState } from "react";
|
||||||
|
import { CssBaseline } from "@mui/material";
|
||||||
|
import { CookiesProvider } from "react-cookie";
|
||||||
|
import { SessionProvider } from "next-auth/react";
|
||||||
|
import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";
|
||||||
|
import { SWRConfig } from "swr";
|
||||||
|
import { GraphQLClient } from "graphql-request";
|
||||||
|
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns";
|
||||||
|
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
||||||
|
|
||||||
|
export const MultiProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
|
const [csrfToken, setCsrfToken] = useState("");
|
||||||
|
const origin =
|
||||||
|
typeof window !== "undefined" && window.location.origin
|
||||||
|
? window.location.origin
|
||||||
|
: null;
|
||||||
|
const client = new GraphQLClient(`${origin}/proxy/zammad/graphql`, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const graphQLFetcher = async ({ document, variables }: any) => {
|
||||||
|
const requestHeaders = {
|
||||||
|
"X-CSRF-Token": csrfToken,
|
||||||
|
};
|
||||||
|
const { data, headers } = await client.rawRequest(
|
||||||
|
document,
|
||||||
|
variables,
|
||||||
|
requestHeaders
|
||||||
|
);
|
||||||
|
|
||||||
|
const token = headers.get("CSRF-Token");
|
||||||
|
setCsrfToken(token);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CssBaseline />
|
||||||
|
<NextAppDirEmotionCacheProvider options={{ key: "css" }}>
|
||||||
|
<SWRConfig value={{ fetcher: graphQLFetcher }}>
|
||||||
|
<SessionProvider>
|
||||||
|
<CookiesProvider>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
|
{children}
|
||||||
|
</LocalizationProvider>
|
||||||
|
</CookiesProvider>
|
||||||
|
</SessionProvider>
|
||||||
|
</SWRConfig>
|
||||||
|
</NextAppDirEmotionCacheProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import {
|
import {
|
||||||
|
|
@ -22,12 +24,12 @@ import {
|
||||||
ExpandCircleDown as ExpandCircleDownIcon,
|
ExpandCircleDown as ExpandCircleDownIcon,
|
||||||
Dvr as DvrIcon,
|
Dvr as DvrIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useRouter } from "next/router";
|
import { usePathname } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import LinkLogo from "public/link-logo-small.png";
|
import LinkLogo from "public/link-logo-small.png";
|
||||||
import { useSession, signOut } from "next-auth/react";
|
import { useSession, signOut } from "next-auth/react";
|
||||||
import { getTicketOverviewCountsQuery } from "graphql/getTicketOverviewCountsQuery";
|
import { getTicketOverviewCountsQuery } from "@/app/_graphql/getTicketOverviewCountsQuery";
|
||||||
|
|
||||||
const openWidth = 270;
|
const openWidth = 270;
|
||||||
const closedWidth = 100;
|
const closedWidth = 100;
|
||||||
|
|
@ -157,8 +159,7 @@ interface SidebarProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
const router = useRouter();
|
const pathname = usePathname();
|
||||||
const { pathname } = router;
|
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
const username = session?.user?.name || "User";
|
const username = session?.user?.name || "User";
|
||||||
const { data: overviewData, error: overviewError }: any = useSWR(
|
const { data: overviewData, error: overviewError }: any = useSWR(
|
||||||
|
|
@ -358,14 +359,20 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Tickets"
|
name="Tickets"
|
||||||
href="/tickets/assigned"
|
href="/overview/assigned"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
selected={pathname.startsWith("/tickets")}
|
selected={
|
||||||
|
pathname.startsWith("/overview") ||
|
||||||
|
pathname.startsWith("/tickets")
|
||||||
|
}
|
||||||
iconSize={20}
|
iconSize={20}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<Collapse
|
<Collapse
|
||||||
in={pathname.startsWith("/tickets")}
|
in={
|
||||||
|
pathname.startsWith("/overview") ||
|
||||||
|
pathname.startsWith("/tickets")
|
||||||
|
}
|
||||||
timeout="auto"
|
timeout="auto"
|
||||||
unmountOnExit
|
unmountOnExit
|
||||||
onClick={undefined}
|
onClick={undefined}
|
||||||
|
|
@ -373,37 +380,37 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
<List component="div" disablePadding>
|
<List component="div" disablePadding>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Assigned"
|
name="Assigned"
|
||||||
href="/tickets/assigned"
|
href="/overview/assigned"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/assigned")}
|
selected={pathname.endsWith("/overview/assigned")}
|
||||||
badge={assignedCount}
|
badge={assignedCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Urgent"
|
name="Urgent"
|
||||||
href="/tickets/urgent"
|
href="/overview/urgent"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/urgent")}
|
selected={pathname.endsWith("/overview/urgent")}
|
||||||
badge={urgentCount}
|
badge={urgentCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Pending"
|
name="Pending"
|
||||||
href="/tickets/pending"
|
href="/overview/pending"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/pending")}
|
selected={pathname.endsWith("/overview/pending")}
|
||||||
badge={pendingCount}
|
badge={pendingCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Unassigned"
|
name="Unassigned"
|
||||||
href="/tickets/unassigned"
|
href="/overview/unassigned"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/unassigned")}
|
selected={pathname.endsWith("/overview/unassigned")}
|
||||||
badge={unassignedCount}
|
badge={unassignedCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import getConfig from "next/config";
|
import getConfig from "next/config";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/navigation";
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
|
|
||||||
type InternalZammadWrapperProps = {
|
type ZammadWrapperProps = {
|
||||||
path: string;
|
path: string;
|
||||||
hideSidebar?: boolean;
|
hideSidebar?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InternalZammadWrapper: FC<InternalZammadWrapperProps> = ({
|
export const ZammadWrapper: FC<ZammadWrapperProps> = ({
|
||||||
path,
|
path,
|
||||||
hideSidebar = true,
|
hideSidebar = true,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [display, setDisplay] = useState("none");
|
const [display, setDisplay] = useState("inherit");
|
||||||
const {
|
//const {
|
||||||
publicRuntimeConfig: { linkURL },
|
// publicRuntimeConfig: { linkURL },
|
||||||
} = getConfig();
|
// } = getConfig();
|
||||||
|
const linkURL = "http://localhost:3000";
|
||||||
const url = `${linkURL}/proxy/zammad${path}`;
|
const url = `${linkURL}/proxy/zammad${path}`;
|
||||||
console.log({ url });
|
console.log({ url });
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Grid } from "@mui/material";
|
||||||
|
import Iframe from "react-iframe";
|
||||||
|
|
||||||
|
export const LabelStudioWrapper: FC = () => (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={0}
|
||||||
|
sx={{ height: "100%", width: "100%" }}
|
||||||
|
direction="column"
|
||||||
|
>
|
||||||
|
<Grid item sx={{ height: "100vh", width: "100%" }}>
|
||||||
|
<Iframe
|
||||||
|
id="link"
|
||||||
|
url={"https://label-studio:3000"}
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
frameBorder={0}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
10
apps/link/app/admin/label-studio/page.tsx
Normal file
10
apps/link/app/admin/label-studio/page.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { LabelStudioWrapper } from "./_components/LabelStudioWrapper";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Label Studio",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <LabelStudioWrapper />;
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,21 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Head from "next/head";
|
import getConfig from "next/config";
|
||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
import { Layout } from "components/Layout";
|
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
|
|
||||||
const LabelStudio: FC = () => (
|
type MetamigoWrapperProps = {
|
||||||
<Layout>
|
path: string;
|
||||||
<Head>
|
};
|
||||||
<title>Link Shell</title>
|
|
||||||
</Head>
|
export const MetamigoWrapper: FC<MetamigoWrapperProps> = ({ path }) => {
|
||||||
|
const {
|
||||||
|
publicRuntimeConfig: { linkURL },
|
||||||
|
} = getConfig();
|
||||||
|
const fullMetamigoURL = `${linkURL}/metamigo/${path}`;
|
||||||
|
|
||||||
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
spacing={0}
|
spacing={0}
|
||||||
|
|
@ -18,14 +25,12 @@ const LabelStudio: FC = () => (
|
||||||
<Grid item sx={{ height: "100vh", width: "100%" }}>
|
<Grid item sx={{ height: "100vh", width: "100%" }}>
|
||||||
<Iframe
|
<Iframe
|
||||||
id="link"
|
id="link"
|
||||||
url={"https://label-studio:3000"}
|
url={fullMetamigoURL}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
frameBorder={0}
|
frameBorder={0}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Layout>
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
export default LabelStudio;
|
|
||||||
16
apps/link/app/admin/metamigo/[...path]/page.tsx
Normal file
16
apps/link/app/admin/metamigo/[...path]/page.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { MetamigoWrapper } from "./_components/MetamigoWrapper";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Metamigo",
|
||||||
|
};
|
||||||
|
|
||||||
|
type PageProps = {
|
||||||
|
params: {
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Page({ params: { path } }: PageProps) {
|
||||||
|
return <MetamigoWrapper path={path} />;
|
||||||
|
}
|
||||||
10
apps/link/app/admin/zammad/page.tsx
Normal file
10
apps/link/app/admin/zammad/page.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { ZammadWrapper } from "@/app/_components/ZammadWrapper";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Zammad",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <ZammadWrapper path="/#manage" hideSidebar={false} />;
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import NextAuth from "next-auth";
|
||||||
import Google from "next-auth/providers/google";
|
import Google from "next-auth/providers/google";
|
||||||
// import Apple from "next-auth/providers/apple";
|
// import Apple from "next-auth/providers/apple";
|
||||||
|
|
||||||
export default NextAuth({
|
const handler = NextAuth({
|
||||||
providers: [
|
providers: [
|
||||||
Google({
|
Google({
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||||
|
|
@ -17,3 +17,6 @@ export default NextAuth({
|
||||||
],
|
],
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export { handler as GET, handler as POST };
|
||||||
7
apps/link/app/api/v1/users/route.ts
Normal file
7
apps/link/app/api/v1/users/route.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
const handler = (req: NextRequest) => {
|
||||||
|
NextResponse.redirect('/proxy/zammad/api/v1' + req.url.substring('/api/v1'.length));
|
||||||
|
};
|
||||||
|
|
||||||
|
export { handler as GET, handler as POST };
|
||||||
11
apps/link/app/error.tsx
Normal file
11
apps/link/app/error.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { DisplayError } from "./_components/DisplayError";
|
||||||
|
|
||||||
|
type PageProps = {
|
||||||
|
error: Error;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Page({ error }: PageProps) {
|
||||||
|
return <DisplayError error={error} />;
|
||||||
|
}
|
||||||
10
apps/link/app/knowledge/page.tsx
Normal file
10
apps/link/app/knowledge/page.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { ZammadWrapper } from "@/app/_components/ZammadWrapper";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Knowledge Base",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <ZammadWrapper path="/#knowledge_base/1/locale/en-us" />;
|
||||||
|
}
|
||||||
35
apps/link/app/layout.tsx
Normal file
35
apps/link/app/layout.tsx
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import "./_styles/global.css";
|
||||||
|
import "@fontsource/poppins/400.css";
|
||||||
|
import "@fontsource/poppins/700.css";
|
||||||
|
import "@fontsource/roboto/400.css";
|
||||||
|
import "@fontsource/roboto/700.css";
|
||||||
|
import "@fontsource/playfair-display/900.css";
|
||||||
|
// import getConfig from "next/config";
|
||||||
|
// import { LicenseInfo } from "@mui/x-data-grid-pro";
|
||||||
|
import { MultiProvider } from "./_components/MultiProvider";
|
||||||
|
import { InternalLayout } from "./_components/InternalLayout";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Link",
|
||||||
|
};
|
||||||
|
|
||||||
|
type LayoutProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Layout({ children }: LayoutProps) {
|
||||||
|
// const { publicRuntimeConfig } = getConfig();
|
||||||
|
// LicenseInfo.setLicenseKey(publicRuntimeConfig.muiLicenseKey);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
<MultiProvider>
|
||||||
|
<InternalLayout>{children}</InternalLayout>
|
||||||
|
</MultiProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC } from "react";
|
||||||
|
import getConfig from "next/config";
|
||||||
|
import { Grid } from "@mui/material";
|
||||||
|
import Iframe from "react-iframe";
|
||||||
|
|
||||||
|
type LeafcutterWrapperProps = {
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LeafcutterWrapper: FC<LeafcutterWrapperProps> = ({ path }) => {
|
||||||
|
const {
|
||||||
|
publicRuntimeConfig: { linkURL },
|
||||||
|
} = getConfig();
|
||||||
|
const fullLeafcutterURL = `${linkURL}/proxy/leafcutter/${path}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={0}
|
||||||
|
sx={{ height: "100%", width: "100%" }}
|
||||||
|
direction="column"
|
||||||
|
>
|
||||||
|
<Grid item sx={{ height: "100vh", width: "100%" }}>
|
||||||
|
<Iframe
|
||||||
|
id="leafcutter"
|
||||||
|
url={fullLeafcutterURL}
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
frameBorder={0}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
||||||
11
apps/link/app/leafcutter/[view]/page.tsx
Normal file
11
apps/link/app/leafcutter/[view]/page.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { LeafcutterWrapper } from "./_components/LeafcutterWrapper";
|
||||||
|
|
||||||
|
type PageProps = {
|
||||||
|
params: {
|
||||||
|
view: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Page({ params: { view } }: PageProps) {
|
||||||
|
<LeafcutterWrapper path={view} />;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue