Ticket list updates
This commit is contained in:
parent
6a85c644dc
commit
dce765033d
12 changed files with 397 additions and 133 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
|
import useSWR from "swr";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Grid,
|
Grid,
|
||||||
|
|
@ -19,12 +20,14 @@ import {
|
||||||
Cottage as CottageIcon,
|
Cottage as CottageIcon,
|
||||||
Settings as SettingsIcon,
|
Settings as SettingsIcon,
|
||||||
ExpandCircleDown as ExpandCircleDownIcon,
|
ExpandCircleDown as ExpandCircleDownIcon,
|
||||||
|
Dvr as DvrIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import LinkLogo from "public/link-logo-small.png";
|
import LinkLogo from "public/link-logo-small.png";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession, signOut } from "next-auth/react";
|
||||||
|
import { getTicketOverviewCountsQuery } from "graphql/getTicketOverviewCountsQuery";
|
||||||
|
|
||||||
const openWidth = 270;
|
const openWidth = 270;
|
||||||
const closedWidth = 100;
|
const closedWidth = 100;
|
||||||
|
|
@ -38,8 +41,9 @@ const MenuItem = ({
|
||||||
selected = false,
|
selected = false,
|
||||||
open = true,
|
open = true,
|
||||||
badge,
|
badge,
|
||||||
|
target = "_self",
|
||||||
}: any) => (
|
}: any) => (
|
||||||
<Link href={href}>
|
<Link href={href} target={target}>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
sx={{
|
sx={{
|
||||||
p: 0,
|
p: 0,
|
||||||
|
|
@ -124,7 +128,7 @@ const MenuItem = ({
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{badge && (
|
{badge && badge > 0 ? (
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Typography
|
<Typography
|
||||||
color="textSecondary"
|
color="textSecondary"
|
||||||
|
|
@ -142,7 +146,7 @@ const MenuItem = ({
|
||||||
{badge}
|
{badge}
|
||||||
</Typography>
|
</Typography>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
)}
|
) : null}
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
@ -153,9 +157,29 @@ interface SidebarProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
const { pathname } = useRouter();
|
const router = useRouter();
|
||||||
|
const { pathname } = router;
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
const username = session?.user?.name || "User";
|
const username = session?.user?.name || "User";
|
||||||
|
const { data: overviewData, error: overviewError }: any = useSWR(
|
||||||
|
{
|
||||||
|
document: getTicketOverviewCountsQuery,
|
||||||
|
},
|
||||||
|
{ refreshInterval: 10000 }
|
||||||
|
);
|
||||||
|
const findOverviewCountByID = (id: number) =>
|
||||||
|
overviewData?.ticketOverviews?.edges?.find((overview: any) =>
|
||||||
|
overview.node.id.endsWith(`/${id}`)
|
||||||
|
)?.node?.ticketCount ?? 0;
|
||||||
|
const assignedCount = findOverviewCountByID(1);
|
||||||
|
const urgentCount = findOverviewCountByID(7);
|
||||||
|
const pendingCount = findOverviewCountByID(3);
|
||||||
|
const unassignedCount = findOverviewCountByID(2);
|
||||||
|
console.log({ assignedCount, urgentCount, pendingCount, unassignedCount });
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
signOut({ callbackUrl: "/login" });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
|
|
@ -335,13 +359,12 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Tickets"
|
name="Tickets"
|
||||||
href="/tickets/3"
|
href="/tickets/assigned"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
selected={pathname.startsWith("/tickets")}
|
selected={pathname.startsWith("/tickets")}
|
||||||
iconSize={20}
|
iconSize={20}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
{/*
|
|
||||||
<Collapse
|
<Collapse
|
||||||
in={pathname.startsWith("/tickets")}
|
in={pathname.startsWith("/tickets")}
|
||||||
timeout="auto"
|
timeout="auto"
|
||||||
|
|
@ -355,7 +378,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/assigned")}
|
selected={pathname.endsWith("/tickets/assigned")}
|
||||||
badge={3}
|
badge={assignedCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|
@ -364,7 +387,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/urgent")}
|
selected={pathname.endsWith("/tickets/urgent")}
|
||||||
badge={1}
|
badge={urgentCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|
@ -373,7 +396,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/pending")}
|
selected={pathname.endsWith("/tickets/pending")}
|
||||||
badge={9}
|
badge={pendingCount}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|
@ -381,21 +404,12 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
href="/tickets/unassigned"
|
href="/tickets/unassigned"
|
||||||
Icon={FeaturedPlayListIcon}
|
Icon={FeaturedPlayListIcon}
|
||||||
iconSize={0}
|
iconSize={0}
|
||||||
selected={pathname.endsWith("/tickets/unnassigned")}
|
selected={pathname.endsWith("/tickets/unassigned")}
|
||||||
badge={27}
|
badge={unassignedCount}
|
||||||
open={open}
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
name="New Ticket UI"
|
|
||||||
href="/tickets/3"
|
|
||||||
Icon={SettingsIcon}
|
|
||||||
iconSize={0}
|
|
||||||
selected={pathname.endsWith("/tickets/3")}
|
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
*/ }
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Knowledge Base"
|
name="Knowledge Base"
|
||||||
href="/knowledge"
|
href="/knowledge"
|
||||||
|
|
@ -419,7 +433,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
onClick={undefined}
|
onClick={undefined}
|
||||||
>
|
>
|
||||||
<List component="div" disablePadding>
|
<List component="div" disablePadding>
|
||||||
{/*
|
{/*
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Dashboard"
|
name="Dashboard"
|
||||||
href="/leafcutter"
|
href="/leafcutter"
|
||||||
|
|
@ -510,13 +524,21 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
||||||
/>
|
/>
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
<MenuItem
|
||||||
|
name="Zammad Interface"
|
||||||
|
href="/proxy/zammad"
|
||||||
|
Icon={DvrIcon}
|
||||||
|
iconSize={20}
|
||||||
|
open={open}
|
||||||
|
target="_blank"
|
||||||
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
name="Logout"
|
name="Logout"
|
||||||
href="/logout"
|
href="/logout"
|
||||||
Icon={LogoutIcon}
|
Icon={LogoutIcon}
|
||||||
iconSize={20}
|
iconSize={20}
|
||||||
open={open}
|
open={open}
|
||||||
|
onClick={logout}
|
||||||
/>
|
/>
|
||||||
</List>
|
</List>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
84
apps/link/components/StyledDataGrid.tsx
Normal file
84
apps/link/components/StyledDataGrid.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Box } from "@mui/material";
|
||||||
|
import {
|
||||||
|
DataGridPro,
|
||||||
|
GridColDef,
|
||||||
|
GridColumnVisibilityModel,
|
||||||
|
GridRowSelectionModel,
|
||||||
|
} from "@mui/x-data-grid-pro";
|
||||||
|
import { useCookies } from "react-cookie";
|
||||||
|
|
||||||
|
interface StyledDataGridProps {
|
||||||
|
name: string;
|
||||||
|
columns: GridColDef[];
|
||||||
|
rows: any[];
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
onRowClick?: (row: any) => void;
|
||||||
|
height?: string;
|
||||||
|
selectedRows?: GridRowSelectionModel;
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
setSelectedRows?: (rows: GridRowSelectionModel) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StyledDataGrid: FC<StyledDataGridProps> = ({
|
||||||
|
name,
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
onRowClick,
|
||||||
|
height = "calc(100vh - 20px)",
|
||||||
|
selectedRows,
|
||||||
|
setSelectedRows,
|
||||||
|
}) => {
|
||||||
|
const cookieName = `${name}DataGridColumnState`;
|
||||||
|
const [cookies, setCookie] = useCookies([cookieName]);
|
||||||
|
const handleColumnVisibilityChange = (model: GridColumnVisibilityModel) =>
|
||||||
|
setCookie(cookieName, model, { path: "/" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#ddd",
|
||||||
|
border: 0,
|
||||||
|
width: "100%",
|
||||||
|
height,
|
||||||
|
".MuiDataGrid-row:nth-of-type(1n)": {
|
||||||
|
backgroundColor: "#f3f3f3",
|
||||||
|
},
|
||||||
|
".MuiDataGrid-row:nth-of-type(2n)": {
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
},
|
||||||
|
".MuiDataGrid-columnHeaderTitle": {
|
||||||
|
color: "#333",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: 11,
|
||||||
|
margin: "0 auto",
|
||||||
|
},
|
||||||
|
".MuiDataGrid-columnHeader": {
|
||||||
|
backgroundColor: "#ccc",
|
||||||
|
border: 0,
|
||||||
|
borderBottom: "3px solid #ddd",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DataGridPro
|
||||||
|
rows={rows}
|
||||||
|
columns={columns}
|
||||||
|
density="compact"
|
||||||
|
hideFooter
|
||||||
|
sx={{ height }}
|
||||||
|
rowBuffer={30}
|
||||||
|
checkboxSelection={!!setSelectedRows}
|
||||||
|
onRowSelectionModelChange={setSelectedRows}
|
||||||
|
rowSelectionModel={selectedRows}
|
||||||
|
rowHeight={46}
|
||||||
|
scrollbarSize={0}
|
||||||
|
disableVirtualization
|
||||||
|
columnVisibilityModel={
|
||||||
|
(cookies[cookieName] as GridColumnVisibilityModel) ?? undefined
|
||||||
|
}
|
||||||
|
onColumnVisibilityModelChange={handleColumnVisibilityChange}
|
||||||
|
onRowClick={onRowClick}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
71
apps/link/components/TicketList.tsx
Normal file
71
apps/link/components/TicketList.tsx
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { Grid, Box } from "@mui/material";
|
||||||
|
import { GridColDef } from "@mui/x-data-grid-pro";
|
||||||
|
import { StyledDataGrid } from "./StyledDataGrid";
|
||||||
|
import { typography } from "styles/theme";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
interface TicketListProps {
|
||||||
|
title: string;
|
||||||
|
tickets: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TicketList: FC<TicketListProps> = ({ title, tickets }) => {
|
||||||
|
const router = useRouter();
|
||||||
|
let gridColumns: GridColDef[] = [
|
||||||
|
{
|
||||||
|
field: "number",
|
||||||
|
headerName: "Number",
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "title",
|
||||||
|
headerName: "Title",
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "customer",
|
||||||
|
headerName: "Sender",
|
||||||
|
valueGetter: (params) => params.row?.customer?.fullname,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "group",
|
||||||
|
headerName: "Group",
|
||||||
|
valueGetter: (params) => params.row?.group?.name,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log({ tickets });
|
||||||
|
const rowClick = ({ row }) => {
|
||||||
|
router.push(`/tickets/${row.internalId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ height: "100vh", backgroundColor: "#ddd", p: 3 }}>
|
||||||
|
<Grid container direction="column">
|
||||||
|
<Grid item>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#ddd",
|
||||||
|
px: "8px",
|
||||||
|
pb: "16px",
|
||||||
|
...typography.h4,
|
||||||
|
fontSize: 24,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<StyledDataGrid
|
||||||
|
name={title}
|
||||||
|
columns={gridColumns}
|
||||||
|
rows={tickets}
|
||||||
|
onRowClick={rowClick}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
19
apps/link/graphql/getTicketOverviewCountsQuery.ts
Normal file
19
apps/link/graphql/getTicketOverviewCountsQuery.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { gql } from 'graphql-request';
|
||||||
|
|
||||||
|
export const getTicketOverviewCountsQuery = gql`
|
||||||
|
query ticketOverviewTicketCount {
|
||||||
|
ticketOverviews {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
ticketCount
|
||||||
|
}
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
pageInfo {
|
||||||
|
endCursor
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
60
apps/link/graphql/getTicketsByOverviewQuery.ts
Normal file
60
apps/link/graphql/getTicketsByOverviewQuery.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
@ -5,17 +5,18 @@ const nextConfig = {
|
||||||
linkURL: process.env.LINK_URL,
|
linkURL: process.env.LINK_URL,
|
||||||
leafcutterURL: process.env.LEAFCUTTER_URL,
|
leafcutterURL: process.env.LEAFCUTTER_URL,
|
||||||
metamigoURL: process.env.METAMIGO_URL,
|
metamigoURL: process.env.METAMIGO_URL,
|
||||||
|
muiLicenseKey: process.env.MUI_LICENSE_KEY,
|
||||||
},
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
return {
|
return {
|
||||||
fallback: [
|
fallback: [
|
||||||
{
|
{
|
||||||
source: '/:path*',
|
source: "/:path*",
|
||||||
destination: `/proxy/zammad/:path*`,
|
destination: `/proxy/zammad/:path*`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,10 @@ import "styles/global.css";
|
||||||
import { LicenseInfo } from "@mui/x-data-grid-pro";
|
import { LicenseInfo } from "@mui/x-data-grid-pro";
|
||||||
import { SWRConfig } from "swr";
|
import { SWRConfig } from "swr";
|
||||||
import { GraphQLClient } from "graphql-request";
|
import { GraphQLClient } from "graphql-request";
|
||||||
|
import getConfig from "next/config";
|
||||||
|
|
||||||
LicenseInfo.setLicenseKey(process.env.MUI_LICENSE_KEY);
|
const { publicRuntimeConfig } = getConfig();
|
||||||
|
LicenseInfo.setLicenseKey(publicRuntimeConfig.muiLicenseKey);
|
||||||
|
|
||||||
const clientSideEmotionCache: any = createEmotionCache();
|
const clientSideEmotionCache: any = createEmotionCache();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
import { FC } from "react";
|
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { Grid } from "@mui/material";
|
import useSWR from "swr";
|
||||||
|
import { NextPage } from "next";
|
||||||
import { Layout } from "components/Layout";
|
import { Layout } from "components/Layout";
|
||||||
import { ZammadWrapper } from "components/ZammadWrapper";
|
import { TicketList } from "components/TicketList";
|
||||||
|
import { getTicketsByOverviewQuery } from "graphql/getTicketsByOverviewQuery";
|
||||||
|
|
||||||
const Assigned: FC = () => (
|
const Assigned: NextPage = () => {
|
||||||
|
const { data: ticketData, error: ticketError }: any = useSWR(
|
||||||
|
{
|
||||||
|
document: getTicketsByOverviewQuery,
|
||||||
|
variables: { overviewId: "gid://zammad/Overview/1" },
|
||||||
|
},
|
||||||
|
{ refreshInterval: 10000 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldRender = !ticketError && ticketData;
|
||||||
|
const tickets =
|
||||||
|
ticketData?.ticketsByOverview?.edges.map((edge: any) => edge.node) || [];
|
||||||
|
|
||||||
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Link Shell</title>
|
<title>Link Shell – Assigned Tickets</title>
|
||||||
</Head>
|
</Head>
|
||||||
<Grid
|
{shouldRender && <TicketList title="Assigned" tickets={tickets} />}
|
||||||
container
|
{ticketError && <div>{ticketError.toString()}</div>}
|
||||||
spacing={0}
|
|
||||||
sx={{ height: "100%", width: "100%" }}
|
|
||||||
direction="column"
|
|
||||||
>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
sx={{
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ZammadWrapper path="/#ticket/view/my_assigned" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Assigned;
|
export default Assigned;
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
import { FC } from "react";
|
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { Grid } from "@mui/material";
|
import useSWR from "swr";
|
||||||
|
import { NextPage } from "next";
|
||||||
import { Layout } from "components/Layout";
|
import { Layout } from "components/Layout";
|
||||||
import { ZammadWrapper } from "components/ZammadWrapper";
|
import { TicketList } from "components/TicketList";
|
||||||
|
import { getTicketsByOverviewQuery } from "graphql/getTicketsByOverviewQuery";
|
||||||
|
|
||||||
const Pending: FC = () => (
|
const Pending: NextPage = () => {
|
||||||
|
const { data: ticketData, error: ticketError }: any = useSWR(
|
||||||
|
{
|
||||||
|
document: getTicketsByOverviewQuery,
|
||||||
|
variables: { overviewId: "gid://zammad/Overview/3" },
|
||||||
|
},
|
||||||
|
{ refreshInterval: 10000 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldRender = !ticketError && ticketData;
|
||||||
|
const tickets =
|
||||||
|
ticketData?.ticketsByOverview?.edges.map((edge: any) => edge.node) || [];
|
||||||
|
|
||||||
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Link Shell</title>
|
<title>Link Shell – Assigned Tickets</title>
|
||||||
</Head>
|
</Head>
|
||||||
<Grid
|
{shouldRender && <TicketList title="Pending" tickets={tickets} />}
|
||||||
container
|
{ticketError && <div>{ticketError.toString()}</div>}
|
||||||
spacing={0}
|
|
||||||
sx={{ height: "100%", width: "100%" }}
|
|
||||||
direction="column"
|
|
||||||
>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
sx={{
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ZammadWrapper path="/#ticket/view/my_pending_reached" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Pending;
|
export default Pending;
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
import { FC } from "react";
|
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { Grid } from "@mui/material";
|
import useSWR from "swr";
|
||||||
|
import { NextPage } from "next";
|
||||||
import { Layout } from "components/Layout";
|
import { Layout } from "components/Layout";
|
||||||
import { ZammadWrapper } from "components/ZammadWrapper";
|
import { TicketList } from "components/TicketList";
|
||||||
|
import { getTicketsByOverviewQuery } from "graphql/getTicketsByOverviewQuery";
|
||||||
|
|
||||||
const Unassigned: FC = () => (
|
const Unassigned: NextPage = () => {
|
||||||
|
const { data: ticketData, error: ticketError }: any = useSWR(
|
||||||
|
{
|
||||||
|
document: getTicketsByOverviewQuery,
|
||||||
|
variables: { overviewId: "gid://zammad/Overview/2" },
|
||||||
|
},
|
||||||
|
{ refreshInterval: 10000 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldRender = !ticketError && ticketData;
|
||||||
|
const tickets =
|
||||||
|
ticketData?.ticketsByOverview?.edges.map((edge: any) => edge.node) || [];
|
||||||
|
|
||||||
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Link Shell</title>
|
<title>Link Shell – Assigned Tickets</title>
|
||||||
</Head>
|
</Head>
|
||||||
<Grid
|
{shouldRender && <TicketList title="Unassigned" tickets={tickets} />}
|
||||||
container
|
{ticketError && <div>{ticketError.toString()}</div>}
|
||||||
spacing={0}
|
|
||||||
sx={{ height: "100%", width: "100%" }}
|
|
||||||
direction="column"
|
|
||||||
>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
sx={{
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ZammadWrapper path="/#ticket/view/all_unassigned" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Unassigned;
|
export default Unassigned;
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
import { FC } from "react";
|
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { Grid } from "@mui/material";
|
import useSWR from "swr";
|
||||||
|
import { NextPage } from "next";
|
||||||
import { Layout } from "components/Layout";
|
import { Layout } from "components/Layout";
|
||||||
import { ZammadWrapper } from "components/ZammadWrapper";
|
import { TicketList } from "components/TicketList";
|
||||||
|
import { getTicketsByOverviewQuery } from "graphql/getTicketsByOverviewQuery";
|
||||||
|
|
||||||
const Urgent: FC = () => (
|
const Urgent: NextPage = () => {
|
||||||
|
const { data: ticketData, error: ticketError }: any = useSWR(
|
||||||
|
{
|
||||||
|
document: getTicketsByOverviewQuery,
|
||||||
|
variables: { overviewId: "gid://zammad/Overview/7" },
|
||||||
|
},
|
||||||
|
{ refreshInterval: 10000 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldRender = !ticketError && ticketData;
|
||||||
|
const tickets =
|
||||||
|
ticketData?.ticketsByOverview?.edges.map((edge: any) => edge.node) || [];
|
||||||
|
|
||||||
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Link Shell</title>
|
<title>Link Shell – Urgent Tickets</title>
|
||||||
</Head>
|
</Head>
|
||||||
<Grid
|
{shouldRender && <TicketList title="Urgent" tickets={tickets} />}
|
||||||
container
|
{ticketError && <div>{ticketError.toString()}</div>}
|
||||||
spacing={0}
|
|
||||||
sx={{ height: "100%", width: "100%" }}
|
|
||||||
direction="column"
|
|
||||||
>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
sx={{
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ZammadWrapper path="/#ticket/view/all_escalated" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Urgent;
|
export default Urgent;
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ services:
|
||||||
|
|
||||||
link:
|
link:
|
||||||
container_name: link
|
container_name: link
|
||||||
|
restart: ${RESTART}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./apps/link/Dockerfile
|
dockerfile: ./apps/link/Dockerfile
|
||||||
|
|
@ -223,13 +224,12 @@ services:
|
||||||
- "8003:3000"
|
- "8003:3000"
|
||||||
environment:
|
environment:
|
||||||
ZAMMAD_PROXY_URL: ${ZAMMAD_PROXY_URL}
|
ZAMMAD_PROXY_URL: ${ZAMMAD_PROXY_URL}
|
||||||
ZAMMAD_URL: ${ZAMMAD_URL}
|
|
||||||
ZAMMAD_API_TOKEN: ${ZAMMAD_API_TOKEN}
|
ZAMMAD_API_TOKEN: ${ZAMMAD_API_TOKEN}
|
||||||
ZAMMAD_VIRUAL_HOST: ${ZAMMAD_VIRTUAL_HOST}
|
ZAMMAD_VIRUAL_HOST: ${ZAMMAD_VIRTUAL_HOST}
|
||||||
LINK_URL: ${LINK_URL}
|
LINK_URL: ${LINK_URL}
|
||||||
LEAFCUTTER_URL: http://leafcutter:3000
|
LEAFCUTTER_URL: http://leafcutter:3000
|
||||||
METAMIGO_URL: http://metamigo-frontend:3000
|
METAMIGO_URL: http://metamigo-frontend:3000
|
||||||
ZAMMAD_URL: http://zammad-nginx:8080
|
ZAMMAD_URL: http://localhost:8001
|
||||||
NEXTAUTH_URL: ${LINK_URL}
|
NEXTAUTH_URL: ${LINK_URL}
|
||||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
||||||
NEXTAUTH_AUDIENCE: ${NEXTAUTH_AUDIENCE}
|
NEXTAUTH_AUDIENCE: ${NEXTAUTH_AUDIENCE}
|
||||||
|
|
@ -240,6 +240,7 @@ services:
|
||||||
|
|
||||||
leafcutter:
|
leafcutter:
|
||||||
container_name: leafcutter
|
container_name: leafcutter
|
||||||
|
restart: ${RESTART}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./apps/leafcutter/Dockerfile
|
dockerfile: ./apps/leafcutter/Dockerfile
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue