Remove leafcutter and related packages

This commit is contained in:
Darren Clarke 2025-11-09 12:48:12 +01:00
parent 48165db6a2
commit 3a1063e40e
264 changed files with 1763 additions and 25062 deletions

View file

@ -0,0 +1,13 @@
"use client";
import { OpenSearchWrapper } from "@/app/_components/OpenSearchWrapper";
export function DefaultDashboard() {
// Extract just the URL path from the full dashboard URL
// The env var format is like: app/dashboards?security_tenant=global#/view/...
const defaultUrl =
process.env.NEXT_PUBLIC_OPENSEARCH_DEFAULT_DASHBOARD_URL ||
"app/dashboards#/";
return <OpenSearchWrapper url={defaultUrl} />;
}

View file

@ -1,12 +0,0 @@
"use client";
import { FC } from "react";
import { OpenSearchWrapper } from "@link-stack/leafcutter-ui";
type HomeProps = {
url: string;
};
export const Home: FC<HomeProps> = ({ url }) => (
<OpenSearchWrapper url={url} margin={0} />
);

View file

@ -31,8 +31,6 @@ import Link from "next/link";
import Image from "next/image";
import LinkLogo from "@app/../public/link-logo-small.png";
import { useSession, signOut } from "next-auth/react";
import { getOverviewTicketCountsAction } from "@/app/_actions/overviews";
import { SearchBox } from "./SearchBox";
import { fonts } from "@link-stack/ui";
const openWidth = 270;
@ -188,25 +186,11 @@ export const Sidebar: FC<SidebarProps> = ({
}) => {
const pathname = usePathname();
const { data: session } = useSession();
const [overviewCounts, setOverviewCounts] = useState<any>(null);
const { poppins } = fonts;
const username = session?.user?.name || "";
// @ts-ignore
const roles = session?.user?.roles || [];
useEffect(() => {
const fetchCounts = async () => {
const counts = await getOverviewTicketCountsAction();
setOverviewCounts(counts);
};
fetchCounts();
const interval = setInterval(fetchCounts, 30000);
return () => clearInterval(interval);
}, []);
return (
<Drawer
sx={{ width: open ? openWidth : closedWidth, flexShrink: 0 }}
@ -342,7 +326,6 @@ export const Sidebar: FC<SidebarProps> = ({
}}
/>
</Grid>
<Grid item>{open && <SearchBox />}</Grid>
<Grid
item
container
@ -374,9 +357,6 @@ export const Sidebar: FC<SidebarProps> = ({
fontSize: 16,
},
},
".badge": {
p: { fontSize: 12, color: "black !important" },
},
},
".Mui-selected": {
background: "#444",
@ -387,92 +367,18 @@ export const Sidebar: FC<SidebarProps> = ({
fontSize: 16,
},
},
".badge": {
p: { fontSize: 12, color: "black !important" },
},
},
},
}}
>
{leafcutterEnabled && (
<MenuItem
name="Home"
href="/"
Icon={CottageIcon}
iconSize={20}
selected={pathname.endsWith("/")}
open={open}
/>
)}
<MenuItem
name="Tickets"
href="/overview/recent"
Icon={FeaturedPlayListIcon}
selected={
pathname.startsWith("/overview") ||
pathname.startsWith("/tickets")
}
name="Dashboards"
href="/dashboards"
Icon={InsightsIcon}
iconSize={20}
selected={pathname.startsWith("/dashboards")}
open={open}
/>
<Collapse
in={
open &&
(pathname.startsWith("/overview") ||
pathname.startsWith("/tickets"))
}
timeout="auto"
unmountOnExit
onClick={undefined}
>
<List component="div" disablePadding>
<MenuItem
name="Recent"
href="/overview/recent"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/overview/recent")}
badge={overviewCounts?.recent}
open={open}
/>
<MenuItem
name="Open"
href="/overview/open"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/overview/open")}
badge={overviewCounts?.open}
open={open}
/>
<MenuItem
name="Urgent"
href="/overview/urgent"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/overview/urgent")}
badge={overviewCounts?.urgent}
open={open}
/>
<MenuItem
name="Assigned"
href="/overview/assigned"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/overview/assigned")}
badge={overviewCounts?.assigned}
open={open}
/>
<MenuItem
name="Unassigned"
href="/overview/unassigned"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/overview/unassigned")}
badge={overviewCounts?.unassigned}
open={open}
/>
</List>
</Collapse>
<MenuItem
name="Documentation"
href="/docs"
@ -481,72 +387,6 @@ export const Sidebar: FC<SidebarProps> = ({
selected={pathname.endsWith("/docs")}
open={open}
/>
{roles.includes("admin") && leafcutterEnabled && (
<MenuItem
name="Opensearch"
href="/opensearch"
Icon={InsightsIcon}
iconSize={20}
selected={pathname.startsWith("/opensearch")}
open={open}
/>
)}
{false && leafcutterEnabled && (
<MenuItem
name="Leafcutter"
href="/leafcutter"
Icon={InsightsIcon}
iconSize={20}
selected={false}
open={open}
/>
)}
<Collapse
in={open && pathname.startsWith("/leafcutter")}
timeout="auto"
unmountOnExit
onClick={undefined}
>
<List component="div" disablePadding>
<MenuItem
name="Dashboard"
href="/leafcutter"
iconSize={0}
selected={pathname.endsWith("/leafcutter")}
open={open}
/>
<MenuItem
name="Search and Create"
href="/leafcutter/create"
iconSize={0}
selected={pathname.endsWith("/leafcutter/create")}
open={open}
/>
<MenuItem
name="Trends"
href="/leafcutter/trends"
iconSize={0}
selected={pathname.endsWith("/leafcutter/trends")}
open={open}
/>
<MenuItem
name="FAQ"
href="/leafcutter/faq"
iconSize={0}
selected={pathname.endsWith("/leafcutter/faq")}
open={open}
/>
<MenuItem
name="About"
href="/leafcutter/about"
Icon={InsightsIcon}
iconSize={0}
selected={pathname.endsWith("/leafcutter/about")}
open={open}
/>
</List>
</Collapse>
{roles.includes("admin") && (
<>
<MenuItem
@ -555,6 +395,7 @@ export const Sidebar: FC<SidebarProps> = ({
Icon={SettingsIcon}
iconSize={20}
open={open}
selected={pathname.startsWith("/admin")}
/>
<Collapse
in={open && pathname.startsWith("/admin/")}
@ -564,55 +405,47 @@ export const Sidebar: FC<SidebarProps> = ({
>
<List component="div" disablePadding>
<MenuItem
name="CDR Bridge"
href="/admin/bridge"
selected={pathname.endsWith("/admin/bridge")}
name="WhatsApp"
href="/admin/bridge/whatsapp"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/whatsapp")}
open={open}
/>
<MenuItem
name="Signal"
href="/admin/bridge/signal"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/signal")}
open={open}
/>
<MenuItem
name="Facebook"
href="/admin/bridge/facebook"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/facebook")}
open={open}
/>
<MenuItem
name="Voice"
href="/admin/bridge/voice"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/voice")}
open={open}
/>
<MenuItem
name="Webhooks"
href="/admin/bridge/webhooks"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/webhooks")}
open={open}
/>
<MenuItem
name="OpenSearch"
href="/admin/opensearch"
iconSize={0}
selected={pathname.endsWith("/admin/opensearch")}
open={open}
/>
<Collapse
in={open && pathname.startsWith("/admin/bridge")}
timeout="auto"
unmountOnExit
onClick={undefined}
>
<List component="div" disablePadding>
<MenuItem
name="WhatsApp"
href="/admin/bridge/whatsapp"
depth={1}
selected={pathname.endsWith("/admin/bridge/whatsapp")}
open={open}
/>
<MenuItem
name="Signal"
href="/admin/bridge/signal"
depth={1}
selected={pathname.endsWith("/admin/bridge/signal")}
open={open}
/>
<MenuItem
name="Facebook"
href="/admin/bridge/facebook"
depth={1}
selected={pathname.endsWith("/admin/bridge/facebook")}
open={open}
/>
<MenuItem
name="Voice"
href="/admin/bridge/voice"
depth={1}
selected={pathname.endsWith("/admin/bridge/voice")}
open={open}
/>
<MenuItem
name="Webhooks"
href="/admin/bridge/webhooks"
depth={1}
selected={pathname.endsWith("/admin/bridge/webhooks")}
open={open}
/>
</List>
</Collapse>
</List>
</Collapse>
</>

View file

@ -1,24 +0,0 @@
"use client";
import { FC } from "react";
import { Grid } from "@mui/material";
import Iframe from "react-iframe";
export const LabelStudioWrapper: FC = () => (
<Grid
container
spacing={0}
sx={{ height: "100%", width: "100%" }}
direction="column"
>
<Grid item sx={{ height: "100vh", width: "100%" }}>
<Iframe
id="label-studio"
url={"/label-studio"}
width="100%"
height="100%"
frameBorder={0}
/>
</Grid>
</Grid>
);

View file

@ -1,10 +0,0 @@
import { Metadata } from "next";
import { LabelStudioWrapper } from "./_components/LabelStudioWrapper";
export const metadata: Metadata = {
title: "Label Studio",
};
export default function Page() {
return <LabelStudioWrapper />;
}

View file

@ -0,0 +1,10 @@
import { Metadata } from "next";
import { OpenSearchWrapper } from "@/app/_components/OpenSearchWrapper";
export const metadata: Metadata = {
title: "CDR Link - OpenSearch",
};
export default function Page() {
return <OpenSearchWrapper url="app/home#/" />;
}

View file

@ -1,10 +0,0 @@
import { Metadata } from "next";
import { ZammadWrapper } from "app/(main)/_components/ZammadWrapper";
export const metadata: Metadata = {
title: "Zammad",
};
export default function Page() {
return <ZammadWrapper path="/#manage" hideSidebar={false} />;
}

View file

@ -1,5 +0,0 @@
import { About } from "@link-stack/leafcutter-ui";
export default function Page() {
return <About />;
}

View file

@ -1,10 +0,0 @@
import { getTemplates } from "@link-stack/opensearch-common";
import { Create } from "@link-stack/leafcutter-ui";
export const dynamic = "force-dynamic";
export default async function Page() {
const templates = await getTemplates(100);
return <Create templates={templates} />;
}

View file

@ -1,5 +0,0 @@
import { FAQ } from "@link-stack/leafcutter-ui";
export default function Page() {
return <FAQ />;
}

View file

@ -1,10 +0,0 @@
import { ReactNode } from "react";
import { LeafcutterWrapper } from "@link-stack/leafcutter-ui";
type LayoutProps = {
children: ReactNode;
};
export default function Layout({ children }: LayoutProps) {
return <LeafcutterWrapper>{children}</LeafcutterWrapper>;
}

View file

@ -1,11 +0,0 @@
import { Home, LeafcutterWrapper } from "@link-stack/leafcutter-ui";
export const dynamic = "force-dynamic";
export default async function Page() {
return (
<LeafcutterWrapper>
<Home visualizations={[]} showWelcome={false} />
</LeafcutterWrapper>
);
}

View file

@ -1,7 +0,0 @@
import { Trends } from "@link-stack/leafcutter-ui";
export const dynamic = "force-dynamic";
export default function Page() {
return <Trends visualizations={[]} />;
}

View file

@ -1,5 +0,0 @@
import { OpenSearchWrapper } from "@link-stack/leafcutter-ui";
export default function Page() {
return <OpenSearchWrapper url="/app/visualize#/" margin={50} />;
}

View file

@ -1,139 +0,0 @@
"use client";
import { FC, useState, useEffect, useActionState } from "react";
import { useRouter } from "next/navigation";
import { Grid } from "@mui/material";
import {
Dialog,
Button,
TextField,
Autocomplete,
Select,
} from "@link-stack/ui";
import { createTicketAction } from "app/_actions/tickets";
import { getCustomersAction } from "app/_actions/users";
import { getGroupsAction } from "app/_actions/groups";
interface TicketCreateDialogProps {
open: boolean;
closeDialog: () => void;
}
export const TicketCreateDialog: FC<TicketCreateDialogProps> = ({
open,
closeDialog,
}) => {
const [customers, setCustomers] = useState([]);
const [groups, setGroups] = useState([]);
const initialState = {
messages: [],
errors: [],
values: {
customerId: "",
groupId: "",
ownerId: "",
priorityId: "",
stateId: "",
tags: [],
title: "",
article: {
body: "",
type: "note",
internal: true,
},
},
};
const [formState, formAction] = useActionState(
createTicketAction,
initialState,
);
const [liveFormState, setLiveFormState] = useState(formState);
const updateFormState = (field: string, value: any) => {
const newState = { ...liveFormState };
newState.values[field] = value;
setLiveFormState(newState);
};
useEffect(() => {
const fetchUsers = async () => {
const result = await getCustomersAction();
setCustomers(result);
};
fetchUsers();
}, []);
useEffect(() => {
const fetchGroups = async () => {
const result = await getGroupsAction();
setGroups(result);
};
fetchGroups();
}, []);
const router = useRouter();
useEffect(() => {
if (formState.success) {
closeDialog();
}
}, [formState.success, router]);
return (
<Dialog
title="Create Ticket"
open={open}
onClose={closeDialog}
formAction={formAction}
buttons={
<Grid container justifyContent="space-between">
<Grid item>
<Button
text="Cancel"
kind="secondary"
onClick={() => {
closeDialog();
}}
/>
</Grid>
<Grid item>
<Button text="Save" type="submit" kind="primary" />
</Grid>
</Grid>
}
>
<Grid container direction="column" spacing={3}>
<Grid item>
<Select
name="groupId"
label="Group"
getOptions={() => groups as any}
formState={liveFormState}
updateFormState={updateFormState}
/>
</Grid>
<Grid item>
<Select
name="customerId"
label="Customer"
getOptions={() => customers as any}
formState={liveFormState}
updateFormState={updateFormState}
/>
</Grid>
<Grid item>
<TextField name="title" label="Title" formState={formState} />
</Grid>
<Grid item>
<TextField
name="details"
label="Details"
lines={10}
formState={formState}
/>
</Grid>
</Grid>
</Dialog>
);
};

View file

@ -1,88 +0,0 @@
"use client";
import { FC, useState } from "react";
import { Grid, Box } from "@mui/material";
import { GridColDef } from "@mui/x-data-grid-pro";
import { StyledDataGrid } from "app/(main)/_components/StyledDataGrid";
import { Button, List, typography } from "@link-stack/ui";
import { useRouter } from "next/navigation";
import { TicketCreateDialog } from "./TicketCreateDialog";
interface TicketListProps {
title: string;
tickets: any;
}
export const TicketList: FC<TicketListProps> = ({ title, tickets }) => {
const [dialogOpen, setDialogOpen] = useState(false);
const router = useRouter();
let gridColumns: GridColDef[] = [
{
field: "number",
headerName: "Number",
flex: 1,
},
{
field: "title",
headerName: "Title",
flex: 3,
},
{
field: "customer",
headerName: "Sender",
valueGetter: (value: any) => value?.fullname,
flex: 1,
},
{
field: "createdAt",
headerName: "Created At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (value: any) => new Date(value).toLocaleString(),
flex: 1,
},
{
field: "group",
headerName: "Group",
valueGetter: (value: any) => value?.name,
flex: 1,
},
];
const onRowClick = (id: any) => {
router.push(`/tickets/${id}`);
};
return (
<>
<List
title={title}
rows={tickets}
columns={gridColumns}
onRowClick={onRowClick}
getRowID={(row: any) => {
return row.internalId;
}}
buttons={
<Grid container direction="row-reverse" alignItems="center">
<Grid item>
<Button
onClick={() => setDialogOpen(true)}
text="Create"
color="primary"
/>
</Grid>
</Grid>
}
/>
<TicketCreateDialog
open={dialogOpen}
closeDialog={() => setDialogOpen(false)}
/>
</>
);
};

View file

@ -1,43 +0,0 @@
"use client";
import { FC, useEffect, useState } from "react";
import { redirect } from "next/navigation";
import { getOverviewTicketsAction } from "app/_actions/overviews";
import { TicketList } from "./TicketList";
type ZammadOverviewProps = {
name: string;
};
export const ZammadOverview: FC<ZammadOverviewProps> = ({ name }) => {
const [tickets, setTickets] = useState([]);
if (typeof window !== "undefined") {
useEffect(() => {
const hash = window?.location?.hash;
if (hash) {
const ticketID = hash.replace("#ticket/zoom/", "");
if (ticketID && !isNaN(parseInt(ticketID, 10))) {
redirect(`/tickets/${ticketID}`);
}
}
}, [window?.location?.hash]);
}
useEffect(() => {
const fetchTickets = async () => {
const { tickets } = await getOverviewTicketsAction(name);
setTickets(tickets);
};
fetchTickets();
const interval = setInterval(fetchTickets, 10000);
return () => clearInterval(interval);
}, [name]);
return <TicketList title={name} tickets={tickets} />;
};

View file

@ -1,11 +0,0 @@
"use client";
import { DisplayError } from "app/_components/DisplayError";
type PageProps = {
error: Error;
};
export default function Page({ error }: PageProps) {
return <DisplayError error={error} />;
}

View file

@ -1,36 +0,0 @@
import { Metadata } from "next";
import { ZammadOverview } from "./_components/ZammadOverview";
const getSection = (overview: string) => {
return overview.charAt(0).toUpperCase() + overview.slice(1);
};
type MetadataProps = {
params: Promise<{
overview: string;
}>;
};
export async function generateMetadata({
params,
}: MetadataProps): Promise<Metadata> {
const { overview } = await params;
const section = getSection(overview);
return {
title: `CDR Link - ${section} Tickets`,
};
}
type PageProps = {
params: Promise<{
overview: string;
}>;
};
export default async function Page({ params }: PageProps) {
const { overview } = await params;
const section = getSection(overview);
return <ZammadOverview name={section} />;
}

View file

@ -1,45 +1,10 @@
import { Metadata } from "next";
import { redirect } from "next/navigation";
import { Home } from "./_components/Home";
import { createLogger } from "@link-stack/logger";
const logger = createLogger('link-page');
// import { getServerSession } from "app/_lib/authentication";
// import { Home } from "@link-stack/leafcutter-ui";
// import { getUserVisualizations } from "@link-stack/opensearch-common";
// import { LeafcutterWrapper } from "@link-stack/leafcutter-ui";
import { DefaultDashboard } from "./_components/DefaultDashboard";
export const metadata: Metadata = {
title: "CDR Link - Home",
};
export default async function Page() {
const leafcutterEnabled = process.env.LEAFCUTTER_ENABLED === "true";
const dashboardURL = process.env.LEAFCUTTER_DEFAULT_DASHBOARD_URL;
if (!leafcutterEnabled) {
redirect("/overview/recent");
}
/*
const session = await getServerSession();
const {
user: { email },
}: any = session;
*/
let visualizations = [];
/*
try {
visualizations = await getUserVisualizations(email ?? "none", 20);
} catch (e) {
logger.error({ meta: e.meta }, "Error metadata");
}
return (
<LeafcutterWrapper>
<Home visualizations={visualizations} showWelcome={false} />
</LeafcutterWrapper>
);
*/
return <Home url={dashboardURL} />;
return <DefaultDashboard />;
}

View file

@ -1,10 +0,0 @@
import { Metadata } from "next";
import { ZammadWrapper } from "../../(main)/_components/ZammadWrapper";
export const metadata: Metadata = {
title: "Profile",
};
export default function Page() {
return <ZammadWrapper path="/#profile" hideSidebar={false} />;
}

View file

@ -1,11 +0,0 @@
import { Metadata } from "next";
import { ZammadWrapper } from "../../(main)/_components/ZammadWrapper";
export const metadata: Metadata = {
title: "Reporting",
};
export default function Page() {
return <ZammadWrapper path="#report" />;
}

View file

@ -1,100 +0,0 @@
"use server";
import { executeGraphQL, executeREST } from "app/_lib/zammad";
import { getTicketOverviewCountsQuery } from "app/_graphql/getTicketOverviewCountsQuery";
import { getTicketsByOverviewQuery } from "app/_graphql/getTicketsByOverviewQuery";
import { createLogger } from "@link-stack/logger";
const logger = createLogger('link-overviews');
const overviewLookup = {
Assigned: "My Assigned Tickets",
Open: "Open Tickets",
Urgent: "Escalated Tickets",
Unassigned: "Unassigned & Open Tickets",
Recent: "Recent Tickets",
Pending: "Pending Reached Tickets",
MyPending: "My Pending Reached Tickets",
MySubscribed: "My Subscribed Tickets",
};
export const getOverviewTicketCountsAction = async () => {
try {
const recent = await executeREST({ path: "/api/v1/recent_view" });
const countResult = await executeGraphQL({
query: getTicketOverviewCountsQuery,
});
const overviews = countResult?.ticketOverviews?.edges ?? [];
const counts = overviews.reduce((acc: any, overview: any) => {
const name = overview.node.name;
const key = Object.keys(overviewLookup)
.find((k) => overviewLookup[k] === name)
?.toLowerCase();
if (key) {
acc[key] = overview.node.ticketCount ?? 0;
}
return acc;
}, {});
counts.recent = recent.length;
return counts;
} catch (e) {
logger.error({ error: e }, "Error occurred");
return {};
}
};
export const getOverviewTicketsAction = async (name: string) => {
let tickets = [];
try {
if (name === "Recent") {
const recent = await executeREST({ path: "/api/v1/recent_view" });
const uniqueIDs = new Set(recent.map((rec: any) => rec.o_id));
for (const id of uniqueIDs) {
const tkt = await executeREST({
path: `/api/v1/tickets/${id}`,
});
tickets.push({
...tkt,
internalId: tkt.id,
createdAt: tkt.created_at,
updatedAt: tkt.updated_at,
});
}
} else {
const fullName = overviewLookup[name];
const countResult = await executeGraphQL({
query: getTicketOverviewCountsQuery,
});
const overviewID = countResult?.ticketOverviews?.edges?.find(
(overview: any) => overview.node.name === fullName,
)?.node?.id;
const ticketsResult = await executeGraphQL({
query: getTicketsByOverviewQuery,
variables: { overviewId: overviewID, pageSize: 250 },
});
const edges = ticketsResult?.ticketsByOverview?.edges;
if (edges) {
tickets = edges.map((edge: any) => edge.node);
}
}
const sortedTickets = tickets.sort((a: any, b: any) => {
if (a.internalId < b.internalId) {
return 1;
}
if (a.internalId > b.internalId) {
return -1;
}
return 0;
});
return { tickets: sortedTickets };
} catch (e) {
logger.error({ error: e }, "Error occurred");
return { tickets, message: e.message ?? "" };
}
};

View file

@ -4,11 +4,9 @@ import { FC, PropsWithChildren } from "react";
import { CssBaseline } from "@mui/material";
import { CookiesProvider } from "react-cookie";
import { SessionProvider } from "next-auth/react";
import { I18n } from "react-polyglot";
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFnsV3";
import { LocalizationProvider } from "@mui/x-date-pickers-pro";
import { LicenseInfo } from "@mui/x-license";
import { locales, LeafcutterProvider } from "@link-stack/leafcutter-ui";
import { ZammadLoginProvider } from "./ZammadLoginProvider";
LicenseInfo.setLicenseKey(
@ -16,18 +14,13 @@ LicenseInfo.setLicenseKey(
);
export const MultiProvider: FC<PropsWithChildren> = ({ children }) => {
const messages: any = { en: locales.en, fr: locales.fr };
const locale = "en";
return (
<SessionProvider basePath="/link/api/auth">
<CssBaseline />
<ZammadLoginProvider>
<CookiesProvider>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<I18n locale={locale} messages={messages[locale]}>
<LeafcutterProvider>{children}</LeafcutterProvider>
</I18n>
{children}
</LocalizationProvider>
</CookiesProvider>
</ZammadLoginProvider>

View file

@ -0,0 +1,44 @@
"use client";
import { FC } from "react";
import Iframe from "react-iframe";
import { Box } from "@mui/material";
interface OpenSearchWrapperProps {
url: string;
margin?: number;
}
export const OpenSearchWrapper: FC<OpenSearchWrapperProps> = ({
url,
margin = 50,
}) => (
<Box sx={{ position: "relative", marginTop: "-100px" }}>
<Box
sx={{
width: "100%",
height: "100px",
marginTop: "-20px",
backgroundColor: "white",
zIndex: 100,
position: "relative",
}}
/>
<Box
sx={{
marginTop: `-${margin}px`,
zIndex: 1,
position: "relative",
height: `calc(100vh + ${margin}px)`,
}}
>
<Iframe
id="opensearch"
url={`/link/dashboards/${url}`}
width="100%"
height="100%"
frameBorder={0}
/>
</Box>
</Box>
);

View file

@ -1,60 +0,0 @@
import { gql } from 'graphql-request';
export const getTicketsByOverviewQuery = gql`
query ticketsByOverview($overviewId: ID!, $orderBy: String, $orderDirection: EnumOrderDirection, $cursor: String, $showPriority: Boolean = false, $showUpdatedBy: Boolean = false, $pageSize: Int = 10) {
ticketsByOverview(
overviewId: $overviewId
orderBy: $orderBy
orderDirection: $orderDirection
after: $cursor
first: $pageSize
) {
totalCount
edges {
node {
id
internalId
number
title
createdAt
updatedAt
updatedBy @include(if: $showUpdatedBy) {
id
fullname
}
customer {
id
firstname
lastname
fullname
}
organization {
id
name
}
state {
id
name
stateType {
name
}
}
group {
id
name
}
priority @include(if: $showPriority) {
id
name
uiColor
defaultCreate
}
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}`;

View file

@ -4,8 +4,6 @@ export default function () {
basePath: '/link',
poweredByHeader: false,
transpilePackages: [
'@link-stack/leafcutter-ui',
'@link-stack/opensearch-common',
'@link-stack/ui',
'@link-stack/bridge-common',
'@link-stack/bridge-ui',

View file

@ -18,9 +18,7 @@
"@emotion/styled": "^11.14.1",
"@link-stack/bridge-common": "*",
"@link-stack/bridge-ui": "*",
"@link-stack/leafcutter-ui": "*",
"@link-stack/logger": "*",
"@link-stack/opensearch-common": "*",
"@link-stack/ui": "*",
"@mui/icons-material": "^6",
"@mui/material": "^6",