WIP 5
This commit is contained in:
parent
b8c6e893ff
commit
b09cc82544
167 changed files with 2196 additions and 1302 deletions
|
|
@ -9,7 +9,7 @@ import { useTranslate } from "react-polyglot";
|
||||||
import { LanguageSelect } from "app/_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 } from "next-auth/react";
|
import { signIn } from "next-auth/react";
|
||||||
import { useAppContext } from "app/_components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui";
|
||||||
|
|
||||||
type LoginProps = {
|
type LoginProps = {
|
||||||
session: any;
|
session: any;
|
||||||
|
|
@ -20,7 +20,7 @@ export const Login: FC<LoginProps> = ({ session }) => {
|
||||||
const {
|
const {
|
||||||
colors: { leafcutterElectricBlue, lightGray },
|
colors: { leafcutterElectricBlue, lightGray },
|
||||||
typography: { h1, h4 },
|
typography: { h1, h4 },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const buttonStyles = {
|
const buttonStyles = {
|
||||||
backgroundColor: lightGray,
|
backgroundColor: lightGray,
|
||||||
borderRadius: 500,
|
borderRadius: 500,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { About } from "leafcutter-common";
|
import { About } from "leafcutter-ui";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return <About />;
|
return <About />;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getTemplates } from "app/_lib/opensearch";
|
import { getTemplates } from "app/_lib/opensearch";
|
||||||
import { Create } from "leafcutter-common";
|
import { Create } from "leafcutter-ui";
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const templates = await getTemplates(100);
|
const templates = await getTemplates(100);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { FAQ } from "leafcutter-common";
|
import { FAQ } from "leafcutter-ui";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return <FAQ />;
|
return <FAQ />;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import "app/_styles/global.css";
|
import "app/_styles/global.css";
|
||||||
// import getConfig from "next/config";
|
|
||||||
// import { LicenseInfo } from "@mui/x-data-grid-pro";
|
|
||||||
import { InternalLayout } from "../_components/InternalLayout";
|
import { InternalLayout } from "../_components/InternalLayout";
|
||||||
|
|
||||||
type LayoutProps = {
|
type LayoutProps = {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "app/_lib/auth";
|
import { authOptions } from "app/_lib/auth";
|
||||||
import { getUserVisualizations } from "app/_lib/opensearch";
|
import { getUserVisualizations } from "app/_lib/opensearch";
|
||||||
import { Home } from "leafcutter-common";
|
import { Home } from "leafcutter-ui";
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const session = await getServerSession(authOptions);
|
const session = await getServerSession(authOptions);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
// import { Client } from "@opensearch-project/opensearch";
|
// import { Client } from "@opensearch-project/opensearch";
|
||||||
import { Preview } from "leafcutter-common";
|
import { Preview } from "leafcutter-ui";
|
||||||
// import { createVisualization } from "lib/opensearch";
|
// import { createVisualization } from "lib/opensearch";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { useLayoutEffect } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
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 "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
|
|
||||||
export const Setup: FC = () => {
|
export const Setup: FC = () => {
|
||||||
const {
|
const {
|
||||||
colors: { leafcutterElectricBlue },
|
colors: { leafcutterElectricBlue },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setTimeout(() => router.push("/"), 4000);
|
setTimeout(() => router.push("/"), 4000);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getTrends } from "app/_lib/opensearch";
|
import { getTrends } from "app/_lib/opensearch";
|
||||||
import { Trends } from "leafcutter-common";
|
import { Trends } from "leafcutter-ui";
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const visualizations = await getTrends(25);
|
const visualizations = await getTrends(25);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
import { Client } from "@opensearch-project/opensearch";
|
import { Client } from "@opensearch-project/opensearch";
|
||||||
import { VisualizationDetail } from "leafcutter-common";
|
import { VisualizationDetail } from "leafcutter-ui";
|
||||||
|
|
||||||
const getVisualization = async (visualizationID: string) => {
|
const getVisualization = async (visualizationID: string) => {
|
||||||
const node = `https://${process.env.OPENSEARCH_USERNAME}:${process.env.OPENSEARCH_PASSWORD}@${process.env.OPENSEARCH_URL}`;
|
const node = `https://${process.env.OPENSEARCH_USERNAME}:${process.env.OPENSEARCH_PASSWORD}@${process.env.OPENSEARCH_URL}`;
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ import {
|
||||||
bindTrigger,
|
bindTrigger,
|
||||||
bindMenu,
|
bindMenu,
|
||||||
} from "material-ui-popup-state/hooks";
|
} from "material-ui-popup-state/hooks";
|
||||||
import { useAppContext } from "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
|
|
||||||
export const AccountButton: FC = () => {
|
export const AccountButton: FC = () => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
const {
|
const {
|
||||||
colors: { leafcutterElectricBlue },
|
colors: { leafcutterElectricBlue },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const popupState = usePopupState({ variant: "popover", popupId: "account" });
|
const popupState = usePopupState({ variant: "popover", popupId: "account" });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
useState,
|
useState,
|
||||||
PropsWithChildren,
|
PropsWithChildren,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { colors, typography } from "leafcutter-common/styles/theme";
|
import { colors, typography } from "leafcutter-ui/styles/theme";
|
||||||
|
|
||||||
const basePath = process.env.GITLAB_CI
|
const basePath = process.env.GITLAB_CI
|
||||||
? "/link/link-stack/apps/leafcutter"
|
? "/link/link-stack/apps/leafcutter"
|
||||||
|
|
@ -29,7 +29,7 @@ const AppContext = createContext({
|
||||||
setFoundCount: null as any,
|
setFoundCount: null as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AppProvider: FC<PropsWithChildren> = ({ children }) => {
|
export const LeafcutterProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
const initialState = {
|
const initialState = {
|
||||||
incidentType: {
|
incidentType: {
|
||||||
display: "Incident Type",
|
display: "Incident Type",
|
||||||
|
|
@ -156,6 +156,6 @@ export const AppProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useAppContext() {
|
export function useLeafcutterContext() {
|
||||||
return useContext(AppContext);
|
return useContext(AppContext);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { FC, useState } from "react";
|
||||||
import { useRouter, usePathname } from "next/navigation";
|
import { useRouter, usePathname } from "next/navigation";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import { QuestionMark as QuestionMarkIcon } from "@mui/icons-material";
|
import { QuestionMark as QuestionMarkIcon } from "@mui/icons-material";
|
||||||
import { useAppContext } from "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
|
|
||||||
export const HelpButton: FC = () => {
|
export const HelpButton: FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -12,7 +12,7 @@ export const HelpButton: FC = () => {
|
||||||
const [helpActive, setHelpActive] = useState(false);
|
const [helpActive, setHelpActive] = useState(false);
|
||||||
const {
|
const {
|
||||||
colors: { leafcutterElectricBlue },
|
colors: { leafcutterElectricBlue },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
if (helpActive) {
|
if (helpActive) {
|
||||||
router.push(pathname);
|
router.push(pathname);
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import CookieConsent from "react-cookie-consent";
|
||||||
import { useCookies } from "react-cookie";
|
import { useCookies } from "react-cookie";
|
||||||
import { TopNav } from "./TopNav";
|
import { TopNav } from "./TopNav";
|
||||||
import { Sidebar } from "./Sidebar";
|
import { Sidebar } from "./Sidebar";
|
||||||
import { GettingStartedDialog } from "leafcutter-common";
|
import { GettingStartedDialog } from "leafcutter-ui";
|
||||||
import { useAppContext } from "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
// import { Footer } from "./Footer";
|
// import { Footer } from "./Footer";
|
||||||
|
|
||||||
type LayoutProps = PropsWithChildren<{
|
type LayoutProps = PropsWithChildren<{
|
||||||
|
|
@ -29,7 +29,7 @@ export const InternalLayout: FC<LayoutProps> = ({
|
||||||
cdrLinkOrange,
|
cdrLinkOrange,
|
||||||
helpYellow,
|
helpYellow,
|
||||||
},
|
},
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import {
|
||||||
bindTrigger,
|
bindTrigger,
|
||||||
bindMenu,
|
bindMenu,
|
||||||
} from "material-ui-popup-state/hooks";
|
} from "material-ui-popup-state/hooks";
|
||||||
import { useAppContext } from "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
// import { Tooltip } from "./Tooltip";
|
// import { Tooltip } from "./Tooltip";
|
||||||
|
|
||||||
export const LanguageSelect = () => {
|
export const LanguageSelect = () => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue },
|
colors: { white, leafcutterElectricBlue },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const locales: any = { en: "English", fr: "Français" };
|
const locales: any = { en: "English", fr: "Français" };
|
||||||
const locale = "en";
|
const locale = "en";
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ import { CookiesProvider } from "react-cookie";
|
||||||
import { I18n } from "react-polyglot";
|
import { I18n } from "react-polyglot";
|
||||||
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFnsV3";
|
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFnsV3";
|
||||||
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
||||||
import { AppProvider } from "leafcutter-common/components/AppProvider";
|
import { LeafcutterProvider } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";
|
import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";
|
||||||
import en from "leafcutter-common/locales/en.json";
|
import en from "leafcutter-ui/locales/en.json";
|
||||||
import fr from "leafcutter-common/locales/fr.json";
|
import fr from "leafcutter-ui/locales/fr.json";
|
||||||
import { LicenseInfo } from "@mui/x-date-pickers-pro";
|
import { LicenseInfo } from "@mui/x-date-pickers-pro";
|
||||||
|
|
||||||
LicenseInfo.setLicenseKey(
|
LicenseInfo.setLicenseKey(
|
||||||
|
|
@ -29,13 +29,13 @@ export const MultiProvider: FC<PropsWithChildren> = ({ children }: any) => {
|
||||||
<SessionProvider>
|
<SessionProvider>
|
||||||
<CookiesProvider>
|
<CookiesProvider>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<AppProvider>
|
<LeafcutterProvider>
|
||||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
<I18n locale={locale} messages={messages[locale]}>
|
<I18n locale={locale} messages={messages[locale]}>
|
||||||
{children}
|
{children}
|
||||||
</I18n>
|
</I18n>
|
||||||
</LocalizationProvider>
|
</LocalizationProvider>
|
||||||
</AppProvider>
|
</LeafcutterProvider>
|
||||||
</CookiesProvider>
|
</CookiesProvider>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
</NextAppDirEmotionCacheProvider>
|
</NextAppDirEmotionCacheProvider>
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import {
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
import { Tooltip } from "leafcutter-common";
|
import { Tooltip } from "leafcutter-ui";
|
||||||
// import { ArrowCircleRight as ArrowCircleRightIcon } from "@mui/icons-material";
|
// import { ArrowCircleRight as ArrowCircleRightIcon } from "@mui/icons-material";
|
||||||
|
|
||||||
const MenuItem = ({
|
const MenuItem = ({
|
||||||
|
|
@ -43,7 +43,7 @@ const MenuItem = ({
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
colors: { leafcutterLightBlue, black },
|
colors: { leafcutterLightBlue, black },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={href} passHref>
|
<Link href={href} passHref>
|
||||||
|
|
@ -105,7 +105,7 @@ export const Sidebar: FC<SidebarProps> = ({ open }) => {
|
||||||
const section = pathname?.split("/")[1];
|
const section = pathname?.split("/")[1];
|
||||||
const {
|
const {
|
||||||
colors: { white }, // leafcutterElectricBlue, leafcutterLightBlue,
|
colors: { white }, // leafcutterElectricBlue, leafcutterLightBlue,
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
// const [recentUpdates, setRecentUpdates] = useState([]);
|
// const [recentUpdates, setRecentUpdates] = useState([]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import { useTranslate } from "react-polyglot";
|
||||||
import LeafcutterLogo from "images/leafcutter-logo.png";
|
import LeafcutterLogo from "images/leafcutter-logo.png";
|
||||||
import { AccountButton } from "./AccountButton";
|
import { AccountButton } from "./AccountButton";
|
||||||
import { HelpButton } from "./HelpButton";
|
import { HelpButton } from "./HelpButton";
|
||||||
import { Tooltip } from "leafcutter-common";
|
import { Tooltip } from "leafcutter-ui";
|
||||||
import { useAppContext } from "leafcutter-common/components/AppProvider";
|
import { useLeafcutterContext } from "leafcutter-ui/components/LeafcutterProvider";
|
||||||
// import { LanguageSelect } from "./LanguageSelect";
|
// import { LanguageSelect } from "./LanguageSelect";
|
||||||
|
|
||||||
export const TopNav: FC = () => {
|
export const TopNav: FC = () => {
|
||||||
|
|
@ -17,7 +17,7 @@ export const TopNav: FC = () => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue, cdrLinkOrange },
|
colors: { white, leafcutterElectricBlue, cdrLinkOrange },
|
||||||
typography: { h5, h6 },
|
typography: { h5, h6 },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar
|
<AppBar
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
import { withAuth } from "next-auth/middleware";
|
import { withAuth } from "next-auth/middleware";
|
||||||
|
|
||||||
export default withAuth(
|
export default withAuth(
|
||||||
|
|
@ -6,26 +7,13 @@ export default withAuth(
|
||||||
signIn: `/login`,
|
signIn: `/login`,
|
||||||
},
|
},
|
||||||
callbacks: {
|
callbacks: {
|
||||||
authorized: ({ token, req }) => {
|
authorized: ({ token }) => {
|
||||||
const {
|
// check for existence in opensearch user list
|
||||||
url,
|
|
||||||
} = req;
|
|
||||||
const parsedURL = new URL(url);
|
|
||||||
|
|
||||||
console.log({ url });
|
|
||||||
console.log({ pathname: parsedURL.pathname });
|
|
||||||
console.log({ allowed: parsedURL.pathname.startsWith("/app") });
|
|
||||||
const allowed = parsedURL.pathname.startsWith('/login') || parsedURL.pathname.startsWith('/api' || parsedURL.pathname.startsWith("/app"));
|
|
||||||
if (allowed) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token?.email) {
|
if (token?.email) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -33,6 +21,6 @@ export default withAuth(
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
matcher: [
|
matcher: [
|
||||||
'/((?!api|app|bootstrap|3961|ui|translations|internal|login|node_modules|_next/static|_next/image|favicon.ico).*)',
|
'/((?!api|app|login|_next/static|_next/image|favicon.ico).*)',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const ContentSecurityPolicy = `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
transpilePackages: ["leafcutter-common"],
|
transpilePackages: ["leafcutter-ui", "opensearch-common"],
|
||||||
experimental: {
|
experimental: {
|
||||||
missingSuspenseWithCSRBailout: false,
|
missingSuspenseWithCSRBailout: false,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,20 @@
|
||||||
"@emotion/server": "^11.11.0",
|
"@emotion/server": "^11.11.0",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/icons-material": "^5",
|
"@mui/icons-material": "^5",
|
||||||
"@mui/lab": "^5.0.0-alpha.168",
|
"@mui/lab": "^5.0.0-alpha.169",
|
||||||
"@mui/material": "^5",
|
"@mui/material": "^5",
|
||||||
"@mui/x-data-grid-pro": "^6.19.6",
|
"@mui/x-data-grid-pro": "^6.19.6",
|
||||||
"@mui/x-date-pickers-pro": "^6.19.7",
|
"@mui/x-date-pickers-pro": "^6.19.7",
|
||||||
"@opensearch-project/opensearch": "^2.6.0",
|
"@opensearch-project/opensearch": "^2.6.0",
|
||||||
"cryptr": "^6.3.0",
|
"cryptr": "^6.3.0",
|
||||||
"date-fns": "^3.5.0",
|
"date-fns": "^3.6.0",
|
||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^2.0.6",
|
||||||
"leafcutter-common": "*",
|
"leafcutter-ui": "*",
|
||||||
"material-ui-popup-state": "^5.0.10",
|
"material-ui-popup-state": "^5.1.0",
|
||||||
"next": "14.1.3",
|
"next": "14.1.4",
|
||||||
"next-auth": "^4.24.7",
|
"next-auth": "^4.24.7",
|
||||||
"next-http-proxy-middleware": "^1.2.6",
|
"next-http-proxy-middleware": "^1.2.6",
|
||||||
|
"opensearch-common": "*",
|
||||||
"nodemailer": "^6.9.12",
|
"nodemailer": "^6.9.12",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-cookie": "^7.1.0",
|
"react-cookie": "^7.1.0",
|
||||||
|
|
@ -45,14 +46,14 @@
|
||||||
"uuid": "^9.0.1"
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.0",
|
"@babel/core": "^7.24.1",
|
||||||
"@types/node": "^20.11.28",
|
"@types/node": "^20.11.30",
|
||||||
"@types/react": "18.2.66",
|
"@types/react": "18.2.67",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-next": "^14.1.3",
|
"eslint-config-next": "^14.1.4",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { OpenSearchWrapper } from "leafcutter-common";
|
import { OpenSearchWrapper } from "leafcutter-ui";
|
||||||
|
|
||||||
export const Home: FC = () => (
|
export const Home: FC = () => (
|
||||||
<OpenSearchWrapper
|
<OpenSearchWrapper url="/app/visualize#/edit/237b8f00-e6a0-11ee-94b3-d7b7409294e7?embed=true" marginTop="0"
|
||||||
url="/app/dashboards#/view/c39012d0-eb7a-11ed-8e00-17d7d50cd7b2?embed=true&tenant=global"
|
|
||||||
marginTop="0"
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ 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 "app/_graphql/getTicketOverviewCountsQuery";
|
import { getTicketOverviewCountsQuery } from "app/_graphql/getTicketOverviewCountsQuery";
|
||||||
import { SearchBox } from "./SearchBox";
|
import { SearchBox } from "./SearchBox";
|
||||||
|
import { fonts } from "app/_styles/theme";
|
||||||
|
|
||||||
const openWidth = 270;
|
const openWidth = 270;
|
||||||
const closedWidth = 100;
|
const closedWidth = 100;
|
||||||
|
|
@ -49,8 +50,10 @@ const MenuItem = ({
|
||||||
open = true,
|
open = true,
|
||||||
badge,
|
badge,
|
||||||
target = "_self",
|
target = "_self",
|
||||||
}: any) => (
|
}: any) => {
|
||||||
<Link href={href} target={target}>
|
const { roboto } = fonts;
|
||||||
|
|
||||||
|
return (<Link href={href} target={target}>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
sx={{
|
sx={{
|
||||||
p: 0,
|
p: 0,
|
||||||
|
|
@ -123,7 +126,7 @@ const MenuItem = ({
|
||||||
variant="body1"
|
variant="body1"
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontFamily: "Roboto",
|
fontFamily: roboto.style.fontFamily,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
border: 0,
|
border: 0,
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
|
|
@ -157,6 +160,7 @@ const MenuItem = ({
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
@ -166,6 +170,7 @@ interface SidebarProps {
|
||||||
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
|
const { poppins } = fonts;
|
||||||
const username = session?.user?.name || "User";
|
const username = session?.user?.name || "User";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const roles = session?.user?.roles || [];
|
const roles = session?.user?.roles || [];
|
||||||
|
|
@ -272,7 +277,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
mt: 1,
|
mt: 1,
|
||||||
ml: 0.5,
|
ml: 0.5,
|
||||||
fontFamily: "Poppins",
|
fontFamily: poppins.style.fontFamily,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
CDR Link
|
CDR Link
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { FC, /* useEffect,*/ useState } from "react";
|
|
||||||
import { Home as HomeInternal } from "leafcutter-common";
|
|
||||||
// import { fetchLeafcutter } from "@/app/_lib/utils";
|
|
||||||
import ClientOnly from "@/app/(main)/_components/ClientOnly";
|
|
||||||
|
|
||||||
export const Home: FC = () => {
|
|
||||||
const [visualizations, setVisualizations] = useState([]);
|
|
||||||
/*
|
|
||||||
useEffect(() => {
|
|
||||||
const getVisualizations = async () => {
|
|
||||||
const visualizations = await fetchLeafcutter(
|
|
||||||
"/api/visualizations/list",
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
if (visualizations) {
|
|
||||||
setVisualizations(visualizations);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getVisualizations();
|
|
||||||
}, []);
|
|
||||||
*/
|
|
||||||
return (
|
|
||||||
<ClientOnly>
|
|
||||||
<HomeInternal visualizations={visualizations} />
|
|
||||||
</ClientOnly>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
import { Box } from "@mui/material";
|
import { About } from "leafcutter-ui";
|
||||||
import { About } from "leafcutter-common";
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return <About />;
|
||||||
<Box sx={{ p: 3 }}>
|
|
||||||
<About />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,8 @@
|
||||||
// import { getTemplates } from "app/_lib/opensearch";
|
import { getTemplates } from "opensearch-common";
|
||||||
import { Create } from "leafcutter-common";
|
import { Create } from "leafcutter-ui";
|
||||||
import { Box } from "@mui/material";
|
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const templates = []; // await getTemplates(100);
|
const templates = await getTemplates(100);
|
||||||
|
|
||||||
return (
|
return <Create templates={templates} />;
|
||||||
<Box sx={{ p: 3 }}>
|
|
||||||
<Create templates={templates} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
import { Box } from "@mui/material";
|
import { FAQ } from "leafcutter-ui";
|
||||||
import { FAQ } from "leafcutter-common";
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return <FAQ />;
|
||||||
<Box sx={{ p: 3 }}>
|
|
||||||
<FAQ />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
apps/link/app/(main)/leafcutter/layout.tsx
Normal file
10
apps/link/app/(main)/leafcutter/layout.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import { LeafcutterWrapper } from "leafcutter-ui";
|
||||||
|
|
||||||
|
type LayoutProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Layout({ children }: LayoutProps) {
|
||||||
|
return <LeafcutterWrapper>{children}</LeafcutterWrapper>;
|
||||||
|
}
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import { Box } from "@mui/material";
|
|
||||||
import { FAQ } from "leafcutter-common";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<Box sx={{ p: 3 }}>
|
|
||||||
<FAQ />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Home } from "./_components/Home";
|
import { Home, LeafcutterWrapper } from "leafcutter-ui";
|
||||||
import { LeafcutterWrapper } from "./_components/LeafcutterWrapper";
|
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
import { Box } from "@mui/material";
|
import { Trends } from "leafcutter-ui";
|
||||||
import { Trends } from "leafcutter-common";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<Box sx={{ p: 3 }}>
|
|
||||||
<Trends visualizations={[]} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <Trends visualizations={[]} />;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,23 @@
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { Home } from "./_components/Home";
|
import { getServerSession } from "app/_lib/authentication";
|
||||||
|
import { Home } from "leafcutter-ui";
|
||||||
|
import { getUserVisualizations } from "opensearch-common";
|
||||||
|
import { LeafcutterWrapper } from "leafcutter-ui";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Link",
|
title: "Link",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Page() {
|
export default async function Page() {
|
||||||
return <Home />;
|
const session = await getServerSession();
|
||||||
|
const {
|
||||||
|
user: { email },
|
||||||
|
}: any = session;
|
||||||
|
const visualizations = await getUserVisualizations(email ?? "none", 20);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LeafcutterWrapper>
|
||||||
|
<Home visualizations={visualizations} showWelcome={false} />
|
||||||
|
</LeafcutterWrapper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FC, PropsWithChildren, useState } from "react";
|
import { FC, PropsWithChildren, useState } from "react";
|
||||||
import { usePathname } from "next/navigation";
|
|
||||||
import { CssBaseline } from "@mui/material";
|
import { CssBaseline } from "@mui/material";
|
||||||
import { CookiesProvider } from "react-cookie";
|
import { CookiesProvider } from "react-cookie";
|
||||||
import { SessionProvider } from "next-auth/react";
|
import { SessionProvider } from "next-auth/react";
|
||||||
|
|
@ -12,7 +11,7 @@ import { I18n } from "react-polyglot";
|
||||||
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFnsV3";
|
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFnsV3";
|
||||||
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
|
||||||
import { LicenseInfo } from "@mui/x-date-pickers-pro";
|
import { LicenseInfo } from "@mui/x-date-pickers-pro";
|
||||||
import { locales } from "leafcutter-common";
|
import { locales, LeafcutterProvider } from "leafcutter-ui";
|
||||||
|
|
||||||
LicenseInfo.setLicenseKey(
|
LicenseInfo.setLicenseKey(
|
||||||
"7c9bf25d9e240f76e77cbf7d2ba58a23Tz02NjU4OCxFPTE3MTU4NjIzMzQ2ODgsUz1wcm8sTE09c3Vic2NyaXB0aW9uLEtWPTI=",
|
"7c9bf25d9e240f76e77cbf7d2ba58a23Tz02NjU4OCxFPTE3MTU4NjIzMzQ2ODgsUz1wcm8sTE09c3Vic2NyaXB0aW9uLEtWPTI=",
|
||||||
|
|
@ -113,7 +112,9 @@ export const MultiProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
<CookiesProvider>
|
<CookiesProvider>
|
||||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||||
<I18n locale={locale} messages={messages[locale]}>
|
<I18n locale={locale} messages={messages[locale]}>
|
||||||
{children}
|
<LeafcutterProvider>
|
||||||
|
{children}
|
||||||
|
</LeafcutterProvider>
|
||||||
</I18n>
|
</I18n>
|
||||||
</LocalizationProvider>
|
</LocalizationProvider>
|
||||||
</CookiesProvider>
|
</CookiesProvider>
|
||||||
|
|
|
||||||
140
apps/link/app/_lib/authentication.ts
Normal file
140
apps/link/app/_lib/authentication.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
import type {
|
||||||
|
GetServerSidePropsContext,
|
||||||
|
NextApiRequest,
|
||||||
|
NextApiResponse,
|
||||||
|
} from "next";
|
||||||
|
import {
|
||||||
|
NextAuthOptions,
|
||||||
|
getServerSession as internalGetServerSession,
|
||||||
|
} from "next-auth";
|
||||||
|
import Google from "next-auth/providers/google";
|
||||||
|
import Credentials from "next-auth/providers/credentials";
|
||||||
|
import Apple from "next-auth/providers/apple";
|
||||||
|
|
||||||
|
const headers = { Authorization: `Token ${process.env.ZAMMAD_API_TOKEN}` };
|
||||||
|
|
||||||
|
const fetchRoles = async () => {
|
||||||
|
const url = `${process.env.ZAMMAD_URL}/api/v1/roles`;
|
||||||
|
const res = await fetch(url, { headers });
|
||||||
|
const roles = await res.json();
|
||||||
|
console.log({ roles });
|
||||||
|
const formattedRoles = roles.reduce((acc: any, role: any) => {
|
||||||
|
acc[role.id] = role.name;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
return formattedRoles;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchUser = async (email: string) => {
|
||||||
|
console.log({ email });
|
||||||
|
const url = `${process.env.ZAMMAD_URL}/api/v1/users/search?query=login:${email}&limit=1`;
|
||||||
|
console.log({ url });
|
||||||
|
const res = await fetch(url, { headers });
|
||||||
|
console.log({ res });
|
||||||
|
const users = await res.json();
|
||||||
|
console.log({ users });
|
||||||
|
const user = users?.[0];
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUserRoles = async (email: string) => {
|
||||||
|
try {
|
||||||
|
const user = await fetchUser(email);
|
||||||
|
console.log({ user });
|
||||||
|
const allRoles = await fetchRoles();
|
||||||
|
console.log({ allRoles });
|
||||||
|
const roles = user.role_ids.map((roleID: number) => {
|
||||||
|
const role = allRoles[roleID];
|
||||||
|
return role ? role.toLowerCase().replace(" ", "_") : null;
|
||||||
|
});
|
||||||
|
return roles.filter((role: string) => role !== null);
|
||||||
|
} catch (e) {
|
||||||
|
console.log({ e });
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const login = async (email: string, password: string) => {
|
||||||
|
const url = `${process.env.ZAMMAD_URL}/api/v1/users/me`;
|
||||||
|
console.log({ url });
|
||||||
|
const authorization =
|
||||||
|
"Basic " + Buffer.from(email + ":" + password).toString("base64");
|
||||||
|
const res = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
authorization,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const user = await res.json();
|
||||||
|
console.log({ user });
|
||||||
|
|
||||||
|
if (user && !user.error && user.id) {
|
||||||
|
return user;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const authOptions: NextAuthOptions = {
|
||||||
|
pages: {
|
||||||
|
signIn: "/login",
|
||||||
|
error: "/login",
|
||||||
|
signOut: "/logout",
|
||||||
|
},
|
||||||
|
providers: [
|
||||||
|
Google({
|
||||||
|
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||||
|
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||||
|
}),
|
||||||
|
Apple({
|
||||||
|
clientId: process.env.APPLE_CLIENT_ID,
|
||||||
|
clientSecret: process.env.APPLE_CLIENT_SECRET,
|
||||||
|
}),
|
||||||
|
Credentials({
|
||||||
|
name: "Zammad",
|
||||||
|
credentials: {
|
||||||
|
email: { label: "Email", type: "text" },
|
||||||
|
password: { label: "Password", type: "password" },
|
||||||
|
},
|
||||||
|
async authorize(credentials, req) {
|
||||||
|
const user = await login(credentials.email, credentials.password);
|
||||||
|
if (user) {
|
||||||
|
return user;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
|
callbacks: {
|
||||||
|
signIn: async ({ user, account, profile }) => {
|
||||||
|
const roles = (await getUserRoles(user.email)) ?? [];
|
||||||
|
return (
|
||||||
|
roles.includes("admin") ||
|
||||||
|
roles.includes("agent") ||
|
||||||
|
process.env.SETUP_MODE === "true"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
session: async ({ session, user, token }) => {
|
||||||
|
// @ts-ignore
|
||||||
|
session.user.roles = token.roles ?? [];
|
||||||
|
// @ts-ignore
|
||||||
|
session.user.leafcutter = token.leafcutter; // remove
|
||||||
|
return session;
|
||||||
|
},
|
||||||
|
jwt: async ({ token, user, account, profile, trigger }) => {
|
||||||
|
if (user) {
|
||||||
|
token.roles = (await getUserRoles(user.email)) ?? [];
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSession = (
|
||||||
|
...args:
|
||||||
|
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]]
|
||||||
|
| [NextApiRequest, NextApiResponse]
|
||||||
|
| []
|
||||||
|
) => internalGetServerSession(...args, authOptions);
|
||||||
|
|
@ -1,128 +1,6 @@
|
||||||
import NextAuth from "next-auth";
|
import NextAuth from "next-auth";
|
||||||
import Google from "next-auth/providers/google";
|
import { authOptions } from "app/_lib/authentication";
|
||||||
import Credentials from "next-auth/providers/credentials";
|
|
||||||
import Apple from "next-auth/providers/apple";
|
|
||||||
|
|
||||||
const headers = { Authorization: `Token ${process.env.ZAMMAD_API_TOKEN}` };
|
const handler = NextAuth(authOptions);
|
||||||
|
|
||||||
const fetchRoles = async () => {
|
|
||||||
const url = `${process.env.ZAMMAD_URL}/api/v1/roles`;
|
|
||||||
const res = await fetch(url, { headers });
|
|
||||||
const roles = await res.json();
|
|
||||||
console.log({ roles });
|
|
||||||
const formattedRoles = roles.reduce((acc: any, role: any) => {
|
|
||||||
acc[role.id] = role.name;
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
return formattedRoles;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchUser = async (email: string) => {
|
|
||||||
console.log({ email });
|
|
||||||
const url = `${process.env.ZAMMAD_URL}/api/v1/users/search?query=login:${email}&limit=1`;
|
|
||||||
console.log({ url });
|
|
||||||
const res = await fetch(url, { headers });
|
|
||||||
console.log({ res });
|
|
||||||
const users = await res.json();
|
|
||||||
console.log({ users });
|
|
||||||
const user = users?.[0];
|
|
||||||
|
|
||||||
return user;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUserRoles = async (email: string) => {
|
|
||||||
try {
|
|
||||||
const user = await fetchUser(email);
|
|
||||||
console.log({ user });
|
|
||||||
const allRoles = await fetchRoles();
|
|
||||||
console.log({ allRoles });
|
|
||||||
const roles = user.role_ids.map((roleID: number) => {
|
|
||||||
const role = allRoles[roleID];
|
|
||||||
return role ? role.toLowerCase().replace(" ", "_") : null;
|
|
||||||
});
|
|
||||||
return roles.filter((role: string) => role !== null);
|
|
||||||
} catch (e) {
|
|
||||||
console.log({ e });
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const login = async (email: string, password: string) => {
|
|
||||||
const url = `${process.env.ZAMMAD_URL}/api/v1/users/me`;
|
|
||||||
console.log({ url });
|
|
||||||
const authorization =
|
|
||||||
"Basic " + Buffer.from(email + ":" + password).toString("base64");
|
|
||||||
const res = await fetch(url, {
|
|
||||||
headers: {
|
|
||||||
authorization,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const user = await res.json();
|
|
||||||
console.log({ user });
|
|
||||||
|
|
||||||
if (user && !user.error && user.id) {
|
|
||||||
return user;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handler = NextAuth({
|
|
||||||
pages: {
|
|
||||||
signIn: "/login",
|
|
||||||
error: "/login",
|
|
||||||
signOut: "/logout",
|
|
||||||
},
|
|
||||||
providers: [
|
|
||||||
Google({
|
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
||||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
||||||
}),
|
|
||||||
Apple({
|
|
||||||
clientId: process.env.APPLE_CLIENT_ID,
|
|
||||||
clientSecret: process.env.APPLE_CLIENT_SECRET,
|
|
||||||
}),
|
|
||||||
Credentials({
|
|
||||||
name: "Zammad",
|
|
||||||
credentials: {
|
|
||||||
email: { label: "Email", type: "text" },
|
|
||||||
password: { label: "Password", type: "password" },
|
|
||||||
},
|
|
||||||
async authorize(credentials, req) {
|
|
||||||
const user = await login(credentials.email, credentials.password);
|
|
||||||
if (user) {
|
|
||||||
return user;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
|
||||||
|
|
||||||
callbacks: {
|
|
||||||
signIn: async ({ user, account, profile }) => {
|
|
||||||
const roles = (await getUserRoles(user.email)) ?? [];
|
|
||||||
return (
|
|
||||||
roles.includes("admin") ||
|
|
||||||
roles.includes("agent") ||
|
|
||||||
process.env.SETUP_MODE === "true"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
session: async ({ session, user, token }) => {
|
|
||||||
// @ts-ignore
|
|
||||||
session.user.roles = token.roles ?? [];
|
|
||||||
// @ts-ignore
|
|
||||||
session.user.leafcutter = token.leafcutter; // remove
|
|
||||||
return session;
|
|
||||||
},
|
|
||||||
jwt: async ({ token, user, account, profile, trigger }) => {
|
|
||||||
if (user) {
|
|
||||||
token.roles = (await getUserRoles(user.email)) ?? [];
|
|
||||||
}
|
|
||||||
return token;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export { handler as GET, handler as POST };
|
export { handler as GET, handler as POST };
|
||||||
|
|
|
||||||
|
|
@ -1,94 +1,83 @@
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from "next/server";
|
||||||
import { withAuth, NextRequestWithAuth } from "next-auth/middleware";
|
import { withAuth, NextRequestWithAuth } from "next-auth/middleware";
|
||||||
|
|
||||||
const rewriteURL = (request: NextRequestWithAuth, originBaseURL: string, destinationBaseURL: string, headers: any = {}) => {
|
const rewriteURL = (
|
||||||
if (request.nextUrl.pathname.startsWith('/api/v1/reports/sets')) {
|
request: NextRequestWithAuth,
|
||||||
console.log(request.nextUrl.searchParams.get("sheet"));
|
originBaseURL: string,
|
||||||
NextResponse.next();
|
destinationBaseURL: string,
|
||||||
}
|
headers: any = {},
|
||||||
|
) => {
|
||||||
const destinationURL = request.url.replace(originBaseURL, destinationBaseURL);
|
const destinationURL = request.url.replace(originBaseURL, destinationBaseURL);
|
||||||
|
|
||||||
console.log(`Rewriting ${request.url} to ${destinationURL}`);
|
console.log(`Rewriting ${request.url} to ${destinationURL}`);
|
||||||
|
|
||||||
const requestHeaders = new Headers(request.headers);
|
const requestHeaders = new Headers(request.headers);
|
||||||
for (const [key, value] of Object.entries(headers)) {
|
for (const [key, value] of Object.entries(headers)) {
|
||||||
requestHeaders.set(key, value as string);
|
requestHeaders.set(key, value as string);
|
||||||
}
|
}
|
||||||
|
requestHeaders.delete("connection");
|
||||||
|
|
||||||
requestHeaders.delete('connection');
|
return NextResponse.rewrite(new URL(destinationURL), {
|
||||||
|
request: { headers: requestHeaders },
|
||||||
return NextResponse.rewrite(new URL(destinationURL), { request: { headers: requestHeaders } });
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkRewrites = async (request: NextRequestWithAuth) => {
|
const checkRewrites = async (request: NextRequestWithAuth) => {
|
||||||
const linkBaseURL = process.env.LINK_URL ?? "http://localhost:3000";
|
const linkBaseURL = process.env.LINK_URL ?? "http://localhost:3000";
|
||||||
const zammadURL = process.env.ZAMMAD_URL ?? "http://zammad-nginx:8080";
|
const zammadURL = process.env.ZAMMAD_URL ?? "http://zammad-nginx:8080";
|
||||||
const opensearchURL = process.env.OPENSEARCH_URL ?? "http://macmini:5601";
|
const opensearchDashboardsURL =
|
||||||
const metamigoURL = process.env.METAMIGO_URL ?? "http://metamigo-api:3000";
|
process.env.OPENSEARCH_DASHBOARDS_URL ?? "http://macmini:5601";
|
||||||
const labelStudioURL = process.env.LABEL_STUDIO_URL ?? "http://label-studio:8080";
|
const zammadPaths = ["/zammad", "/api/v1", "/auth/sso", "/assets", "/mobile"];
|
||||||
const { token } = request.nextauth;
|
const { token } = request.nextauth;
|
||||||
const headers = { 'X-Forwarded-User': token?.email?.toLowerCase() };
|
const email = token?.email?.toLowerCase() ?? "unknown";
|
||||||
console.log({ pathname: request.nextUrl.pathname });
|
let headers = { "x-forwarded-user": email };
|
||||||
|
|
||||||
if (request.nextUrl.pathname.startsWith('/opensearch')) {
|
if (request.nextUrl.pathname.startsWith("/dashboards")) {
|
||||||
const headers = {
|
const roles: string[] = (token?.roles as string[]) ?? [];
|
||||||
'x-proxy-user': "admin",
|
const leafcutterRole = roles.includes("admin")
|
||||||
'x-proxy-roles': "all_access",
|
? "leafcutter_admin"
|
||||||
// 'X-Forwarded-For': "link"
|
: "leafcutter_user";
|
||||||
};
|
headers["x-forwarded-roles"] = "admin"; // leafcutterRole;
|
||||||
return rewriteURL(request, `${linkBaseURL}/opensearch`, opensearchURL, headers);
|
// headers["secruitytenant"] = "global";
|
||||||
} else if (request.nextUrl.pathname.startsWith('/metamigo')) {
|
// headers["x-forwarded-for"] = 'link';
|
||||||
return rewriteURL(request, `${linkBaseURL}/metamigo`, metamigoURL);
|
|
||||||
} else if (request.nextUrl.pathname.startsWith('/label-studio')) {
|
return rewriteURL(
|
||||||
return rewriteURL(request, `${linkBaseURL}/label-studio`, labelStudioURL);
|
request,
|
||||||
} else if (request.nextUrl.pathname.startsWith('/zammad')) {
|
`${linkBaseURL}/dashboards`,
|
||||||
|
opensearchDashboardsURL,
|
||||||
|
headers,
|
||||||
|
);
|
||||||
|
} else if (request.nextUrl.pathname.startsWith("/zammad")) {
|
||||||
return rewriteURL(request, `${linkBaseURL}/zammad`, zammadURL, headers);
|
return rewriteURL(request, `${linkBaseURL}/zammad`, zammadURL, headers);
|
||||||
} else if (request.nextUrl.pathname.startsWith('/auth/sso') || request.nextUrl.pathname.startsWith('/assets')) {
|
} else if (zammadPaths.some((p) => request.nextUrl.pathname.startsWith(p))) {
|
||||||
return rewriteURL(request, linkBaseURL, zammadURL, headers);
|
|
||||||
} else if (request.nextUrl.pathname.startsWith('/proxy/api') || request.nextUrl.pathname.startsWith('/proxy/assets')) {
|
|
||||||
return rewriteURL(request, `${linkBaseURL}/proxy`, zammadURL);
|
|
||||||
} else if (request.nextUrl.pathname.startsWith('/api/v1') || request.nextUrl.pathname.startsWith('/auth/sso') || request.nextUrl.pathname.startsWith('/mobile')) {
|
|
||||||
return rewriteURL(request, linkBaseURL, zammadURL, headers);
|
return rewriteURL(request, linkBaseURL, zammadURL, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withAuth(
|
export default withAuth(checkRewrites, {
|
||||||
checkRewrites,
|
pages: {
|
||||||
{
|
signIn: `/login`,
|
||||||
pages: {
|
},
|
||||||
signIn: `/login`,
|
callbacks: {
|
||||||
|
authorized: ({ token, req }) => {
|
||||||
|
if (req.nextUrl.pathname === "/api/v1") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.SETUP_MODE === "true") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles: any = token?.roles ?? [];
|
||||||
|
if (roles.includes("admin") || roles.includes("agent")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
callbacks: {
|
},
|
||||||
authorized: ({ token, req }) => {
|
});
|
||||||
const {
|
|
||||||
url,
|
|
||||||
} = req;
|
|
||||||
|
|
||||||
const noAuthPaths = ["/login", "/api/v1"];
|
|
||||||
const parsedURL = new URL(url);
|
|
||||||
const path = parsedURL.pathname;
|
|
||||||
|
|
||||||
if (noAuthPaths.some((p: string) => path.startsWith(p))) {
|
|
||||||
console.log({ p: parsedURL.pathname, auth: "no" });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const roles: any = token?.roles ?? [];
|
|
||||||
if (roles.includes("admin") || roles.includes("agent") || process.env.SETUP_MODE === "true") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
matcher: [
|
matcher: ["/((?!ws|wss|_next/static|_next/image|favicon.ico).*)"],
|
||||||
'/((?!ws|wss|_next/static|_next/image|favicon.ico).*)',
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,33 +4,13 @@ const nextConfig = {
|
||||||
experimental: {
|
experimental: {
|
||||||
missingSuspenseWithCSRBailout: false,
|
missingSuspenseWithCSRBailout: false,
|
||||||
},
|
},
|
||||||
modularizeImports: {
|
transpilePackages: ["leafcutter-ui", "metamigo-ui", "opensearch-common", "ui"],
|
||||||
"@mui/material": {
|
|
||||||
transform: "@mui/material/{{member}}",
|
|
||||||
},
|
|
||||||
"@mui/icons-material": {
|
|
||||||
transform: "@mui/icons-material/{{member}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
transpilePackages: ["leafcutter-common"],
|
|
||||||
publicRuntimeConfig: {
|
publicRuntimeConfig: {
|
||||||
linkURL: process.env.LINK_URL ?? "http://localhost:3000",
|
linkURL: process.env.LINK_URL ?? "http://localhost:3000",
|
||||||
leafcutterURL:
|
|
||||||
process.env.LEAFCUTTER_URL ?? "https://lc.digiresilience.org",
|
|
||||||
metamigoURL: process.env.METAMIGO_URL ?? "http://localhost:8002",
|
metamigoURL: process.env.METAMIGO_URL ?? "http://localhost:8002",
|
||||||
labelStudioURL: process.env.LABEL_STUDIO_URL ?? "http://localhost:8006",
|
labelStudioURL: process.env.LABEL_STUDIO_URL ?? "http://localhost:8006",
|
||||||
muiLicenseKey: process.env.MUI_LICENSE_KEY ?? "",
|
muiLicenseKey: process.env.MUI_LICENSE_KEY ?? "",
|
||||||
},
|
},
|
||||||
async rewrites() {
|
|
||||||
return {
|
|
||||||
fallback: [
|
|
||||||
{
|
|
||||||
source: "/:path*",
|
|
||||||
destination: `/proxy/leafcutter/:path*`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
|
|
||||||
|
|
@ -16,26 +16,24 @@
|
||||||
"@emotion/server": "^11.11.0",
|
"@emotion/server": "^11.11.0",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/icons-material": "^5",
|
"@mui/icons-material": "^5",
|
||||||
"@mui/lab": "^5.0.0-alpha.168",
|
"@mui/lab": "^5.0.0-alpha.169",
|
||||||
"@mui/material": "^5",
|
"@mui/material": "^5",
|
||||||
"@mui/x-data-grid-pro": "^6.19.6",
|
"@mui/x-data-grid-pro": "^6.19.6",
|
||||||
"@mui/x-date-pickers-pro": "^6.19.7",
|
"@mui/x-date-pickers-pro": "^6.19.7",
|
||||||
"cryptr": "^6.3.0",
|
"date-fns": "^3.6.0",
|
||||||
"date-fns": "^3.5.0",
|
|
||||||
"graphql-request": "^6.1.0",
|
"graphql-request": "^6.1.0",
|
||||||
"leafcutter-common": "*",
|
"leafcutter-ui": "*",
|
||||||
"material-ui-popup-state": "^5.0.10",
|
"material-ui-popup-state": "^5.1.0",
|
||||||
"metamigo-common": "*",
|
"metamigo-ui": "*",
|
||||||
"mui-chips-input": "^2.1.4",
|
"mui-chips-input": "^2.1.4",
|
||||||
"next": "14.1.3",
|
"next": "14.1.4",
|
||||||
"next-auth": "^4.24.7",
|
"next-auth": "^4.24.7",
|
||||||
|
"opensearch-common": "*",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-cookie": "^7.1.0",
|
"react-cookie": "^7.1.0",
|
||||||
"react-digit-input": "^2.1.0",
|
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-iframe": "^1.8.5",
|
"react-iframe": "^1.8.5",
|
||||||
"react-polyglot": "^0.7.2",
|
"react-polyglot": "^0.7.2",
|
||||||
"react-timer-hook": "^3.0.7",
|
|
||||||
"sharp": "^0.33.2",
|
"sharp": "^0.33.2",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"tss-react": "^4.9.4",
|
"tss-react": "^4.9.4",
|
||||||
|
|
@ -43,14 +41,14 @@
|
||||||
"ui": "*"
|
"ui": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.0",
|
"@babel/core": "^7.24.1",
|
||||||
"@types/node": "^20.11.28",
|
"@types/node": "^20.11.30",
|
||||||
"@types/react": "18.2.66",
|
"@types/react": "18.2.67",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-next": "^14.1.3",
|
"eslint-config-next": "^14.1.4",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { KyselyAdapter } from "@auth/kysely-adapter"
|
||||||
import { db } from "./database";
|
import { db } from "./database";
|
||||||
|
|
||||||
export const authOptions = NextAuth({
|
export const authOptions = NextAuth({
|
||||||
|
// @ts-ignore
|
||||||
adapter: KyselyAdapter(db),
|
adapter: KyselyAdapter(db),
|
||||||
providers: [
|
providers: [
|
||||||
GoogleProvider({
|
GoogleProvider({
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import type { GeneratedAlways } from "kysely";
|
||||||
|
|
||||||
interface Database {
|
interface Database {
|
||||||
User: {
|
User: {
|
||||||
id: GeneratedAlways<string>;
|
id: string;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
email: string;
|
email: string;
|
||||||
emailVerified: Date | null;
|
emailVerified: Date | null;
|
||||||
|
|
@ -16,16 +16,16 @@ interface Database {
|
||||||
Account: {
|
Account: {
|
||||||
id: GeneratedAlways<string>;
|
id: GeneratedAlways<string>;
|
||||||
userId: string;
|
userId: string;
|
||||||
type: string;
|
type: "oidc" | "oauth" | "email" | "webauthn";
|
||||||
provider: string;
|
provider: string;
|
||||||
providerAccountId: string;
|
providerAccountId: string;
|
||||||
refresh_token: string | null;
|
refresh_token: string | undefined;
|
||||||
access_token: string | null;
|
access_token: string | undefined;
|
||||||
expires_at: number | null;
|
expires_at: number | undefined;
|
||||||
token_type: string | null;
|
token_type: Lowercase<string> | undefined;
|
||||||
scope: string | null;
|
scope: string | undefined;
|
||||||
id_token: string | null;
|
id_token: string | undefined;
|
||||||
session_state: string | null;
|
session_state: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
Session: {
|
Session: {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return <h1>Home</h1>;
|
return <h1>Home</h1>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/icons-material": "^5",
|
"@mui/icons-material": "^5",
|
||||||
"@mui/lab": "^5.0.0-alpha.168",
|
"@mui/lab": "^5.0.0-alpha.169",
|
||||||
"@mui/material": "^5",
|
"@mui/material": "^5",
|
||||||
"@mui/material-nextjs": "^5.15.11",
|
"@mui/material-nextjs": "^5.15.11",
|
||||||
"@mui/x-data-grid-pro": "^6.19.6",
|
"@mui/x-data-grid-pro": "^6.19.6",
|
||||||
"@mui/x-date-pickers-pro": "^6.19.7",
|
"@mui/x-date-pickers-pro": "^6.19.7",
|
||||||
"date-fns": "^3.5.0",
|
"date-fns": "^3.6.0",
|
||||||
"kysely": "^0.26.1",
|
"kysely": "^0.26.1",
|
||||||
"material-ui-popup-state": "^5.0.10",
|
"material-ui-popup-state": "^5.1.0",
|
||||||
"mui-chips-input": "^2.1.4",
|
"mui-chips-input": "^2.1.4",
|
||||||
"next": "14.1.3",
|
"next": "14.1.4",
|
||||||
"next-auth": "^4.24.7",
|
"next-auth": "^4.24.7",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
|
@ -37,11 +37,11 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/pg": "^8.11.2",
|
"@types/pg": "^8.11.3",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.1.3",
|
"eslint-config-next": "14.1.4",
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
"ts-config": "*"
|
"ts-config": "*"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
"node-fetch": "^3",
|
"node-fetch": "^3",
|
||||||
"pg-promise": "^11.5.4",
|
"pg-promise": "^11.5.4",
|
||||||
"remeda": "^1.50.1",
|
"remeda": "^1.55.0",
|
||||||
"twilio": "^5.0.1"
|
"twilio": "^5.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ts-config": "*",
|
"ts-config": "*",
|
||||||
"@babel/core": "7.24.0",
|
"@babel/core": "7.24.1",
|
||||||
"@babel/preset-env": "7.24.0",
|
"@babel/preset-env": "7.24.1",
|
||||||
"@babel/preset-typescript": "7.23.3",
|
"@babel/preset-typescript": "7.24.1",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@types/fluent-ffmpeg": "^2.1.24",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,18 @@ opensearch.requestHeadersAllowlist:
|
||||||
"securitytenant",
|
"securitytenant",
|
||||||
"Authorization",
|
"Authorization",
|
||||||
"x-forwarded-for",
|
"x-forwarded-for",
|
||||||
"x-proxy-user",
|
"x-forwarded-user",
|
||||||
"x-proxy-roles",
|
"x-forwarded-roles",
|
||||||
]
|
]
|
||||||
# opensearch_security.auth.type: "proxy"
|
opensearch_security.auth.type: "proxy"
|
||||||
# opensearch_security.proxycache.user_header: "x-proxy-user"
|
opensearch_security.proxycache.user_header: "x-forwarded-user"
|
||||||
# opensearch_security.proxycache.roles_header: "x-proxy-roles"
|
opensearch_security.proxycache.roles_header: "x-forwarded-roles"
|
||||||
|
|
||||||
opensearch_security.multitenancy.enabled: true
|
opensearch_security.multitenancy.enabled: true
|
||||||
|
opensearch_security.multitenancy.tenants.enable_global: true
|
||||||
|
opensearch_security.multitenancy.tenants.enable_private: true
|
||||||
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
|
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
|
||||||
opensearch_security.readonly_mode.roles: [kibana_read_only]
|
# opensearch_security.readonly_mode.roles: [kibana_read_only]
|
||||||
opensearch_security.cookie.secure: false
|
opensearch_security.cookie.secure: false
|
||||||
server.host: "0.0.0.0"
|
server.host: "0.0.0.0"
|
||||||
server.basePath: "/opensearch"
|
server.basePath: "/dashboards"
|
||||||
server.rewriteBasePath: false
|
server.rewriteBasePath: false
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ config:
|
||||||
type: proxy
|
type: proxy
|
||||||
challenge: false
|
challenge: false
|
||||||
config:
|
config:
|
||||||
user_header: "x-proxy-user"
|
user_header: "x-forwarded-user"
|
||||||
roles_header: "x-proxy-roles"
|
roles_header: "x-forwarded-roles"
|
||||||
authentication_backend:
|
authentication_backend:
|
||||||
type: noop
|
type: noop
|
||||||
|
|
|
||||||
1455
package-lock.json
generated
1455
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -9,9 +9,9 @@
|
||||||
"fmt": "prettier \"profile/**/*.js\" --write"
|
"fmt": "prettier \"profile/**/*.js\" --write"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.7.2",
|
"@rushstack/eslint-patch": "^1.8.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||||
"@typescript-eslint/parser": "^7.2.0",
|
"@typescript-eslint/parser": "^7.3.1",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-config-xo-space": "^0.35.0",
|
"eslint-config-xo-space": "^0.35.0",
|
||||||
"eslint-plugin-cypress": "^2.15.1",
|
"eslint-plugin-cypress": "^2.15.1",
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
"eslint-plugin-no-use-extend-native": "^0.5.0",
|
"eslint-plugin-no-use-extend-native": "^0.5.0",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-unicorn": "51.0.1",
|
"eslint-plugin-unicorn": "51.0.1",
|
||||||
"@babel/eslint-parser": "7.23.10"
|
"@babel/eslint-parser": "7.24.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { FC, useEffect, useState } from "react";
|
|
||||||
import { useAppContext } from "./AppProvider";
|
|
||||||
import { RawDataViewer } from "./RawDataViewer";
|
|
||||||
|
|
||||||
export const LiveDataViewer: FC = () => {
|
|
||||||
const { query, setFoundCount } = useAppContext();
|
|
||||||
const [rows, setRows] = useState<any[]>([]);
|
|
||||||
const searchQuery = encodeURI(JSON.stringify(query));
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchData = async () => {
|
|
||||||
const result = await fetch(
|
|
||||||
`/api/visualizations/query?searchQuery=${searchQuery}`,
|
|
||||||
);
|
|
||||||
const json = await result.json();
|
|
||||||
setRows(json);
|
|
||||||
setFoundCount(json?.length ?? 0);
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}, [searchQuery, setFoundCount]);
|
|
||||||
|
|
||||||
return <RawDataViewer rows={rows} height={350} />;
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import type { NextAuthOptions } from "next-auth";
|
|
||||||
import Google from "next-auth/providers/google";
|
|
||||||
import Apple from "next-auth/providers/apple";
|
|
||||||
|
|
||||||
export const authOptions: NextAuthOptions = {
|
|
||||||
providers: [
|
|
||||||
Google({
|
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID ?? "",
|
|
||||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET ?? "",
|
|
||||||
}),
|
|
||||||
Apple({
|
|
||||||
clientId: process.env.APPLE_CLIENT_ID ?? "",
|
|
||||||
clientSecret: process.env.APPLE_CLIENT_SECRET ?? "",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
|
||||||
};
|
|
||||||
File diff suppressed because one or more lines are too long
23
packages/leafcutter-ui/actions/visualizations.ts
Normal file
23
packages/leafcutter-ui/actions/visualizations.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import { performLeafcutterQuery, performZammadQuery, createUserVisualization } from "opensearch-common";
|
||||||
|
|
||||||
|
export const createUserVisualizationAction = async ({visualizationID, title, description, query}: any) => {
|
||||||
|
const email = "darren@redaranj.com";
|
||||||
|
const id = await createUserVisualization({
|
||||||
|
email,
|
||||||
|
visualizationID,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
query
|
||||||
|
});
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const searchVisualizationsAction = async (
|
||||||
|
kind: string,
|
||||||
|
searchQuery: string,
|
||||||
|
) =>
|
||||||
|
kind === "zammad"
|
||||||
|
? performZammadQuery(searchQuery, 1000)
|
||||||
|
: performLeafcutterQuery(searchQuery, 1000);
|
||||||
|
|
@ -5,7 +5,7 @@ import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { Grid, Container, Box, Button } from "@mui/material";
|
import { Grid, Container, Box, Button } from "@mui/material";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
import { AboutBox } from "./AboutBox";
|
import { AboutBox } from "./AboutBox";
|
||||||
import { AboutFeature } from "./AboutFeature";
|
import { AboutFeature } from "./AboutFeature";
|
||||||
import { PageHeader } from "./PageHeader";
|
import { PageHeader } from "./PageHeader";
|
||||||
|
|
@ -21,7 +21,7 @@ export const About: FC = () => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue, cdrLinkOrange },
|
colors: { white, leafcutterElectricBlue, cdrLinkOrange },
|
||||||
typography: { h1, h4, p },
|
typography: { h1, h4, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
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 { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
type AboutBoxProps = PropsWithChildren<{
|
type AboutBoxProps = PropsWithChildren<{
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
|
|
@ -14,7 +14,7 @@ export const AboutBox: FC<AboutBoxProps> = ({
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const {
|
const {
|
||||||
colors: { white },
|
colors: { white },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
|
@ -4,7 +4,7 @@ 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";
|
||||||
import AboutDots from "../images/about-dots.png";
|
import AboutDots from "../images/about-dots.png";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface AboutFeatureProps {
|
interface AboutFeatureProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -25,7 +25,7 @@ export const AboutFeature: FC<AboutFeatureProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
typography: { h2, p },
|
typography: { h2, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
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";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
@ -14,7 +14,7 @@ interface ButtonProps {
|
||||||
export const Button: FC<ButtonProps> = ({ text, color, href }) => {
|
export const Button: FC<ButtonProps> = ({ text, color, href }) => {
|
||||||
const {
|
const {
|
||||||
colors: { white, almostBlack },
|
colors: { white, almostBlack },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={href} passHref>
|
<Link href={href} passHref>
|
||||||
|
|
@ -5,7 +5,7 @@ import { useTranslate } from "react-polyglot";
|
||||||
import { useRouter, usePathname } from "next/navigation";
|
import { useRouter, usePathname } from "next/navigation";
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { useCookies } from "react-cookie";
|
import { useCookies } from "react-cookie";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
import { PageHeader } from "./PageHeader";
|
import { PageHeader } from "./PageHeader";
|
||||||
import { VisualizationBuilder } from "./VisualizationBuilder";
|
import { VisualizationBuilder } from "./VisualizationBuilder";
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ export const Create: FC<CreateProps> = ({ templates }) => {
|
||||||
const {
|
const {
|
||||||
colors: { cdrLinkOrange },
|
colors: { cdrLinkOrange },
|
||||||
typography: { h1, h4 },
|
typography: { h1, h4 },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname() ?? "";
|
const pathname = usePathname() ?? "";
|
||||||
const cookieName = "searchIntroComplete";
|
const cookieName = "searchIntroComplete";
|
||||||
|
|
@ -5,7 +5,7 @@ import { useTranslate } from "react-polyglot";
|
||||||
import { Box, Grid } from "@mui/material";
|
import { Box, Grid } from "@mui/material";
|
||||||
import { PageHeader } from "./PageHeader";
|
import { PageHeader } from "./PageHeader";
|
||||||
import { Question } from "./Question";
|
import { Question } from "./Question";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
import FaqHeader from "../images/faq-header.svg";
|
import FaqHeader from "../images/faq-header.svg";
|
||||||
|
|
||||||
export const FAQ: FC = () => {
|
export const FAQ: FC = () => {
|
||||||
|
|
@ -13,7 +13,7 @@ export const FAQ: FC = () => {
|
||||||
const {
|
const {
|
||||||
colors: { lavender },
|
colors: { lavender },
|
||||||
typography: { h1, h4, p },
|
typography: { h1, h4, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
const questions = [
|
const questions = [
|
||||||
{
|
{
|
||||||
|
|
@ -9,14 +9,14 @@ import leafcutterLogo from "../images/leafcutter-logo.png";
|
||||||
import footerLogo from "../images/footer-logo.png";
|
import footerLogo from "../images/footer-logo.png";
|
||||||
import twitterLogo from "../images/twitter-logo.png";
|
import twitterLogo from "../images/twitter-logo.png";
|
||||||
import gitlabLogo from "../images/gitlab-logo.png";
|
import gitlabLogo from "../images/gitlab-logo.png";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
export const Footer: FC = () => {
|
export const Footer: FC = () => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue },
|
colors: { white, leafcutterElectricBlue },
|
||||||
typography: { bodySmall },
|
typography: { bodySmall },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const smallLinkStyles: any = {
|
const smallLinkStyles: any = {
|
||||||
...bodySmall,
|
...bodySmall,
|
||||||
color: white,
|
color: white,
|
||||||
|
|
@ -5,7 +5,7 @@ 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";
|
||||||
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
type CheckboxItemProps = {
|
type CheckboxItemProps = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -22,7 +22,7 @@ const CheckboxItem: FC<CheckboxItemProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
typography: { p, small },
|
typography: { p, small },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid item container spacing={0}>
|
<Grid item container spacing={0}>
|
||||||
|
|
@ -60,7 +60,7 @@ export const GettingStartedDialog: FC = () => {
|
||||||
const {
|
const {
|
||||||
colors: { almostBlack },
|
colors: { almostBlack },
|
||||||
typography: { h4 },
|
typography: { h4 },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [completedItems, setCompletedItems] = useState([] as any[]);
|
const [completedItems, setCompletedItems] = useState([] as any[]);
|
||||||
|
|
@ -10,13 +10,14 @@ import { useCookies } from "react-cookie";
|
||||||
import { Welcome } from "./Welcome";
|
import { Welcome } from "./Welcome";
|
||||||
import { WelcomeDialog } from "./WelcomeDialog";
|
import { WelcomeDialog } from "./WelcomeDialog";
|
||||||
import { VisualizationCard } from "./VisualizationCard";
|
import { VisualizationCard } from "./VisualizationCard";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
type HomeProps = {
|
type HomeProps = {
|
||||||
visualizations: any;
|
visualizations: any;
|
||||||
|
showWelcome?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Home: FC<HomeProps> = ({ visualizations = [] }) => {
|
export const Home: FC<HomeProps> = ({ visualizations = [], showWelcome = true }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname() ?? "";
|
const pathname = usePathname() ?? "";
|
||||||
const cookieName = "homeIntroComplete";
|
const cookieName = "homeIntroComplete";
|
||||||
|
|
@ -25,7 +26,7 @@ export const Home: FC<HomeProps> = ({ visualizations = [] }) => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue },
|
colors: { white, leafcutterElectricBlue },
|
||||||
typography: { h4 },
|
typography: { h4 },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const homeIntroComplete = parseInt(cookies[cookieName], 10) || 0;
|
const homeIntroComplete = parseInt(cookies[cookieName], 10) || 0;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -37,14 +38,14 @@ export const Home: FC<HomeProps> = ({ visualizations = [] }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Welcome />
|
{showWelcome && <Welcome />}
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
spacing={3}
|
spacing={3}
|
||||||
sx={{ pt: "22px", pb: "22px" }}
|
sx={{ pt: "22px", pb: "22px" }}
|
||||||
direction="row-reverse"
|
direction="row-reverse"
|
||||||
>
|
>
|
||||||
<Link href="/create" passHref>
|
<Link href={`${process.env.LEAFCUTTER_BASE_PATH ?? ""}/create`} passHref>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
useState,
|
useState,
|
||||||
PropsWithChildren,
|
PropsWithChildren,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { colors, typography } from "leafcutter-common/styles/theme";
|
import { colors, typography } from "../styles/theme";
|
||||||
|
|
||||||
const basePath = process.env.GITLAB_CI
|
const basePath = process.env.GITLAB_CI
|
||||||
? "/link/link-stack/apps/leafcutter"
|
? "/link/link-stack/apps/leafcutter"
|
||||||
|
|
@ -16,10 +16,12 @@ const basePath = process.env.GITLAB_CI
|
||||||
const imageURL = (image: any) =>
|
const imageURL = (image: any) =>
|
||||||
typeof image === "string" ? `${basePath}${image}` : `${basePath}${image.src}`;
|
typeof image === "string" ? `${basePath}${image}` : `${basePath}${image.src}`;
|
||||||
|
|
||||||
const AppContext = createContext({
|
const LeafcutterContext = createContext({
|
||||||
colors,
|
colors,
|
||||||
typography,
|
typography,
|
||||||
imageURL,
|
imageURL,
|
||||||
|
datasource: "leafcutter",
|
||||||
|
setDatasource: null as any,
|
||||||
query: null as any,
|
query: null as any,
|
||||||
updateQuery: null as any,
|
updateQuery: null as any,
|
||||||
updateQueryType: null as any,
|
updateQueryType: null as any,
|
||||||
|
|
@ -29,7 +31,7 @@ const AppContext = createContext({
|
||||||
setFoundCount: null as any,
|
setFoundCount: null as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AppProvider: FC<PropsWithChildren> = ({ children }) => {
|
export const LeafcutterProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
const initialState = {
|
const initialState = {
|
||||||
incidentType: {
|
incidentType: {
|
||||||
display: "Incident Type",
|
display: "Incident Type",
|
||||||
|
|
@ -134,14 +136,17 @@ export const AppProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
const replaceQuery = (payload: any) => dispatch({ type: "REPLACE", payload });
|
const replaceQuery = (payload: any) => dispatch({ type: "REPLACE", payload });
|
||||||
const clearQuery = () => dispatch({ type: "CLEAR" });
|
const clearQuery = () => dispatch({ type: "CLEAR" });
|
||||||
const [foundCount, setFoundCount] = useState(0);
|
const [foundCount, setFoundCount] = useState(0);
|
||||||
|
const [datasource, setDatasource] = useState("leafcutter");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider
|
<LeafcutterContext.Provider
|
||||||
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
||||||
value={{
|
value={{
|
||||||
colors,
|
colors,
|
||||||
typography,
|
typography,
|
||||||
imageURL,
|
imageURL,
|
||||||
|
datasource,
|
||||||
|
setDatasource,
|
||||||
query,
|
query,
|
||||||
updateQuery,
|
updateQuery,
|
||||||
updateQueryType,
|
updateQueryType,
|
||||||
|
|
@ -152,10 +157,10 @@ export const AppProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</AppContext.Provider>
|
</LeafcutterContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useAppContext() {
|
export function useLeafcutterContext() {
|
||||||
return useContext(AppContext);
|
return useContext(LeafcutterContext);
|
||||||
}
|
}
|
||||||
21
packages/leafcutter-ui/components/LiveDataViewer.tsx
Normal file
21
packages/leafcutter-ui/components/LiveDataViewer.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC, useEffect, useState } from "react";
|
||||||
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
import { RawDataViewer } from "./RawDataViewer";
|
||||||
|
import { searchVisualizationsAction } from "../actions/visualizations";
|
||||||
|
|
||||||
|
export const LiveDataViewer: FC = () => {
|
||||||
|
const { query, setFoundCount, datasource } = useLeafcutterContext();
|
||||||
|
const [rows, setRows] = useState<any[]>([]);
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const result = await searchVisualizationsAction(datasource, query);
|
||||||
|
setRows(result);
|
||||||
|
setFoundCount(result?.length ?? 0);
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, [query, setFoundCount, datasource]);
|
||||||
|
|
||||||
|
return <RawDataViewer rows={rows} height={350} />;
|
||||||
|
};
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
Public as PublicIcon,
|
Public as PublicIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { VisualizationDetailDialog } from "./VisualizationDetailDialog";
|
import { VisualizationDetailDialog } from "./VisualizationDetailDialog";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface MetricSelectCardProps {
|
interface MetricSelectCardProps {
|
||||||
visualizationID: string;
|
visualizationID: string;
|
||||||
|
|
@ -35,7 +35,7 @@ export const MetricSelectCard: FC<MetricSelectCardProps> = ({
|
||||||
typography: { small },
|
typography: { small },
|
||||||
colors: { white, leafcutterElectricBlue, cdrLinkOrange },
|
colors: { white, leafcutterElectricBlue, cdrLinkOrange },
|
||||||
query,
|
query,
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
/* const images = {
|
/* const images = {
|
||||||
actor: PrivacyTipIcon,
|
actor: PrivacyTipIcon,
|
||||||
incidenttype: PrivacyTipIcon,
|
incidenttype: PrivacyTipIcon,
|
||||||
|
|
@ -34,7 +34,7 @@ export const OpenSearchWrapper: FC<OpenSearchWrapperProps> = ({
|
||||||
>
|
>
|
||||||
<Iframe
|
<Iframe
|
||||||
id="opensearch"
|
id="opensearch"
|
||||||
url={`/opensearch/${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`}
|
url={`/dashboards/${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
frameBorder={0}
|
frameBorder={0}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
/* 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";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
type PageHeaderProps = PropsWithChildren<{
|
type PageHeaderProps = PropsWithChildren<{
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
|
|
@ -17,7 +17,7 @@ export const PageHeader: FC<PageHeaderProps> = ({
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const {
|
const {
|
||||||
colors: { white },
|
colors: { white },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
|
@ -21,7 +21,7 @@ import taxonomy from "../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 { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
import { Tooltip } from "./Tooltip";
|
import { Tooltip } from "./Tooltip";
|
||||||
|
|
||||||
interface QueryBuilderProps {}
|
interface QueryBuilderProps {}
|
||||||
|
|
@ -32,7 +32,7 @@ export const QueryBuilder: FC<QueryBuilderProps> = () => {
|
||||||
const {
|
const {
|
||||||
typography: { p },
|
typography: { p },
|
||||||
colors: { leafcutterElectricBlue, mediumGray, almostBlack },
|
colors: { leafcutterElectricBlue, mediumGray, almostBlack },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
const openAdvancedOptions = () => {
|
const openAdvancedOptions = () => {
|
||||||
setDialogOpen(false);
|
setDialogOpen(false);
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
ExpandMore as ExpandMoreIcon,
|
ExpandMore as ExpandMoreIcon,
|
||||||
Help as HelpIcon,
|
Help as HelpIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface QueryBuilderSectionProps {
|
interface QueryBuilderSectionProps {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -42,7 +42,7 @@ const Tooltip: FC<TooltipProps> = ({ title, description, children, open }) => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue, almostBlack },
|
colors: { white, leafcutterElectricBlue, almostBlack },
|
||||||
typography: { h5, small },
|
typography: { h5, small },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MUITooltip
|
<MUITooltip
|
||||||
|
|
@ -108,7 +108,7 @@ export const QueryBuilderSection: FC<QueryBuilderSectionProps> = ({
|
||||||
colors: { white, leafcutterElectricBlue, warningPink, almostBlack },
|
colors: { white, leafcutterElectricBlue, warningPink, almostBlack },
|
||||||
typography: { h6, small },
|
typography: { h6, small },
|
||||||
updateQueryType,
|
updateQueryType,
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const updateType = (type: string) => {
|
const updateType = (type: string) => {
|
||||||
setQueryType(type);
|
setQueryType(type);
|
||||||
updateQueryType({
|
updateQueryType({
|
||||||
|
|
@ -4,7 +4,7 @@ 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";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface QueryDateRangeSelectorProps {}
|
interface QueryDateRangeSelectorProps {}
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const QueryDateRangeSelector: FC<QueryDateRangeSelectorProps> = () => {
|
||||||
const [relativeDate, setRelativeDate] = useState("");
|
const [relativeDate, setRelativeDate] = useState("");
|
||||||
const [startDate, setStartDate] = useState(null);
|
const [startDate, setStartDate] = useState(null);
|
||||||
const [endDate, setEndDate] = useState(null);
|
const [endDate, setEndDate] = useState(null);
|
||||||
const { updateQuery, query } = useAppContext();
|
const { updateQuery, query } = useLeafcutterContext();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!query) return;
|
if (!query) return;
|
||||||
setStartDate(query.startDate.values[0] ?? null);
|
setStartDate(query.startDate.values[0] ?? null);
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
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";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface QueryListSelectorProps {
|
interface QueryListSelectorProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -24,7 +24,7 @@ export const QueryListSelector: FC<QueryListSelectorProps> = ({
|
||||||
typography: { small },
|
typography: { small },
|
||||||
query,
|
query,
|
||||||
updateQuery,
|
updateQuery,
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const isExclude = query?.[keyName]?.queryType === "exclude";
|
const isExclude = query?.[keyName]?.queryType === "exclude";
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -5,14 +5,14 @@ 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 "../config/taxonomy.json";
|
||||||
import { colors } from "../styles/theme";
|
import { colors } from "../styles/theme";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
export const QueryText: FC = () => {
|
export const QueryText: FC = () => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
const {
|
const {
|
||||||
typography: { h6 },
|
typography: { h6 },
|
||||||
query: q,
|
query: q,
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
const displayNames: any = {
|
const displayNames: any = {
|
||||||
incidentType: t("incidentType"),
|
incidentType: t("incidentType"),
|
||||||
|
|
@ -14,7 +14,7 @@ import {
|
||||||
ExpandMore as ExpandMoreIcon,
|
ExpandMore as ExpandMoreIcon,
|
||||||
Circle as CircleIcon,
|
Circle as CircleIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface QuestionProps {
|
interface QuestionProps {
|
||||||
question: string;
|
question: string;
|
||||||
|
|
@ -26,7 +26,7 @@ export const Question: FC<QuestionProps> = ({ question, answer }) => {
|
||||||
const {
|
const {
|
||||||
colors: { lavender, darkLavender },
|
colors: { lavender, darkLavender },
|
||||||
typography: { h5, p },
|
typography: { h5, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
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";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
|
|
@ -12,14 +13,23 @@ interface RawDataViewerProps {
|
||||||
|
|
||||||
export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
|
export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
|
const router = useRouter();
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
field: "date",
|
field: "open_date",
|
||||||
headerName: t("date"),
|
headerName: "Open Date", //t("date"),
|
||||||
editable: false,
|
editable: false,
|
||||||
flex: 0.7,
|
flex: 0.7,
|
||||||
valueFormatter: ({ value }: any) => new Date(value).toLocaleDateString(),
|
valueFormatter: ({ value }: any) => new Date(value).toLocaleDateString(),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: "close_date",
|
||||||
|
headerName: "Close Date", // t("date"),
|
||||||
|
editable: false,
|
||||||
|
flex: 0.7,
|
||||||
|
valueFormatter: ({ value }: any) => new Date(value).toLocaleDateString(),
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
field: "incident",
|
field: "incident",
|
||||||
headerName: t("incident"),
|
headerName: t("incident"),
|
||||||
|
|
@ -77,6 +87,7 @@ export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
|
||||||
disableColumnMenu
|
disableColumnMenu
|
||||||
scrollbarSize={10}
|
scrollbarSize={10}
|
||||||
disableVirtualization
|
disableVirtualization
|
||||||
|
onCellClick={(e) => router.push("/tickets/" + e.row.id)}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { Close as CloseIcon } from "@mui/icons-material";
|
import { Close as CloseIcon } from "@mui/icons-material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface TooltipProps {
|
interface TooltipProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -38,7 +38,7 @@ export const Tooltip: FC<TooltipProps> = ({
|
||||||
const {
|
const {
|
||||||
typography: { p, small },
|
typography: { p, small },
|
||||||
colors: { white, leafcutterElectricBlue, almostBlack },
|
colors: { white, leafcutterElectricBlue, almostBlack },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname() ?? "";
|
const pathname = usePathname() ?? "";
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
@ -5,7 +5,7 @@ import { Grid, Box } from "@mui/material";
|
||||||
import { useTranslate } from "react-polyglot";
|
import { useTranslate } from "react-polyglot";
|
||||||
import { PageHeader } from "./PageHeader";
|
import { PageHeader } from "./PageHeader";
|
||||||
import { VisualizationCard } from "./VisualizationCard";
|
import { VisualizationCard } from "./VisualizationCard";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
type TrendsProps = {
|
type TrendsProps = {
|
||||||
visualizations: any;
|
visualizations: any;
|
||||||
|
|
@ -16,7 +16,7 @@ export const Trends: FC<TrendsProps> = ({ visualizations }) => {
|
||||||
const {
|
const {
|
||||||
colors: { cdrLinkOrange },
|
colors: { cdrLinkOrange },
|
||||||
typography: { h1, h4, p },
|
typography: { h1, h4, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -32,7 +32,7 @@ import { Tooltip } from "./Tooltip";
|
||||||
import visualizationMap from "../config/visualizationMap.json";
|
import visualizationMap from "../config/visualizationMap.json";
|
||||||
import { VisualizationSelectCard } from "./VisualizationSelectCard";
|
import { VisualizationSelectCard } from "./VisualizationSelectCard";
|
||||||
import { MetricSelectCard } from "./MetricSelectCard";
|
import { MetricSelectCard } from "./MetricSelectCard";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface VisualizationBuilderProps {
|
interface VisualizationBuilderProps {
|
||||||
templates: any[];
|
templates: any[];
|
||||||
|
|
@ -49,7 +49,9 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
|
||||||
query,
|
query,
|
||||||
replaceQuery,
|
replaceQuery,
|
||||||
clearQuery,
|
clearQuery,
|
||||||
} = useAppContext();
|
datasource,
|
||||||
|
setDatasource,
|
||||||
|
} = useLeafcutterContext();
|
||||||
const { visualizations } = visualizationMap;
|
const { visualizations } = visualizationMap;
|
||||||
const [selectedVisualizationType, setSelectedVisualizationType] = useState(
|
const [selectedVisualizationType, setSelectedVisualizationType] = useState(
|
||||||
null as any,
|
null as any,
|
||||||
|
|
@ -194,6 +196,24 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={() =>
|
||||||
|
setDatasource(
|
||||||
|
datasource === "leafcutter" ? "zammad" : "leafcutter",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: cdrLinkOrange,
|
||||||
|
textTransform: "none",
|
||||||
|
fontStyle: "italic",
|
||||||
|
fontWeight: "bold",
|
||||||
|
mr: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{datasource === "zammad" ? "Switch to Global" : "Switch to Local"}
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
aria-describedby={elementID}
|
aria-describedby={elementID}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
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 "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
import { VisualizationDetailDialog } from "./VisualizationDetailDialog";
|
import { VisualizationDetailDialog } from "./VisualizationDetailDialog";
|
||||||
|
|
||||||
interface VisualizationCardProps {
|
interface VisualizationCardProps {
|
||||||
|
|
@ -24,7 +24,7 @@ export const VisualizationCard: FC<VisualizationCardProps> = ({
|
||||||
const {
|
const {
|
||||||
typography: { h4, p },
|
typography: { h4, p },
|
||||||
colors: { leafcutterLightBlue, leafcutterElectricBlue },
|
colors: { leafcutterLightBlue, leafcutterElectricBlue },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const finalURL = `${process.env.NEXT_PUBLIC_LEAFCUTTER_URL}${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`;
|
const finalURL = `${process.env.NEXT_PUBLIC_LEAFCUTTER_URL}${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import Iframe from "react-iframe";
|
import Iframe from "react-iframe";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface VisualizationDetailProps {
|
interface VisualizationDetailProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -23,7 +23,7 @@ export const VisualizationDetail: FC<VisualizationDetailProps> = ({
|
||||||
const {
|
const {
|
||||||
colors: { mediumGray },
|
colors: { mediumGray },
|
||||||
typography: { h4, p },
|
typography: { h4, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const finalURL = `${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`;
|
const finalURL = `${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`;
|
||||||
console.log({ finalURL });
|
console.log({ finalURL });
|
||||||
return (
|
return (
|
||||||
|
|
@ -11,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 "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
import { VisualizationDetail } from "./VisualizationDetail";
|
import { VisualizationDetail } from "./VisualizationDetail";
|
||||||
|
|
||||||
interface VisualizationDetailDialogProps {
|
interface VisualizationDetailDialogProps {
|
||||||
|
|
@ -37,7 +37,7 @@ export const VisualizationDetailDialog: FC<VisualizationDetailDialogProps> = ({
|
||||||
const {
|
const {
|
||||||
colors: { leafcutterElectricBlue, leafcutterLightBlue, white, almostBlack },
|
colors: { leafcutterElectricBlue, leafcutterLightBlue, white, almostBlack },
|
||||||
query,
|
query,
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
const deleteAndClose = async () => {
|
const deleteAndClose = async () => {
|
||||||
await fetch(`/api/visualizations/delete`, {
|
await fetch(`/api/visualizations/delete`, {
|
||||||
|
|
@ -13,7 +13,7 @@ import lineStacked from "../images/line-stacked.svg";
|
||||||
import dataTable from "../images/data-table.svg";
|
import dataTable from "../images/data-table.svg";
|
||||||
import metric from "../images/metric.svg";
|
import metric from "../images/metric.svg";
|
||||||
import tagCloud from "../images/tag-cloud.svg";
|
import tagCloud from "../images/tag-cloud.svg";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
interface VisualizationSelectCardProps {
|
interface VisualizationSelectCardProps {
|
||||||
visualizationType: string;
|
visualizationType: string;
|
||||||
|
|
@ -38,7 +38,7 @@ export const VisualizationSelectCard: FC<VisualizationSelectCardProps> = ({
|
||||||
leafcutterLightBlue,
|
leafcutterLightBlue,
|
||||||
cdrLinkOrange,
|
cdrLinkOrange,
|
||||||
},
|
},
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const images: any = {
|
const images: any = {
|
||||||
horizontalBar,
|
horizontalBar,
|
||||||
horizontalBarStacked,
|
horizontalBarStacked,
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
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";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
export const Welcome = () => {
|
export const Welcome = () => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
|
|
@ -17,7 +17,7 @@ export const Welcome = () => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue },
|
colors: { white, leafcutterElectricBlue },
|
||||||
typography: { h1, h4, p },
|
typography: { h1, h4, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
|
@ -4,7 +4,7 @@ import { Box, Grid, Dialog, Button } from "@mui/material";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
// import { useSession } from "next-auth/react";
|
// import { useSession } from "next-auth/react";
|
||||||
// import { useTranslate } from "react-polyglot";
|
// import { useTranslate } from "react-polyglot";
|
||||||
import { useAppContext } from "./AppProvider";
|
import { useLeafcutterContext } from "./LeafcutterProvider";
|
||||||
|
|
||||||
export const WelcomeDialog = () => {
|
export const WelcomeDialog = () => {
|
||||||
// const t = useTranslate();
|
// const t = useTranslate();
|
||||||
|
|
@ -15,7 +15,7 @@ export const WelcomeDialog = () => {
|
||||||
const {
|
const {
|
||||||
colors: { white, leafcutterElectricBlue },
|
colors: { white, leafcutterElectricBlue },
|
||||||
typography: { h1, h6, p },
|
typography: { h1, h6, p },
|
||||||
} = useAppContext();
|
} = useLeafcutterContext();
|
||||||
const activeTooltip = searchParams?.get("tooltip")?.toString();
|
const activeTooltip = searchParams?.get("tooltip")?.toString();
|
||||||
const open = activeTooltip === "welcome";
|
const open = activeTooltip === "welcome";
|
||||||
|
|
||||||
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