Build and type fixes

This commit is contained in:
Darren Clarke 2023-05-24 20:27:57 +00:00
parent d5bd58ac3e
commit 656f3fbe71
64 changed files with 1878 additions and 1501 deletions

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
v20

View file

@ -1,15 +0,0 @@
FROM gitpod/workspace-full
# set up aws
RUN rm -rf ~/.aws
RUN mkdir ~/.aws
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/home/gitpod/awscliv2.zip"
RUN unzip ~/awscliv2.zip -d ~/awscliv2
RUN sudo ~/awscliv2/aws/install --update
RUN brew install aws-vault
RUN brew install kubectl
RUN brew install pipx
RUN pipx install aws-sso-util
RUN npm i -g prettier
RUN npm i -g npm-check-updates

View file

@ -1,6 +0,0 @@
tasks:
- init: npm install
command: npm run dev
image:
file: .gitpod.Dockerfile

View file

@ -1,12 +1,15 @@
import { FC } from "react";
import { FC, PropsWithChildren } from "react";
import { Box } from "@mui/material";
import { useAppContext } from "./AppProvider";
interface AboutBoxProps {
type AboutBoxProps = PropsWithChildren<{
backgroundColor: string;
}
}>;
export const AboutBox: FC<AboutBoxProps> = ({ backgroundColor, children }: any) => {
export const AboutBox: FC<AboutBoxProps> = ({
backgroundColor,
children,
}: any) => {
const {
colors: { white },
} = useAppContext();

View file

@ -36,7 +36,7 @@ export const AccountButton: FC = () => {
},
}}
>
<Image src={UserIcon} alt="account" width="30px" height="30px" />
<Image src={UserIcon} alt="account" width={30} height={30} />
</Button>
<Menu {...bindMenu(popupState)}>
<MenuItem

View file

@ -1,7 +1,16 @@
import { FC, createContext, useContext, useReducer, useState } from "react";
import {
FC,
createContext,
useContext,
useReducer,
useState,
PropsWithChildren,
} from "react";
import { colors, typography } from "styles/theme";
const basePath = process.env.GITLAB_CI ? "/link/link-stack/apps/leafcutter" : "";
const basePath = process.env.GITLAB_CI
? "/link/link-stack/apps/leafcutter"
: "";
const imageURL = (image: any) =>
typeof image === "string" ? `${basePath}${image}` : `${basePath}${image.src}`;
@ -9,16 +18,16 @@ const AppContext = createContext({
colors,
typography,
imageURL,
query: null,
updateQuery: null,
updateQueryType: null,
replaceQuery: null,
clearQuery: null,
query: null as any,
updateQuery: null as any,
updateQueryType: null as any,
replaceQuery: null as any,
clearQuery: null as any,
foundCount: 0,
setFoundCount: null,
setFoundCount: null as any,
});
export const AppProvider: FC = ({ children }) => {
export const AppProvider: FC<PropsWithChildren> = ({ children }) => {
const initialState = {
incidentType: {
display: "Incident Type",
@ -82,7 +91,10 @@ export const AppProvider: FC = ({ children }) => {
},
};
const reducer = (state: any, action: any) => {
const key = action.payload ? Object.keys(action.payload)[0] : null;
const key = action.payload?.[0];
if (!key) {
throw new Error("Unknown key");
}
const newState = { ...state };
switch (action.type) {
case "UPDATE":

View file

@ -5,7 +5,19 @@ import { useRouter } from "next/router";
import { useTranslate } from "react-polyglot";
import { useAppContext } from "./AppProvider";
const CheckboxItem = ({ title, description, checked, onChange }) => {
type CheckboxItemProps = {
title: string;
description: string;
checked: boolean;
onChange: () => void;
};
const CheckboxItem: FC<CheckboxItemProps> = ({
title,
description,
checked,
onChange,
}) => {
const {
typography: { p, small },
} = useAppContext();
@ -48,10 +60,10 @@ export const GettingStartedDialog: FC = () => {
typography: { h4 },
} = useAppContext();
const t = useTranslate();
const [completedItems, setCompletedItems] = useState([]);
const [completedItems, setCompletedItems] = useState([] as any[]);
const router = useRouter();
const open = router.query.tooltip?.toString() === "checklist";
const toggleCompletedItem = (item) => {
const toggleCompletedItem = (item: any) => {
if (completedItems.includes(item)) {
setCompletedItems(completedItems.filter((i) => i !== item));
} else {

View file

@ -14,7 +14,7 @@ export const LanguageSelect = () => {
colors: { white, leafcutterElectricBlue },
} = useAppContext();
const router = useRouter();
const locales = { en: "English", fr: "Français" };
const locales: any = { en: "English", fr: "Français" };
const popupState = usePopupState({ variant: "popover", popupId: "language" });
return (
@ -36,7 +36,7 @@ export const LanguageSelect = () => {
},
}}
>
{locales[router.locale] ?? locales.en}
{locales[router.locale as any] ?? locales.en}
<KeyboardArrowDownIcon />
</IconButton>
<Menu {...bindMenu(popupState)}>

View file

@ -1,3 +1,4 @@
import { FC, PropsWithChildren } from "react";
import { Grid, Container } from "@mui/material";
import CookieConsent from "react-cookie-consent";
import { useCookies } from "react-cookie";
@ -7,7 +8,7 @@ import { GettingStartedDialog } from "./GettingStartedDialog";
import { useAppContext } from "./AppProvider";
// import { Footer } from "./Footer";
export const Layout = ({ children }) => {
export const Layout: FC<PropsWithChildren> = ({ children }) => {
const [cookies, setCookie] = useCookies(["cookieConsent"]);
const consentGranted = cookies.cookieConsent === "true";
const {

View file

@ -1,12 +1,12 @@
/* eslint-disable react/require-default-props */
import { FC } from "react";
import { FC, PropsWithChildren } from "react";
import { Box } from "@mui/material";
import { useAppContext } from "./AppProvider";
interface PageHeaderProps {
type PageHeaderProps = PropsWithChildren<{
backgroundColor: string;
sx?: any;
}
}>;
export const PageHeader: FC<PageHeaderProps> = ({
backgroundColor,

View file

@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { FC, PropsWithChildren, useState } from "react";
import {
Box,
Grid,
@ -29,7 +29,14 @@ interface QueryBuilderSectionProps {
tooltipDescription: string;
}
const Tooltip = ({ title, description, children, open }) => {
type TooltipProps = PropsWithChildren<{
title: string;
description: string;
children: any;
open: boolean;
}>;
const Tooltip: FC<TooltipProps> = ({ title, description, children, open }) => {
const {
colors: { white, leafcutterElectricBlue, almostBlack },
typography: { h5, small },

View file

@ -63,6 +63,7 @@ export const QueryDateRangeSelector: FC<QueryDateRangeSelectorProps> = () => {
startDate: { values: [date] },
});
}}
// @ts-ignore
renderInput={(params) => (
<TextField
{...params}
@ -89,6 +90,7 @@ export const QueryDateRangeSelector: FC<QueryDateRangeSelectorProps> = () => {
endDate: { values: [date] },
});
}}
// @ts-ignore
renderInput={(params) => (
<TextField
{...params}

View file

@ -16,7 +16,7 @@ export const QueryListSelector: FC<QueryListSelectorProps> = ({
values,
width,
}) => {
const [selectionModel, setSelectionModel] = useState([]);
const [selectionModel, setSelectionModel] = useState([] as any[]);
const {
colors: { leafcutterLightBlue, pink, leafcutterElectricBlue, warningPink },
typography: { small },
@ -70,19 +70,19 @@ export const QueryListSelector: FC<QueryListSelectorProps> = ({
rows={rows}
columns={columns}
density="compact"
pageSize={100}
pageSizeOptions={[100]}
checkboxSelection
disableSelectionOnClick
disableRowSelectionOnClick
hideFooter
disableColumnMenu
scrollbarSize={10}
onSelectionModelChange={(newSelectionModel) => {
onRowSelectionModelChange={(newSelectionModel) => {
setSelectionModel(newSelectionModel);
updateQuery({
[keyName]: { values: newSelectionModel },
});
}}
selectionModel={selectionModel}
rowSelectionModel={selectionModel}
/>
</Grid>
</Grid>

View file

@ -12,7 +12,7 @@ export const QueryText: FC = () => {
query: q,
} = useAppContext();
const displayNames = {
const displayNames: any = {
incidentType: t("incidentType"),
startDate: t("startDate"),
endDate: t("endDate"),
@ -41,6 +41,7 @@ export const QueryText: FC = () => {
queryType === "include" ? ` ${t("is")} ` : ` ${t("isNot")} `
} ${values
.map(
// @ts-expect-error
(value: string) => `<em>${taxonomy[key]?.[value]?.display ?? ""}</em>`
)
.join(` ${t("or")} `)}</span>`;

View file

@ -16,7 +16,7 @@ export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
headerName: t("date"),
editable: false,
flex: 0.7,
valueFormatter: ({ value }) => new Date(value).toLocaleDateString(),
valueFormatter: ({ value }: any) => new Date(value).toLocaleDateString(),
},
{
field: "incident",
@ -58,7 +58,10 @@ export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
return (
<Grid item xs={12}>
<Box sx={{ width: "100%", height }} onClick={(e: any) => e.stopPropagation()}>
<Box
sx={{ width: "100%", height }}
onClick={(e: any) => e.stopPropagation()}
>
<Grid container direction="column" spacing={2}>
<Grid item>
<DataGridPro
@ -66,8 +69,8 @@ export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
rows={rows}
columns={columns}
density="compact"
pageSize={100}
disableSelectionOnClick
pageSizeOptions={[100]}
disableRowSelectionOnClick
hideFooter
disableColumnMenu
scrollbarSize={10}
@ -76,6 +79,6 @@ export const RawDataViewer: FC<RawDataViewerProps> = ({ rows, height }) => {
</Grid>
</Grid>
</Box>
</Grid >
</Grid>
);
};

View file

@ -49,8 +49,9 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
clearQuery,
} = useAppContext();
const { visualizations } = visualizationMap;
const [selectedVisualizationType, setSelectedVisualizationType] =
useState(null);
const [selectedVisualizationType, setSelectedVisualizationType] = useState(
null as any
);
const toggleSelectedVisualizationType = (visualizationType: string) => {
if (visualizationType === selectedVisualizationType) {
setSelectedVisualizationType(null);
@ -72,7 +73,7 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
updateSearches();
}, [setSavedSearches]);
const showSavedSearchPopup = (event) => {
const showSavedSearchPopup = (event: any) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
@ -104,8 +105,10 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
const updateSearch = (name: string) => {
handleClose();
closeDialog();
const found = savedSearches.find((search) => search.name === name);
replaceQuery(found.query);
const found: any = savedSearches.find(
(search: any) => search.name === name
);
replaceQuery(found?.query);
};
const clearSearch = () => clearQuery();
@ -240,7 +243,7 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
<ListItemText>{t("saveCurrentSearch")}</ListItemText>
</MenuItem>
<Divider />
{savedSearches.map((savedSearch) => (
{savedSearches.map((savedSearch: any) => (
<MenuItem
key={savedSearch.name}
onClick={() => updateSearch(savedSearch.name)}
@ -322,6 +325,7 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
<VisualizationSelectCard
key={key}
visualizationType={key}
// @ts-expect-error
title={visualizations[key].name}
enabled={
selectedVisualizationType === key ||
@ -347,6 +351,7 @@ export const VisualizationBuilder: FC<VisualizationBuilderProps> = ({
const { id, type, title, description } = template;
const cleanTitle = title
.replace("Templated", "")
// @ts-expect-error
.replace(visualizations[type].name, "");
const metricType = cleanTitle.replace(/\s/g, "").toLowerCase();
return (

View file

@ -37,7 +37,7 @@ export const VisualizationSelectCard: FC<VisualizationSelectCardProps> = ({
cdrLinkOrange,
},
} = useAppContext();
const images = {
const images: any = {
horizontalBar,
horizontalBarStacked,
verticalBar,

View file

@ -8,7 +8,7 @@ export const Welcome = () => {
const { data: session } = useSession();
const {
user: { name },
} = session;
} = session as any;
const {
colors: { white, leafcutterElectricBlue },
typography: { h1, h4, p },

View file

@ -103,7 +103,7 @@ export const getUserMetadata = async (username: string) => {
}
return res?.body._source;
}
};
export const saveUserMetadata = async (username: string, metadata: any) => {
const client = createClient();
@ -112,7 +112,7 @@ export const saveUserMetadata = async (username: string, metadata: any) => {
index: userMetadataIndexName,
body: { doc: { username, ...metadata } }
});
}
};
/* User */
@ -130,13 +130,13 @@ const getCurrentUserIndex = async (email: string) => {
const indicesResponse = await client.indices.get({
index: `.kibana_*_${userIndexName}_1`,
})
});
const currentUserIndex = Object.keys(indicesResponse.body)[0];
return currentUserIndex;
}
};
const getIndexPattern = async (index: string) => {
const getIndexPattern: any = async (index: string) => {
const client = createClient();
const query = {
query: {
@ -335,6 +335,7 @@ export const performQuery = async (searchQuery: any, limit: number) => {
if (searchQuery.relativeDate.values.length > 0) {
searchQuery.relativeDate.values.forEach((value: string) => {
// @ts-expect-error
body.query.bool.must.push({
range: {
date: {
@ -347,6 +348,7 @@ export const performQuery = async (searchQuery: any, limit: number) => {
if (searchQuery.startDate.values.length > 0) {
searchQuery.startDate.values.forEach((value: string) => {
// @ts-expect-error
body.query.bool.must.push({
range: {
date: {
@ -359,6 +361,7 @@ export const performQuery = async (searchQuery: any, limit: number) => {
if (searchQuery.endDate.values.length > 0) {
searchQuery.endDate.values.forEach((value: string) => {
// @ts-expect-error
body.query.bool.must.push({
range: {
date: {
@ -370,54 +373,63 @@ export const performQuery = async (searchQuery: any, limit: number) => {
}
if (searchQuery.incidentType.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "incident.keyword": searchQuery.incidentType.values },
});
}
if (searchQuery.targetedGroup.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "targeted_group.keyword": searchQuery.targetedGroup.values },
});
}
if (searchQuery.platform.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "technology.keyword": searchQuery.platform.values },
});
}
if (searchQuery.device.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "technology.keyword": searchQuery.device.values },
});
}
if (searchQuery.service.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "technology.keyword": searchQuery.service.values },
});
}
if (searchQuery.maker.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "technology.keyword": searchQuery.maker.values },
});
}
if (searchQuery.subregion.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "region.keyword": searchQuery.subregion.values },
});
}
if (searchQuery.country.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "country.keyword": searchQuery.country.values },
});
}
if (searchQuery.continent.values.length > 0) {
// @ts-expect-error
body.query.bool.must.push({
terms: { "continent.keyword": searchQuery.continent.values },
});

View file

@ -13,51 +13,50 @@
"lint": "next lint"
},
"dependencies": {
"@emotion/cache": "^11.10.3",
"@emotion/react": "^11.10.4",
"@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.4",
"@fontsource/playfair-display": "^4.5.12",
"@fontsource/poppins": "^4.5.10",
"@fontsource/roboto": "^4.5.8",
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.0",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@fontsource/playfair-display": "^5.0.1",
"@fontsource/poppins": "^5.0.1",
"@fontsource/roboto": "^5.0.1",
"@mui/icons-material": "^5",
"@mui/lab": "^5.0.0-alpha.102",
"@mui/lab": "^5.0.0-alpha.131",
"@mui/material": "^5",
"@mui/styles": "^5",
"@mui/x-data-grid-pro": "^5.17.5",
"@mui/x-date-pickers-pro": "^5.0.3",
"@mui/x-data-grid-pro": "^6.5.0",
"@mui/x-date-pickers-pro": "^6.5.0",
"@opensearch-project/opensearch": "^2.0.0",
"date-fns": "^2.29.3",
"date-fns": "^2.30.0",
"http-proxy-middleware": "^2.0.6",
"material-ui-popup-state": "^4.1.0",
"next": "^12.3",
"next-auth": "^4.12.2",
"next-http-proxy-middleware": "^1.2.4",
"nodemailer": "^6.8.0",
"react": "^17",
"material-ui-popup-state": "^5.0.8",
"next": "^13.4",
"next-auth": "^4.22.1",
"next-http-proxy-middleware": "^1.2.5",
"nodemailer": "^6.9.2",
"react": "^18",
"react-cookie": "^4.1.1",
"react-cookie-consent": "^8.0.1",
"react-dom": "^17",
"react-iframe": "^1.8.4",
"react-markdown": "^8.0.3",
"react-dom": "^18",
"react-iframe": "^1.8.5",
"react-markdown": "^8.0.7",
"react-polyglot": "^0.7.2",
"sharp": "^0.31.3",
"swr": "^1.3.0",
"sharp": "^0.32.1",
"swr": "^2.1.5",
"uuid": "^9.0.0"
},
"devDependencies": {
"@babel/core": "^7.19.3",
"@types/react": "^17",
"@types/uuid": "^8.3.4",
"babel-loader": "^8.2.5",
"eslint": "^8.24.0",
"@babel/core": "^7.21.8",
"@types/react": "^18",
"@types/uuid": "^9.0.1",
"babel-loader": "^9.1.2",
"eslint": "^8.41.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^12.3.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-config-next": "^13.4.3",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.8",
"typescript": "^4.9.5"
"eslint-plugin-react": "^7.32.2",
"typescript": "^5.0.4"
}
}

View file

@ -22,13 +22,11 @@ import "@fontsource/playfair-display/900.css";
import "styles/global.css";
import { LicenseInfo } from "@mui/x-data-grid-pro";
LicenseInfo.setLicenseKey(
"fd009c623acc055adb16370731be92e4T1JERVI6NDA3NTQsRVhQSVJZPTE2ODAyNTAwMTUwMDAsS0VZVkVSU0lPTj0x"
);
LicenseInfo.setLicenseKey(process.env.MUI_LICENSE_KEY ?? "");
const clientSideEmotionCache: any = createEmotionCache();
const messages = { en, fr };
const messages: any = { en, fr };
interface LeafcutterWebProps extends AppProps {
// eslint-disable-next-line react/require-default-props
@ -36,7 +34,7 @@ interface LeafcutterWebProps extends AppProps {
}
const LeafcutterWeb = (props: LeafcutterWebProps) => {
const { locale } = useRouter();
const { locale = "en" } = useRouter();
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
return (

View file

@ -5,12 +5,12 @@ import Apple from "next-auth/providers/apple";
export default NextAuth({
providers: [
Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
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
clientId: process.env.APPLE_CLIENT_ID ?? "",
clientSecret: process.env.APPLE_CLIENT_SECRET ?? "",
}),
],
secret: process.env.NEXTAUTH_SECRET,

View file

@ -3,8 +3,8 @@ import { NextApiRequest, NextApiResponse } from "next";
import { getToken } from "next-auth/jwt";
const withAuthInfo =
(handler) => async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getToken({
(handler: any) => async (req: NextApiRequest, res: NextApiResponse) => {
const session: any = await getToken({
req,
secret: process.env.NEXTAUTH_SECRET,
});

View file

@ -16,7 +16,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return res.status(500).json({ message: "Only POST requests are allowed" });
}
const { email } = session;
const { email }: any = session;
const { name, query } = JSON.parse(req.body);
const result = await getUserMetadata(email);
const { savedSearches } = result;
@ -24,8 +24,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
savedSearches: [...savedSearches, { name, query }]
});
const { savedSearches: updatedSavedSearches } = await getUserMetadata(email);
return res.json(updatedSavedSearches)
}
return res.json(updatedSavedSearches);
};
export default handler;

View file

@ -16,14 +16,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return res.status(500).json({ message: "Only POST requests are allowed" });
}
const { email } = session;
const { email }: any = session;
const { name } = JSON.parse(req.body);
const { savedSearches } = await getUserMetadata(email);
const updatedSavedSearches = savedSearches.filter(search => search.name !== name);
const result = await saveUserMetadata(email, { savedSearches: updatedSavedSearches })
const updatedSavedSearches = savedSearches.filter((search: any) => search.name !== name);
const result = await saveUserMetadata(email, { savedSearches: updatedSavedSearches });
return res.json({ result })
}
return res.json({ result });
};
export default handler;

View file

@ -16,10 +16,10 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return res.status(500).json({ message: "Only GET requests are allowed" });
}
const { email } = session;
const { email }: any = session;
const { savedSearches } = await getUserMetadata(email);
return res.json(savedSearches)
}
return res.json(savedSearches);
};
export default handler;

View file

@ -25,13 +25,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const { id } = ticket;
try {
const country = ticket.country[0] ?? "none";
// @ts-expect-error
const translatedCountry = taxonomy.country[country]?.display ?? "none";
const countryDetails = unRegions.find((c) => c.name === translatedCountry);
const countryDetails: any = unRegions.find((c) => c.name === translatedCountry);
const augmentedTicket = {
...ticket,
region: countryDetails['sub-region']?.toLowerCase().replace(" ", "-") ?? null,
continent: countryDetails.region?.toLowerCase().replace(" ", "-") ?? null,
}
};
const out = await client.create({
id: uuid(),
index: "sample_tagged_tickets",
@ -41,13 +42,13 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
console.log(out);
succeeded.push(id);
} catch (e) {
console.log(e)
console.log(e);
failed.push(id);
}
}
const results = { succeeded, failed };
return res.json(results)
return res.json(results);
};
export default handler;

View file

@ -18,14 +18,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const { visualizationID, title, description, query } = req.body;
const id = await createUserVisualization({
email: session.email,
email: session.email as string,
visualizationID,
title,
description,
query
});
return res.json({ id })
return res.json({ id });
};
export default handler;

View file

@ -17,9 +17,9 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}
const { id } = req.body;
await deleteUserVisualization(session.email, id);
await deleteUserVisualization(session.email as string, id);
return res.json({ id })
return res.json({ id });
};
export default handler;

View file

@ -18,14 +18,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const { id, title, description, query } = req.body;
await updateUserVisualization({
email: session.email,
email: session.email as string,
id,
title,
description,
query
});
return res.json({ id })
return res.json({ id });
};
export default handler;

View file

@ -1,4 +1,4 @@
import { useEffect } from "react";
import { FC, useEffect } from "react";
import { GetServerSideProps, GetServerSidePropsContext } from "next";
import Head from "next/head";
import { useTranslate } from "react-polyglot";
@ -12,7 +12,11 @@ import { useAppContext } from "components/AppProvider";
import { PageHeader } from "components/PageHeader";
import { VisualizationBuilder } from "components/VisualizationBuilder";
const Create = ({ templates }) => {
type CreateProps = {
templates: any;
};
const Create: FC<CreateProps> = ({ templates }) => {
const t = useTranslate();
const {
colors: { cdrLinkOrange },

View file

@ -1,5 +1,5 @@
import { useEffect } from "react";
import { GetServerSideProps, GetServerSidePropsContext } from "next";
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
import { useRouter } from "next/router";
import Head from "next/head";
import Link from "next/link";
@ -15,7 +15,13 @@ import { WelcomeDialog } from "components/WelcomeDialog";
import { VisualizationCard } from "components/VisualizationCard";
import { useAppContext } from "components/AppProvider";
const MyVisualizations = ({ visualizations }) => {
type MyVisualizationsProps = {
visualizations: any;
};
const MyVisualizations: NextPage<MyVisualizationsProps> = ({
visualizations,
}) => {
const router = useRouter();
const cookieName = "homeIntroComplete";
const [cookies, setCookie] = useCookies([cookieName]);
@ -85,7 +91,7 @@ const MyVisualizations = ({ visualizations }) => {
</Grid>
</Grid>
) : null}
{visualizations.map((visualization, index) => (
{visualizations.map((visualization: any, index: number) => (
<VisualizationCard
id={visualization.id}
key={index}

View file

@ -1,4 +1,5 @@
import Head from "next/head";
import { NextPage } from "next";
import Link from "next/link";
import Image from "next/image";
import { Box, Grid, Container, IconButton } from "@mui/material";
@ -9,7 +10,11 @@ import LeafcutterLogoLarge from "images/leafcutter-logo-large.png";
import { signIn, getSession } from "next-auth/react";
import { useAppContext } from "components/AppProvider";
const Login = ({ session }) => {
type LoginProps = {
session: any;
};
const Login: NextPage<LoginProps> = ({ session }) => {
const t = useTranslate();
const {
colors: { leafcutterElectricBlue, lightGray },
@ -112,7 +117,7 @@ const Login = ({ session }) => {
export default Login;
export async function getServerSideProps(context) {
export async function getServerSideProps(context: any) {
const session = (await getSession(context)) ?? null;
return {

View file

@ -1,10 +1,12 @@
import { FC, useLayoutEffect } from "react";
import { useLayoutEffect } from "react";
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
import { useRouter } from "next/router";
import { Grid, CircularProgress } from "@mui/material";
import Iframe from "react-iframe";
import { useAppContext } from "components/AppProvider";
import { checkAuth } from "lib/checkAuth";
export const Setup: FC = () => {
const Setup: NextPage = () => {
const {
colors: { leafcutterElectricBlue },
} = useAppContext();
@ -44,3 +46,7 @@ export const Setup: FC = () => {
};
export default Setup;
export const getServerSideProps: GetServerSideProps = async (
context: GetServerSidePropsContext
) => checkAuth(context);

View file

@ -1,4 +1,4 @@
import { GetServerSideProps, GetServerSidePropsContext } from "next";
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
import Head from "next/head";
import { Grid, Box } from "@mui/material";
import { useTranslate } from "react-polyglot";
@ -9,7 +9,11 @@ import { PageHeader } from "components/PageHeader";
import { VisualizationCard } from "components/VisualizationCard";
import { useAppContext } from "components/AppProvider";
const Trends = ({ visualizations }) => {
type TrendsProps = {
visualizations: any;
};
const Trends: NextPage<TrendsProps> = ({ visualizations }) => {
const t = useTranslate();
const {
colors: { cdrLinkOrange },
@ -58,7 +62,7 @@ const Trends = ({ visualizations }) => {
spacing={3}
justifyContent="space-between"
>
{visualizations.map((visualization, index) => (
{visualizations.map((visualization: any, index: number) => (
<VisualizationCard
key={index}
id={visualization.id}

View file

@ -1,12 +1,16 @@
/* eslint-disable no-underscore-dangle */
import { GetServerSideProps, GetServerSidePropsContext } from "next";
import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next";
import { Client } from "@opensearch-project/opensearch";
import Head from "next/head";
import { Layout } from "components/Layout";
import { VisualizationDetail } from "components/VisualizationDetail";
import { checkAuth } from "lib/checkAuth";
const Visualization = ({ visualization }) => (
type VisualizationProps = {
visualization: any;
};
const Visualization: NextPage<VisualizationProps> = ({ visualization }) => (
<Layout>
<Head>
<title>Digital Threat Dashboard Leafcutter</title>
@ -43,7 +47,8 @@ export const getServerSideProps: GetServerSideProps = async (
const response = rawResponse.body;
const hits = response.hits.hits.filter(
(hit) => hit._id.split(":")[1] === visualizationID[0]
// @ts-expect-error
(hit: any) => hit._id.split(":")[1] === visualizationID[0]
);
const hit = hits[0];
res.props.visualization = {

View file

@ -4,7 +4,7 @@
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,

View file

@ -0,0 +1,76 @@
import { FC, useState } from "react";
import { useRouter } from "next/router";
import Iframe from "react-iframe";
type InternalZammadWrapperProps = {
path: string;
hideSidebar?: boolean;
};
export const InternalZammadWrapper: FC<InternalZammadWrapperProps> = ({
path,
hideSidebar = true,
}) => {
const router = useRouter();
const [display, setDisplay] = useState("none");
const url = `${origin}/zammad${path}`;
console.log({ origin, path, url });
return (
// @ts-ignore
<Iframe
id="link"
url={url}
width="100%"
height="100%"
frameBorder={0}
styles={{ display }}
onLoad={() => {
const linkElement = document.querySelector("iframe");
if (
linkElement.contentDocument &&
linkElement.contentDocument?.querySelector &&
linkElement.contentDocument.querySelector("#navigation") &&
linkElement.contentDocument.querySelector("body") &&
linkElement.contentDocument.querySelector(".sidebar")
) {
// @ts-ignore
linkElement.contentDocument.querySelector("#navigation").style =
"display: none";
// @ts-ignore
linkElement.contentDocument.querySelector("body").style =
"font-family: Arial";
if (hideSidebar) {
// @ts-ignore
linkElement.contentDocument.querySelector(".sidebar").style =
"display: none";
}
// @ts-ignore
if (linkElement.contentDocument.querySelector(".overview-header")) {
// @ts-ignore
linkElement.contentDocument.querySelector(".overview-header").style =
"display: none";
}
setDisplay("inherit");
if (linkElement.contentWindow) {
linkElement.contentWindow.addEventListener('hashchange', () => {
const hash = linkElement.contentWindow?.location?.hash ?? ""
if (hash.startsWith("#ticket/zoom/")) {
setDisplay("none");
const ticketID = hash.split("/").pop();
router.push(`/tickets/${ticketID}`);
setTimeout(() => {
setDisplay("inherit");
}, 1000);
}
});
}
}
}}
/>
);
};

View file

@ -1,6 +1,12 @@
import { FC, useState } from "react";
import { useRouter } from "next/router";
import Iframe from "react-iframe";
import { FC } from "react";
import dynamic from "next/dynamic";
const InternalZammadWrapper = dynamic(
import("./InternalZammadWrapper").then((mod) => mod.InternalZammadWrapper),
{
ssr: false,
}
);
type ZammadWrapperProps = {
path: string;
@ -9,72 +15,5 @@ type ZammadWrapperProps = {
export const ZammadWrapper: FC<ZammadWrapperProps> = ({
path,
hideSidebar = true,
}) => {
const router = useRouter();
const origin =
typeof window !== "undefined" && window.location.origin
? window.location.origin
: "";
const [display, setDisplay] = useState("none");
const url = `${origin}/zammad${path}`;
console.log({ origin, path, url });
return (
// @ts-ignore
<Iframe
id="link"
url={url}
width="100%"
height="100%"
frameBorder={0}
styles={{ display }}
onLoad={() => {
const linkElement = document.querySelector("iframe");
if (
linkElement.contentDocument &&
linkElement.contentDocument?.querySelector &&
linkElement.contentDocument.querySelector("#navigation") &&
linkElement.contentDocument.querySelector("body") &&
linkElement.contentDocument.querySelector(".sidebar")
) {
// @ts-ignore
linkElement.contentDocument.querySelector("#navigation").style =
"display: none";
// @ts-ignore
linkElement.contentDocument.querySelector("body").style =
"font-family: Arial";
if (hideSidebar) {
// @ts-ignore
linkElement.contentDocument.querySelector(".sidebar").style =
"display: none";
}
// @ts-ignore
if (linkElement.contentDocument.querySelector(".overview-header")) {
// @ts-ignore
linkElement.contentDocument.querySelector(".overview-header").style =
"display: none";
}
setDisplay("inherit");
if (linkElement.contentWindow) {
linkElement.contentWindow.addEventListener('hashchange', () => {
const hash = linkElement.contentWindow?.location?.hash ?? ""
if (hash.startsWith("#ticket/zoom/")) {
setDisplay("none");
const ticketID = hash.split("/").pop();
router.push(`/tickets/${ticketID}`);
setTimeout(() => {
setDisplay("inherit");
}, 1000);
}
});
}
}
}}
/>
);
};
hideSidebar,
}) => <InternalZammadWrapper path={path} hideSidebar={hideSidebar} />;

30
apps/link/middleware.ts Normal file
View file

@ -0,0 +1,30 @@
import { withAuth } from "next-auth/middleware";
export default withAuth(
() => { },
{
pages: {
signIn: `/login`,
},
callbacks: {
authorized: ({ token, req }) => {
const {
url,
headers,
} = req;
// check login page
const parsedURL = new URL(url);
if (parsedURL.pathname.startsWith('/login')) {
return true;
}
// check session auth
const authorizedDomains = ["redaranj.com", "digiresilience.org"];
const userDomain = token?.email?.toLowerCase().split("@").pop() ?? "unauthorized.net";
return false;
},
}
}
);

View file

@ -1,4 +1,5 @@
module.exports = {
reactStrictMode: true,
rewrites: async () => ({
fallback: [
{

View file

@ -11,45 +11,45 @@
"dependencies": {
"@chatscope/chat-ui-kit-react": "^1.10.1",
"@chatscope/chat-ui-kit-styles": "^1.4.0",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.5",
"@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.5",
"@fontsource/playfair-display": "^4.5.13",
"@fontsource/poppins": "^4.5.10",
"@fontsource/roboto": "^4.5.8",
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.0",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@fontsource/playfair-display": "^5.0.1",
"@fontsource/poppins": "^5.0.1",
"@fontsource/roboto": "^5.0.1",
"@mui/icons-material": "^5",
"@mui/lab": "^5.0.0-alpha.118",
"@mui/lab": "^5.0.0-alpha.131",
"@mui/material": "^5",
"@mui/x-data-grid-pro": "^5.17.22",
"@mui/x-date-pickers-pro": "^5.0.17",
"date-fns": "^2.29.3",
"graphql-request": "^5.2.0",
"@mui/x-data-grid-pro": "^6.5.0",
"@mui/x-date-pickers-pro": "^6.5.0",
"date-fns": "^2.30.0",
"graphql-request": "^6.1.0",
"http-proxy-middleware": "^2.0.6",
"material-ui-popup-state": "^5.0.4",
"next": "^12",
"next-auth": "^4.19.2",
"material-ui-popup-state": "^5.0.8",
"next": "^13",
"next-auth": "^4.22.1",
"next-http-proxy-middleware": "^1.2.5",
"react": "^17",
"react-dom": "^17",
"react": "^18",
"react-dom": "^18",
"react-iframe": "^1.8.5",
"react-polyglot": "^0.7.2",
"sharp": "^0.30.7",
"swr": "^2.0.3"
"sharp": "^0.32.1",
"swr": "^2.1.5"
},
"devDependencies": {
"@babel/core": "^7.20.12",
"@babel/core": "^7.21.8",
"@types/react": "^18",
"@types/uuid": "^9.0.0",
"@types/uuid": "^9.0.1",
"babel-loader": "^9.1.2",
"eslint": "^8.33.0",
"eslint": "^8.41.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^13.1.6",
"eslint-config-prettier": "^8.6.0",
"eslint-config-next": "^13.4.3",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"typescript": "^4.9.5"
"typescript": "^5.0.4"
}
}

13
apps/link/pages/404.tsx Normal file
View file

@ -0,0 +1,13 @@
import { FC } from "react";
import Head from "next/head";
import { Layout } from "components/Layout";
const FourOhFour: FC = () => (
<Layout>
<Head>
<title>Link Shell</title>
</Head>
</Layout>
);
export default FourOhFour;

13
apps/link/pages/500.tsx Normal file
View file

@ -0,0 +1,13 @@
import { FC } from "react";
import Head from "next/head";
import { Layout } from "components/Layout";
const FiveHundred: FC = () => (
<Layout>
<Head>
<title>Link Shell</title>
</Head>
</Layout>
);
export default FiveHundred;

View file

@ -17,9 +17,7 @@ import { LicenseInfo } from "@mui/x-data-grid-pro";
import { SWRConfig } from "swr";
import { GraphQLClient } from "graphql-request";
LicenseInfo.setLicenseKey(
"fd009c623acc055adb16370731be92e4T1JERVI6NDA3NTQsRVhQSVJZPTE2ODAyNTAwMTUwMDAsS0VZVkVSU0lPTj0x"
);
LicenseInfo.setLicenseKey(process.env.MUI_LICENSE_KEY);
const clientSideEmotionCache: any = createEmotionCache();
@ -28,15 +26,18 @@ interface LinkWebProps extends AppProps {
emotionCache?: EmotionCache;
}
const LinkWeb = (props: LinkWebProps) => {
export default function LinkWeb(props: LinkWebProps) {
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
const [csrfToken, setCsrfToken] = useState("");
const origin = typeof window !== 'undefined' && window.location.origin
? window.location.origin : null;
const origin =
typeof window !== "undefined" && window.location.origin
? window.location.origin
: null;
const client = new GraphQLClient(`${origin}/graphql`, {
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
Accept: "application/json",
},
});
const graphQLFetcher = async ({ document, variables }: any) => {
@ -49,7 +50,7 @@ const LinkWeb = (props: LinkWebProps) => {
requestHeaders
);
const token = headers.get('CSRF-Token');
const token = headers.get("CSRF-Token");
setCsrfToken(token);
return data;
@ -67,6 +68,4 @@ const LinkWeb = (props: LinkWebProps) => {
</CacheProvider>
</SessionProvider>
);
};
export default LinkWeb;
}

View file

@ -1,4 +1,3 @@
// @ts-nocheck
import { FC } from "react";
import Head from "next/head";
import { Grid } from "@mui/material";
@ -30,3 +29,5 @@ const LabelStudio: FC = () => (
);
export default LabelStudio;
export const getServerSideProps = async (context: any) => {};

View file

@ -1,4 +1,3 @@
// @ts-nocheck
import { FC } from "react";
import Head from "next/head";
import { Grid } from "@mui/material";
@ -30,3 +29,5 @@ const Metamigo: FC = () => (
);
export default Metamigo;
export const getServerSideProps = async (context: any) => {};

View file

@ -29,3 +29,5 @@ const Zammad: FC = () => (
);
export default Zammad;
export const getServerSideProps = async (context: any) => {};

View file

@ -28,3 +28,5 @@ const Home = () => (
);
export default Home;
export const getServerSideProps = async (context: any) => {};

View file

@ -1,7 +1,6 @@
// @ts-nocheck
import { FC, useState } from "react";
import Head from "next/head";
import { Grid, Button } from "@mui/material";
import { Grid } from "@mui/material";
import { Layout } from "components/Layout";
import Iframe from "react-iframe";
@ -35,3 +34,5 @@ const About: FC = () => {
};
export default About;
export const getServerSideProps = async (context: any) => {};

View file

@ -35,3 +35,5 @@ const Create: FC = () => {
};
export default Create;
export const getServerSideProps = async (context: any) => {};

View file

@ -35,3 +35,5 @@ const FAQ: FC = () => {
};
export default FAQ;
export const getServerSideProps = async (context: any) => {};

View file

@ -1,4 +1,3 @@
// @ts-nocheck
import { FC, useState } from "react";
import Head from "next/head";
import { Grid, Button } from "@mui/material";
@ -35,3 +34,5 @@ const Leafcutter: FC = () => {
};
export default Leafcutter;
export const getServerSideProps = async (context: any) => {};

View file

@ -35,3 +35,5 @@ const Trends: FC = () => {
};
export default Trends;
export const getServerSideProps = async (context: any) => {};

View file

@ -1,30 +0,0 @@
import Head from "next/head";
import { Grid } from "@mui/material";
import { Layout } from "components/Layout";
import { ZammadWrapper } from "components/ZammadWrapper";
const Link = () => (
<Layout>
<Head>
<title>Link Shell</title>
</Head>
<Grid
container
spacing={0}
sx={{ height: "100%", width: "100%" }}
direction="column"
>
<Grid
item
sx={{
height: "100%",
width: "100%",
}}
>
<ZammadWrapper path="/zammad/#ticket/zoom/518/1490" />
</Grid>
</Grid>
</Layout>
);
export default Link;

View file

@ -1,12 +1,18 @@
import Head from "next/head";
import { FC } from "react";
import { Box, Grid, Container, IconButton } from "@mui/material";
import { Apple as AppleIcon, Google as GoogleIcon } from "@mui/icons-material";
import { signIn, getSession } from "next-auth/react";
const Login = ({ session }) => {
const origin = typeof window !== 'undefined' && window.location.origin
type LoginProps = {
session: any;
};
const Login: FC<LoginProps> = ({ session }) => {
const origin =
typeof window !== "undefined" && window.location.origin
? window.location.origin
: '';
: "";
const buttonStyles = {
borderRadius: 500,
width: "100%",

View file

@ -29,3 +29,5 @@ const Profile: NextPage = () => (
);
export default Profile;
export const getServerSideProps = async (context: any) => {};

View file

@ -29,3 +29,5 @@ const Assigned: FC = () => (
);
export default Assigned;
export const getServerSideProps = async (context: any) => {};

View file

@ -29,3 +29,5 @@ const Pending: FC = () => (
);
export default Pending;
export const getServerSideProps = async (context: any) => {};

View file

@ -29,3 +29,5 @@ const Unassigned: FC = () => (
);
export default Unassigned;
export const getServerSideProps = async (context: any) => {};

View file

@ -29,3 +29,5 @@ const Urgent: FC = () => (
);
export default Urgent;
export const getServerSideProps = async (context: any) => {};

View file

@ -5,7 +5,7 @@ import MicIcon from "@material-ui/icons/Mic";
import StopIcon from "@material-ui/icons/Stop";
import Button from "@material-ui/core/Button";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import AudioPlayer from "material-ui-audio-player";
// import AudioPlayer from "material-ui-audio-player";
import { useStopwatch } from "react-timer-hook";
import style from "./MicInput.module.css";
// import type { ReactMicProps } from "react-mic";
@ -130,7 +130,7 @@ const MicInput = (props: any) => {
)}
</div>
<div className={style.playerWrapper}>
{canPlay && (
{/* canPlay && (
<AudioPlayer
elevation={0}
src={decodedValue}
@ -138,7 +138,7 @@ const MicInput = (props: any) => {
volume={false}
useStyles={useStyles}
/>
)}
) */}
</div>
</div>
</div>

View file

@ -3,33 +3,31 @@
"version": "0.2.0",
"private": true,
"dependencies": {
"@apollo/client": "^3.7.4",
"@apollo/client": "^3.7.14",
"@digiresilience/metamigo-config": "*",
"@hapi/boom": "^10.0.0",
"@hapi/wreck": "^18.0.0",
"@hapi/boom": "^10.0.1",
"@hapi/wreck": "^18.0.1",
"@mui/icons-material": "^5",
"@mui/material": "^5",
"@mui/styles": "^5",
"@twilio/voice-sdk": "^2.2.0",
"@twilio/voice-sdk": "^2.5.0",
"http-proxy-middleware": "^2.0.6",
"jsonwebtoken": "^9.0.0",
"jwks-rsa": "^3.0.1",
"material-ui-audio-player": "^1.7.1",
"next": "12.3.4",
"next-auth": "4.18.8",
"ra-data-graphql": "^4.6.0",
"ra-i18n-polyglot": "^4.7.0",
"ra-input-rich-text": "^4.7.1",
"ra-language-english": "^4.7.0",
"next": "13.4.3",
"next-auth": "4.22.1",
"ra-data-graphql": "^4.10.1",
"ra-i18n-polyglot": "^4.10.6",
"ra-input-rich-text": "^4.10.6",
"ra-language-english": "^4.10.6",
"ra-postgraphile": "^6.1.0",
"react": "^17",
"react-admin": "^4.7.1",
"react": "^18",
"react-admin": "^4.10.6",
"react-digit-input": "^2.1.0",
"react-dom": "^17",
"react-dom": "^18",
"react-qr-code": "^2.0.11",
"react-redux": "^8.0.5",
"react-timer-hook": "^3.0.5",
"swr": "^2.0.0",
"react-timer-hook": "^3.0.6",
"swr": "^2.1.5",
"twilio-client": "^1.15.0"
},
"scripts": {
@ -42,14 +40,14 @@
"fmt": "prettier --ignore-path .eslintignore \"**/*.{js,jsx,ts,tsx,graphql,md}\" --list-different"
},
"devDependencies": {
"@next/eslint-plugin-next": "^13.1.2",
"@next/eslint-plugin-next": "^13.4.3",
"@types/hapi__wreck": "17.0.1",
"@types/react": "^17",
"@types/react": "^18",
"@types/react-mic": "12.4.3",
"babel-preset-link": "*",
"eslint-config-link": "*",
"jest-config-link": "*",
"tsconfig-link": "*",
"typescript": "^4.9.5"
"typescript": "^5.0.4"
}
}

2598
package-lock.json generated

File diff suppressed because it is too large Load diff