Metamigo -> Bridge

This commit is contained in:
Darren Clarke 2024-04-21 09:44:30 +02:00
parent 242f3cf6b8
commit a445762a37
145 changed files with 396 additions and 16668 deletions

View file

@ -241,7 +241,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
fontFamily: poppins.style.fontFamily,
}}
>
Metamigo
CDR Bridge
</Typography>
</Grid>
)}

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before After
Before After

View file

@ -2,10 +2,12 @@ import type { Metadata } from "next";
import { InternalLayout } from "./_components/InternalLayout";
import { LicenseInfo } from "@mui/x-license";
LicenseInfo.setLicenseKey("7c9bf25d9e240f76e77cbf7d2ba58a23Tz02NjU4OCxFPTE3MTU4NjIzMzQ2ODgsUz1wcm8sTE09c3Vic2NyaXB0aW9uLEtWPTI=");
LicenseInfo.setLicenseKey(
"7c9bf25d9e240f76e77cbf7d2ba58a23Tz02NjU4OCxFPTE3MTU4NjIzMzQ2ODgsUz1wcm8sTE09c3Vic2NyaXB0aW9uLEtWPTI=",
);
export const metadata: Metadata = {
title: "Metamigo",
title: "CDR Bridge",
description: "",
};

View file

@ -1,5 +1,5 @@
{
"name": "metamigo-frontend",
"name": "bridge-frontend",
"version": "0.1.0",
"private": true,
"scripts": {
@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@auth/kysely-adapter": "^0.7.0",
"@auth/kysely-adapter": "^1.0.0",
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
@ -17,14 +17,14 @@
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5",
"@mui/material-nextjs": "^5.15.11",
"@mui/x-data-grid-pro": "^7.1.1",
"@mui/x-date-pickers-pro": "^7.1.1",
"@mui/x-license": "^7.1.1",
"@mui/x-data-grid-pro": "^7.3.0",
"@mui/x-date-pickers-pro": "^7.2.0",
"@mui/x-license": "^7.2.0",
"date-fns": "^3.6.0",
"kysely": "^0.26.1",
"material-ui-popup-state": "^5.1.0",
"mui-chips-input": "^2.1.4",
"next": "14.1.4",
"next": "14.2.2",
"next-auth": "^4.24.7",
"pg": "^8.11.5",
"react": "18.2.0",
@ -41,8 +41,8 @@
"@types/pg": "^8.11.5",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^9",
"eslint-config-next": "14.1.4",
"eslint": "^8",
"eslint-config-next": "14.2.2",
"ts-config": "*",
"typescript": "^5"
}

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Before After
Before After

View file

@ -0,0 +1,3 @@
{
"presets": ["@digiresilience/babel-preset-bridge"]
}

View file

@ -1,16 +1,16 @@
/* eslint-disable camelcase */
import { SavedVoiceProvider } from "@digiresilience/metamigo-db";
import { SavedVoiceProvider } from "@digiresilience/bridge-db";
import Twilio from "twilio";
import { CallInstance } from "twilio/lib/rest/api/v2010/account/call";
import { Zammad, getOrCreateUser } from "./zammad";
export const twilioClientFor = (
provider: SavedVoiceProvider
provider: SavedVoiceProvider,
): Twilio.Twilio => {
const { accountSid, apiKeySid, apiKeySecret } = provider.credentials;
if (!accountSid || !apiKeySid || !apiKeySecret)
throw new Error(
`twilio provider ${provider.name} does not have credentials`
`twilio provider ${provider.name} does not have credentials`,
);
return Twilio(apiKeySid, apiKeySecret, {
@ -20,7 +20,7 @@ export const twilioClientFor = (
export const createZammadTicket = async (
call: CallInstance,
mp3: Buffer
mp3: Buffer,
): Promise<void> => {
const title = `Call from ${call.fromFormatted} at ${call.startTime}`;
const body = `<ul>
@ -36,7 +36,7 @@ export const createZammadTicket = async (
{
token: "EviH_WL0p6YUlCoIER7noAZEAPsYA_fVU4FZCKdpq525Vmzzvl8d7dNuP_8d-Amb",
},
"https://demo.digiresilience.org"
"https://demo.digiresilience.org",
);
try {
const customer = await getOrCreateUser(zammad, call.fromFormatted);

View file

@ -1,12 +1,16 @@
import pgPromise from "pg-promise";
import * as pgMonitor from "pg-monitor";
import { dbInitOptions, IRepositories, AppDatabase } from "@digiresilience/metamigo-db";
import config from "@digiresilience/metamigo-config";
import {
dbInitOptions,
IRepositories,
AppDatabase,
} from "@digiresilience/bridge-db";
import config from "@digiresilience/bridge-config";
import type { IInitOptions } from "pg-promise";
export const initDiagnostics = (
logSql: boolean,
initOpts: IInitOptions<IRepositories>
initOpts: IInitOptions<IRepositories>,
): void => {
if (logSql) {
pgMonitor.attach(initOpts);
@ -44,4 +48,4 @@ export const withDb = <T>(f: (db: AppDatabase) => Promise<T>): Promise<T> => {
}
};
export type { AppDatabase } from "@digiresilience/metamigo-db";
export type { AppDatabase } from "@digiresilience/bridge-db";

View file

@ -1,6 +1,6 @@
import { defState } from "@digiresilience/montar";
import { configureLogger } from "@digiresilience/metamigo-common";
import config from "@digiresilience/metamigo-config";
import { configureLogger } from "@digiresilience/bridge-common";
import config from "@digiresilience/bridge-config";
export const logger = defState("workerLogger", {
start: async () => configureLogger(config),

View file

@ -1,5 +1,5 @@
{
"name": "metamigo-worker",
"name": "bridge-worker",
"version": "0.2.0",
"main": "build/main/index.js",
"type": "module",
@ -10,8 +10,8 @@
"html-to-text": "^9.0.5",
"node-fetch": "^3",
"pg-promise": "^11.6.0",
"remeda": "^1.57.2",
"twilio": "^5.0.3"
"remeda": "^1.60.1",
"twilio": "^5.0.4"
},
"devDependencies": {
"ts-config": "*",
@ -29,7 +29,7 @@
"prettier": "^3.2.5",
"ts-node": "^10.9.2",
"typedoc": "^0.25.13",
"typescript": "^5.4.4"
"typescript": "^5.4.5"
},
"nodemonConfig": {
"ignore": [

View file

@ -3,29 +3,35 @@ import { convert } from "html-to-text";
import fetch from "node-fetch";
import { URLSearchParams } from "url";
import { withDb, AppDatabase } from "../db";
import { loadConfig } from "@digiresilience/metamigo-config";
import { loadConfig } from "@digiresilience/bridge-config";
import { tagMap } from "../lib/tag-map";
type FormattedZammadTicket = {
data: Record<string, unknown>,
data: Record<string, unknown>;
predictions: Record<string, unknown>[];
};
const getZammadTickets = async (page: number, minUpdatedTimestamp: Date): Promise<[boolean, FormattedZammadTicket[]]> => {
const { leafcutter: { zammadApiUrl, zammadApiKey, contributorName, contributorId } } = await loadConfig();
const getZammadTickets = async (
page: number,
minUpdatedTimestamp: Date,
): Promise<[boolean, FormattedZammadTicket[]]> => {
const {
leafcutter: { zammadApiUrl, zammadApiKey, contributorName, contributorId },
} = await loadConfig();
const headers = { Authorization: `Token ${zammadApiKey}` };
let shouldContinue = false;
const docs = [];
const ticketsQuery = new URLSearchParams({
"expand": "true",
"sort_by": "updated_at",
"order_by": "asc",
"query": "state.name: closed",
"per_page": "25",
"page": `${page}`,
expand: "true",
sort_by: "updated_at",
order_by: "asc",
query: "state.name: closed",
per_page: "25",
page: `${page}`,
});
const rawTickets = await fetch(`${zammadApiUrl}/tickets/search?${ticketsQuery}`,
{ headers }
const rawTickets = await fetch(
`${zammadApiUrl}/tickets/search?${ticketsQuery}`,
{ headers },
);
const tickets: any = await rawTickets.json();
console.log({ tickets });
@ -41,14 +47,25 @@ const getZammadTickets = async (page: number, minUpdatedTimestamp: Date): Promis
shouldContinue = true;
if (source_closed_at <= minUpdatedTimestamp) {
console.log(`Skipping ticket`, { source_id, source_updated_at, source_closed_at, minUpdatedTimestamp });
console.log(`Skipping ticket`, {
source_id,
source_updated_at,
source_closed_at,
minUpdatedTimestamp,
});
continue;
}
console.log(`Processing ticket`, { source_id, source_updated_at, source_closed_at, minUpdatedTimestamp });
console.log(`Processing ticket`, {
source_id,
source_updated_at,
source_closed_at,
minUpdatedTimestamp,
});
const rawArticles = await fetch(`${zammadApiUrl}/ticket_articles/by_ticket/${source_id}`,
{ headers }
const rawArticles = await fetch(
`${zammadApiUrl}/ticket_articles/by_ticket/${source_id}`,
{ headers },
);
const articles: any = await rawArticles.json();
let articleText = "";
@ -69,7 +86,9 @@ const getZammadTickets = async (page: number, minUpdatedTimestamp: Date): Promis
o_id: source_id,
});
const rawTags = await fetch(`${zammadApiUrl}/tags?${tagsQuery}`, { headers });
const rawTags = await fetch(`${zammadApiUrl}/tags?${tagsQuery}`, {
headers,
});
const { tags }: any = await rawTags.json();
const transformedTags = [];
for (const tag of tags) {
@ -88,7 +107,7 @@ const getZammadTickets = async (page: number, minUpdatedTimestamp: Date): Promis
source_created_at,
source_updated_at,
},
predictions: []
predictions: [],
};
const result = transformedTags.map((tag) => {
@ -115,12 +134,17 @@ const getZammadTickets = async (page: number, minUpdatedTimestamp: Date): Promis
return [shouldContinue, docs];
};
const fetchFromZammad = async (minUpdatedTimestamp: Date): Promise<FormattedZammadTicket[]> => {
const fetchFromZammad = async (
minUpdatedTimestamp: Date,
): Promise<FormattedZammadTicket[]> => {
const pages = [...Array.from({ length: 10000 }).keys()];
const allTickets: FormattedZammadTicket[] = [];
for await (const page of pages) {
const [shouldContinue, tickets] = await getZammadTickets(page + 1, minUpdatedTimestamp);
const [shouldContinue, tickets] = await getZammadTickets(
page + 1,
minUpdatedTimestamp,
);
if (!shouldContinue) {
break;
@ -135,7 +159,9 @@ const fetchFromZammad = async (minUpdatedTimestamp: Date): Promise<FormattedZamm
};
const sendToLabelStudio = async (tickets: FormattedZammadTicket[]) => {
const { leafcutter: { labelStudioApiUrl, labelStudioApiKey } } = await loadConfig();
const {
leafcutter: { labelStudioApiUrl, labelStudioApiKey },
} = await loadConfig();
const headers = {
Authorization: `Token ${labelStudioApiKey}`,
@ -157,10 +183,14 @@ const sendToLabelStudio = async (tickets: FormattedZammadTicket[]) => {
const importLabelStudioTask = async (): Promise<void> => {
withDb(async (db: AppDatabase) => {
const { leafcutter: { contributorName } } = await loadConfig();
const {
leafcutter: { contributorName },
} = await loadConfig();
const settingName = `${contributorName}ImportLabelStudioTask`;
const res: any = await db.settings.findByName(settingName);
const startTimestamp = res?.value?.minUpdatedTimestamp ? new Date(res.value.minUpdatedTimestamp as string) : new Date("2023-03-01");
const startTimestamp = res?.value?.minUpdatedTimestamp
? new Date(res.value.minUpdatedTimestamp as string)
: new Date("2023-03-01");
const tickets = await fetchFromZammad(startTimestamp);
if (tickets.length > 0) {
@ -168,7 +198,9 @@ const importLabelStudioTask = async (): Promise<void> => {
const lastTicket = tickets.pop();
const newLastTimestamp = lastTicket.data.source_closed_at;
console.log({ newLastTimestamp });
await db.settings.upsert(settingName, { minUpdatedTimestamp: newLastTimestamp });
await db.settings.upsert(settingName, {
minUpdatedTimestamp: newLastTimestamp,
});
}
});
};

View file

@ -2,7 +2,7 @@
import fetch from "node-fetch";
import { URLSearchParams } from "url";
import { withDb, AppDatabase } from "../db";
import { loadConfig } from "@digiresilience/metamigo-config";
import { loadConfig } from "@digiresilience/bridge-config";
type LabelStudioTicket = {
id: string;
@ -27,12 +27,11 @@ type LeafcutterTicket = {
source_updated_at: string;
};
const getLabelStudioTickets = async (page: number): Promise<LabelStudioTicket[]> => {
const getLabelStudioTickets = async (
page: number,
): Promise<LabelStudioTicket[]> => {
const {
leafcutter: {
labelStudioApiUrl,
labelStudioApiKey,
}
leafcutter: { labelStudioApiUrl, labelStudioApiKey },
} = await loadConfig();
const headers = {
@ -44,8 +43,10 @@ const getLabelStudioTickets = async (page: number): Promise<LabelStudioTicket[]>
page: `${page}`,
});
console.log({ url: `${labelStudioApiUrl}/projects/1/tasks?${ticketsQuery}` });
const res = await fetch(`${labelStudioApiUrl}/projects/1/tasks?${ticketsQuery}`,
{ headers });
const res = await fetch(
`${labelStudioApiUrl}/projects/1/tasks?${ticketsQuery}`,
{ headers },
);
console.log({ res });
const tasksResult: any = await res.json();
console.log({ tasksResult });
@ -53,7 +54,9 @@ const getLabelStudioTickets = async (page: number): Promise<LabelStudioTicket[]>
return tasksResult;
};
const fetchFromLabelStudio = async (minUpdatedTimestamp: Date): Promise<LabelStudioTicket[]> => {
const fetchFromLabelStudio = async (
minUpdatedTimestamp: Date,
): Promise<LabelStudioTicket[]> => {
const pages = [...Array.from({ length: 10000 }).keys()];
const allDocs: LabelStudioTicket[] = [];
@ -85,8 +88,8 @@ const sendToLeafcutter = async (tickets: LabelStudioTicket[]) => {
contributorId,
opensearchApiUrl,
opensearchUsername,
opensearchPassword
}
opensearchPassword,
},
} = await loadConfig();
console.log({ tickets });
@ -96,11 +99,7 @@ const sendToLeafcutter = async (tickets: LabelStudioTicket[]) => {
const {
id,
annotations,
data: {
source_id,
source_created_at,
source_updated_at
}
data: { source_id, source_created_at, source_updated_at },
} = ticket;
const getTags = (tags: Record<string, any>[], name: string) =>
@ -127,7 +126,7 @@ const sendToLeafcutter = async (tickets: LabelStudioTicket[]) => {
origin: contributorId,
origin_id: source_id as string,
source_created_at: source_created_at as string,
source_updated_at: source_updated_at as string
source_updated_at: source_updated_at as string,
};
});
@ -145,19 +144,30 @@ const sendToLeafcutter = async (tickets: LabelStudioTicket[]) => {
console.log({ result });
};
const importLeafcutterTask = async (): Promise<void> => {
withDb(async (db: AppDatabase) => {
const { leafcutter: { contributorName } } = await loadConfig();
const {
leafcutter: { contributorName },
} = await loadConfig();
const settingName = `${contributorName}ImportLeafcutterTask`;
const res: any = await db.settings.findByName(settingName);
const startTimestamp = res?.value?.minUpdatedTimestamp ? new Date(res.value.minUpdatedTimestamp as string) : new Date("2023-03-01");
const startTimestamp = res?.value?.minUpdatedTimestamp
? new Date(res.value.minUpdatedTimestamp as string)
: new Date("2023-03-01");
const newLastTimestamp = new Date();
console.log({ contributorName, settingName, res, startTimestamp, newLastTimestamp });
console.log({
contributorName,
settingName,
res,
startTimestamp,
newLastTimestamp,
});
const tickets = await fetchFromLabelStudio(startTimestamp);
console.log({ tickets });
await sendToLeafcutter(tickets);
await db.settings.upsert(settingName, { minUpdatedTimestamp: newLastTimestamp });
await db.settings.upsert(settingName, {
minUpdatedTimestamp: newLastTimestamp,
});
});
};

View file

@ -1,5 +1,5 @@
import Twilio from "twilio";
import config from "@digiresilience/metamigo-config";
import config from "@digiresilience/bridge-config";
import { withDb, AppDatabase } from "../db";
interface VoiceLineDeleteTaskOptions {
@ -9,7 +9,7 @@ interface VoiceLineDeleteTaskOptions {
}
const voiceLineDeleteTask = async (
payload: VoiceLineDeleteTaskOptions
payload: VoiceLineDeleteTaskOptions,
): Promise<void> =>
withDb(async (db: AppDatabase) => {
const { voiceLineId, providerId, providerLineSid } = payload;
@ -19,7 +19,7 @@ const voiceLineDeleteTask = async (
const { accountSid, apiKeySid, apiKeySecret } = provider.credentials;
if (!accountSid || !apiKeySid || !apiKeySecret)
throw new Error(
`twilio provider ${provider.name} does not have credentials`
`twilio provider ${provider.name} does not have credentials`,
);
const client = Twilio(apiKeySid, apiKeySecret, {
@ -30,7 +30,7 @@ const voiceLineDeleteTask = async (
if (
number &&
number.voiceUrl ===
`${config.frontend.url}/api/v1/voice/twilio/record/${voiceLineId}`
`${config.frontend.url}/api/v1/voice/twilio/record/${voiceLineId}`
)
await client.incomingPhoneNumbers(providerLineSid).update({
voiceUrl: "",

View file

@ -1,5 +1,5 @@
import Twilio from "twilio";
import config from "@digiresilience/metamigo-config";
import config from "@digiresilience/bridge-config";
import { withDb, AppDatabase } from "../db";
interface VoiceLineUpdateTaskOptions {
@ -7,7 +7,7 @@ interface VoiceLineUpdateTaskOptions {
}
const voiceLineUpdateTask = async (
payload: VoiceLineUpdateTaskOptions
payload: VoiceLineUpdateTaskOptions,
): Promise<void> =>
withDb(async (db: AppDatabase) => {
const { voiceLineId } = payload;
@ -22,7 +22,7 @@ const voiceLineUpdateTask = async (
const { accountSid, apiKeySid, apiKeySecret } = provider.credentials;
if (!accountSid || !apiKeySid || !apiKeySecret)
throw new Error(
`twilio provider ${provider.name} does not have credentials`
`twilio provider ${provider.name} does not have credentials`,
);
const client = Twilio(apiKeySid, apiKeySecret, {

View file

@ -1,6 +1,6 @@
import * as Worker from "graphile-worker";
import { defState } from "@digiresilience/montar";
import config from "@digiresilience/metamigo-config";
import config from "@digiresilience/bridge-config";
const startWorkerUtils = async (): Promise<Worker.WorkerUtils> => {
const workerUtils = await Worker.makeWorkerUtils({

View file

@ -20,15 +20,15 @@
"@mui/icons-material": "^5",
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5",
"@mui/x-data-grid-pro": "^7.1.1",
"@mui/x-date-pickers-pro": "^7.1.1",
"@opensearch-project/opensearch": "^2.6.0",
"@mui/x-data-grid-pro": "^7.3.0",
"@mui/x-date-pickers-pro": "^7.2.0",
"@opensearch-project/opensearch": "^2.7.0",
"cryptr": "^6.3.0",
"date-fns": "^3.6.0",
"http-proxy-middleware": "^3.0.0",
"leafcutter-ui": "*",
"material-ui-popup-state": "^5.1.0",
"next": "14.1.4",
"next": "14.2.2",
"next-auth": "^4.24.7",
"next-http-proxy-middleware": "^1.2.6",
"opensearch-common": "*",
@ -47,17 +47,17 @@
},
"devDependencies": {
"@babel/core": "^7.24.4",
"@types/node": "^20.12.6",
"@types/react": "18.2.75",
"@types/node": "^20.12.7",
"@types/react": "18.2.79",
"@types/uuid": "^9.0.8",
"babel-loader": "^9.1.3",
"eslint": "^9.0.0",
"eslint-config-next": "^14.1.4",
"eslint": "^8.0.0",
"eslint-config-next": "^14.2.2",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.1",
"typescript": "5.4.4"
"typescript": "5.4.5"
}
}

View file

@ -53,114 +53,115 @@ const MenuItem = ({
}: any) => {
const { roboto } = fonts;
return (<Link href={href} target={target}>
<ListItemButton
sx={{
p: 0,
mb: 1,
bl: iconSize === 0 ? "1px solid white" : "inherit",
}}
selected={selected}
>
{iconSize > 0 ? (
<ListItemIcon
sx={{
color: `white`,
minWidth: 0,
mr: 2,
textAlign: "center",
margin: open ? "0 8 0 0" : "0 auto",
}}
>
<Box
return (
<Link href={href} target={target}>
<ListItemButton
sx={{
p: 0,
mb: 1,
bl: iconSize === 0 ? "1px solid white" : "inherit",
}}
selected={selected}
>
{iconSize > 0 ? (
<ListItemIcon
sx={{
width: iconSize,
height: iconSize,
mr: 0.5,
mt: "-4px",
color: `white`,
minWidth: 0,
mr: 2,
textAlign: "center",
margin: open ? "0 8 0 0" : "0 auto",
}}
>
<Icon />
</Box>
</ListItemIcon>
) : (
<Box
sx={{
width: 30,
height: "28px",
position: "relative",
ml: "9px",
mr: "1px",
}}
>
<Box
sx={{
width: "1px",
height: "56px",
backgroundColor: "white",
position: "absolute",
left: "3px",
top: "-10px",
}}
/>
<Box
sx={{
width: "42px",
height: "42px",
position: "absolute",
top: "-27px",
left: "3px",
border: "solid 1px #fff",
borderColor: "transparent transparent transparent #fff",
borderRadius: "60px",
rotate: "-35deg",
}}
/>
</Box>
)}
{open && (
<ListItemText
inset={inset}
primary={
<Typography
variant="body1"
<Box
sx={{
fontSize: 16,
fontFamily: roboto.style.fontFamily,
fontWeight: "bold",
border: 0,
textAlign: "left",
color: "white",
width: iconSize,
height: iconSize,
mr: 0.5,
mt: "-4px",
}}
>
{name}
</Typography>
}
/>
)}
{badge && badge > 0 ? (
<ListItemSecondaryAction>
<Typography
color="textSecondary"
variant="body1"
className="badge"
<Icon />
</Box>
</ListItemIcon>
) : (
<Box
sx={{
backgroundColor: "#FFB620",
color: "black !important",
borderRadius: 10,
px: 1,
fontSize: 12,
fontWeight: "bold",
width: 30,
height: "28px",
position: "relative",
ml: "9px",
mr: "1px",
}}
>
{badge}
</Typography>
</ListItemSecondaryAction>
) : null}
</ListItemButton>
</Link>
);
}
<Box
sx={{
width: "1px",
height: "56px",
backgroundColor: "white",
position: "absolute",
left: "3px",
top: "-10px",
}}
/>
<Box
sx={{
width: "42px",
height: "42px",
position: "absolute",
top: "-27px",
left: "3px",
border: "solid 1px #fff",
borderColor: "transparent transparent transparent #fff",
borderRadius: "60px",
rotate: "-35deg",
}}
/>
</Box>
)}
{open && (
<ListItemText
inset={inset}
primary={
<Typography
variant="body1"
sx={{
fontSize: 16,
fontFamily: roboto.style.fontFamily,
fontWeight: "bold",
border: 0,
textAlign: "left",
color: "white",
}}
>
{name}
</Typography>
}
/>
)}
{badge && badge > 0 ? (
<ListItemSecondaryAction>
<Typography
color="textSecondary"
variant="body1"
className="badge"
sx={{
backgroundColor: "#FFB620",
color: "black !important",
borderRadius: 10,
px: 1,
fontSize: 12,
fontWeight: "bold",
}}
>
{badge}
</Typography>
</ListItemSecondaryAction>
) : null}
</ListItemButton>
</Link>
);
};
interface SidebarProps {
open: boolean;
@ -577,13 +578,13 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
selected={pathname.endsWith("/admin/zammad")}
open={open}
/>
{false && roles.includes("metamigo") && (
{false && roles.includes("bridge") && (
<MenuItem
name="Metamigo"
href="/admin/metamigo"
name="Bridge"
href="/admin/bridge"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/admin/metamigo")}
selected={pathname.endsWith("/admin/bridge")}
open={open}
/>
)}

View file

@ -4,10 +4,10 @@ const nextConfig = {
experimental: {
missingSuspenseWithCSRBailout: false,
},
transpilePackages: ["leafcutter-ui", "metamigo-ui", "opensearch-common", "ui"],
transpilePackages: ["leafcutter-ui", "bridge-ui", "opensearch-common", "ui"],
publicRuntimeConfig: {
linkURL: process.env.LINK_URL ?? "http://localhost:3000",
metamigoURL: process.env.METAMIGO_URL ?? "http://localhost:8002",
bridgeURL: process.env.BRIDGE_URL ?? "http://localhost:8002",
labelStudioURL: process.env.LABEL_STUDIO_URL ?? "http://localhost:8006",
muiLicenseKey: process.env.MUI_LICENSE_KEY ?? "",
},

View file

@ -18,15 +18,15 @@
"@mui/icons-material": "^5",
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5",
"@mui/x-data-grid-pro": "^7.1.1",
"@mui/x-date-pickers-pro": "^7.1.1",
"@mui/x-data-grid-pro": "^7.3.0",
"@mui/x-date-pickers-pro": "^7.2.0",
"date-fns": "^3.6.0",
"graphql-request": "^6.1.0",
"leafcutter-ui": "*",
"material-ui-popup-state": "^5.1.0",
"metamigo-ui": "*",
"bridge-ui": "*",
"mui-chips-input": "^2.1.4",
"next": "14.1.4",
"next": "14.2.2",
"next-auth": "^4.24.7",
"opensearch-common": "*",
"react": "18.2.0",
@ -42,17 +42,17 @@
},
"devDependencies": {
"@babel/core": "^7.24.4",
"@types/node": "^20.12.6",
"@types/react": "18.2.75",
"@types/node": "^20.12.7",
"@types/react": "18.2.79",
"@types/uuid": "^9.0.8",
"babel-loader": "^9.1.3",
"eslint": "^9.0.0",
"eslint-config-next": "^14.1.4",
"eslint": "^8.0.0",
"eslint-config-next": "^14.2.2",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.1",
"typescript": "5.4.4"
"typescript": "5.4.5"
}
}

View file

@ -1,2 +0,0 @@
@digiresilience:registry=https://gitlab.com/api/v4/packages/npm/
@guardianproject-ops:registry=https://gitlab.com/api/v4/packages/npm/

View file

@ -1,5 +0,0 @@
{
"presets": [
"@digiresilience/babel-preset-metamigo"
]
}