diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index a159a6a..56c85b7 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -8,23 +8,25 @@
*/
import {
- makeStyles,
- Subtitle1,
- Tab,
- TabList,
- Text,
- tokens,
+ Button,
+ makeStyles,
+ Subtitle1,
+ Subtitle2,
+ Text,
+ tokens,
} from '@fluentui/react-components'
import {
- Bot24Regular,
- DataHistogram24Regular,
- DocumentEdit24Regular,
- Flow24Regular,
- Info24Regular,
- Pulse24Regular,
- Settings24Regular,
- Table24Regular,
- Wrench24Regular,
+ Bot24Regular,
+ ChevronLeft24Regular,
+ ChevronRight24Regular,
+ DataHistogram24Regular,
+ DocumentEdit24Regular,
+ Flow24Regular,
+ Info24Regular,
+ Pulse24Regular,
+ Settings24Regular,
+ Table24Regular,
+ Wrench24Regular,
} from '@fluentui/react-icons'
import { useEffect, useMemo, useState } from 'react'
import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
@@ -43,31 +45,174 @@ import SettingsPage from './features/settings/SettingsPage'
import useTabPreferences from './features/settings/useTabPreferences'
import { listWorkbenchAgents } from './services/api'
+const NAV_COLLAPSED_STORAGE_KEY = 'app-nav-collapsed'
+
const useStyles = makeStyles({
app: {
minHeight: '100vh',
backgroundColor: tokens.colorNeutralBackground3,
+ overflowX: 'hidden',
+ display: 'flex',
+ flexDirection: 'column',
},
header: {
backgroundColor: tokens.colorBrandBackground,
color: tokens.colorNeutralForegroundOnBrand,
padding: `${tokens.spacingVerticalL} ${tokens.spacingHorizontalXL}`,
boxShadow: tokens.shadow4,
+ '@media (max-width: 768px)': {
+ padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalL}`,
+ },
+ '@media (max-width: 480px)': {
+ padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
+ },
+ },
+ headerInner: {
+ maxWidth: '1400px',
+ margin: '0 auto',
},
title: {
color: tokens.colorNeutralForegroundOnBrand,
+ overflowWrap: 'anywhere',
},
subtitle: {
color: tokens.colorNeutralForegroundOnBrand,
opacity: 0.9,
marginTop: tokens.spacingVerticalXS,
+ overflowWrap: 'anywhere',
},
- nav: {
+ shell: {
+ display: 'flex',
+ flex: 1,
+ minHeight: 0,
+ },
+ sidebar: {
+ width: '280px',
+ flexShrink: 0,
+ display: 'flex',
+ flexDirection: 'column',
backgroundColor: tokens.colorNeutralBackground1,
+ borderRight: `1px solid ${tokens.colorNeutralStroke1}`,
+ transitionDuration: tokens.durationNormal,
+ transitionProperty: 'width',
+ transitionTimingFunction: tokens.curveEasyEase,
+ minHeight: 0,
+ '@media (max-width: 768px)': {
+ width: '232px',
+ },
+ },
+ sidebarCollapsed: {
+ width: '88px',
+ '@media (max-width: 768px)': {
+ width: '72px',
+ },
+ },
+ sidebarHeader: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ gap: tokens.spacingHorizontalS,
+ padding: `${tokens.spacingVerticalL} ${tokens.spacingHorizontalM}`,
borderBottom: `1px solid ${tokens.colorNeutralStroke1}`,
- padding: `0 ${tokens.spacingHorizontalXL}`,
+ },
+ sidebarTitle: {
+ minWidth: 0,
+ overflow: 'hidden',
+ },
+ collapseButton: {
+ minWidth: '36px',
+ width: '36px',
+ height: '36px',
+ padding: 0,
+ flexShrink: 0,
+ },
+ navList: {
+ display: 'flex',
+ flexDirection: 'column',
+ gap: tokens.spacingVerticalXS,
+ padding: tokens.spacingHorizontalS,
+ overflowY: 'auto',
+ flex: 1,
+ minHeight: 0,
+ },
+ navButton: {
+ width: '100%',
+ display: 'flex',
+ alignItems: 'center',
+ gap: tokens.spacingHorizontalM,
+ border: 'none',
+ borderRadius: tokens.borderRadiusLarge,
+ backgroundColor: 'transparent',
+ color: tokens.colorNeutralForeground2,
+ cursor: 'pointer',
+ padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
+ textAlign: 'left',
+ transitionDuration: tokens.durationNormal,
+ transitionProperty: 'background-color, color',
+ transitionTimingFunction: tokens.curveEasyEase,
+ ':hover': {
+ backgroundColor: tokens.colorNeutralBackground1Hover,
+ color: tokens.colorNeutralForeground1,
+ },
+ },
+ navButtonCollapsed: {
+ justifyContent: 'center',
+ padding: `${tokens.spacingVerticalS} 0`,
+ },
+ navButtonActive: {
+ backgroundColor: tokens.colorBrandBackground2,
+ color: tokens.colorBrandForeground1,
+ boxShadow: `inset 3px 0 0 ${tokens.colorBrandStroke1}`,
+ ':hover': {
+ backgroundColor: tokens.colorBrandBackground2Hover,
+ color: tokens.colorBrandForeground1,
+ },
+ },
+ navIcon: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ flexShrink: 0,
+ },
+ navLabelWrap: {
+ minWidth: 0,
+ display: 'flex',
+ flexDirection: 'column',
+ gap: '2px',
+ },
+ navLabel: {
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ },
+ navPath: {
+ color: tokens.colorNeutralForeground4,
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ },
+ contentArea: {
+ flex: 1,
+ minWidth: 0,
+ minHeight: 0,
+ display: 'flex',
+ flexDirection: 'column',
},
content: {
+ width: '100%',
+ flex: 1,
+ minWidth: 0,
+ minHeight: 0,
+ padding: `${tokens.spacingVerticalL} ${tokens.spacingHorizontalXL}`,
+ '@media (max-width: 768px)': {
+ padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalL}`,
+ },
+ '@media (max-width: 480px)': {
+ padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
+ },
+ },
+ contentInner: {
+ width: '100%',
maxWidth: '1400px',
margin: '0 auto',
},
@@ -77,8 +222,24 @@ export default function App() {
const styles = useStyles()
const location = useLocation()
const navigate = useNavigate()
+ const [isNavCollapsed, setIsNavCollapsed] = useState(false)
const [menuAgents, setMenuAgents] = useState([])
+ useEffect(() => {
+ const storedValue = window.localStorage.getItem(NAV_COLLAPSED_STORAGE_KEY)
+ if (storedValue !== null) {
+ setIsNavCollapsed(storedValue === 'true')
+ return
+ }
+ if (window.innerWidth <= 1024) {
+ setIsNavCollapsed(true)
+ }
+ }, [])
+
+ useEffect(() => {
+ window.localStorage.setItem(NAV_COLLAPSED_STORAGE_KEY, String(isNavCollapsed))
+ }, [isNavCollapsed])
+
useEffect(() => {
listWorkbenchAgents()
.then((data) => {
@@ -136,63 +297,105 @@ export default function App() {
?? allTabs.find((tab) => location.pathname.startsWith(tab.path))?.value
?? 'csvtickets'
+ const mainNavTabs = navTabs.filter((tab) => tab.value !== 'settings')
+
+ const renderNavButton = (tab) => {
+ const isActive = activeTab === tab.value
+ return (
+
+ )
+ }
+
return (
-
-
-
-
- } />
- } />
- } />
- {USECASE_DEMO_DEFINITIONS.map((definition) => (
- }
- />
- ))}
- } />
- } />
- } />
- {menuAgents.map((agent) => (
- }
+
+
+
+
+
+
+
+ } />
+ } />
+ } />
+ {USECASE_DEMO_DEFINITIONS.map((definition) => (
+ }
+ />
+ ))}
+ } />
+ } />
+ } />
+ {menuAgents.map((agent) => (
+ }
+ />
+ ))}
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+
+
)
}
diff --git a/frontend/src/features/agent/AgentChat.jsx b/frontend/src/features/agent/AgentChat.jsx
index b17fdb4..ab6158f 100644
--- a/frontend/src/features/agent/AgentChat.jsx
+++ b/frontend/src/features/agent/AgentChat.jsx
@@ -41,6 +41,12 @@ const useStyles = makeStyles({
height: '100%',
display: 'flex',
flexDirection: 'column',
+ '@media (max-width: 768px)': {
+ padding: tokens.spacingVerticalM,
+ },
+ '@media (max-width: 480px)': {
+ padding: tokens.spacingVerticalS,
+ },
},
card: {
maxWidth: '1200px',
@@ -49,17 +55,27 @@ const useStyles = makeStyles({
display: 'flex',
flexDirection: 'column',
height: 'calc(100vh - 200px)',
+ minHeight: '480px',
+ '@media (max-width: 768px)': {
+ height: 'calc(100vh - 160px)',
+ },
+ '@media (max-width: 480px)': {
+ height: 'calc(100vh - 120px)',
+ minHeight: '420px',
+ },
},
header: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
gap: tokens.spacingHorizontalM,
+ flexWrap: 'wrap',
},
headerControls: {
display: 'flex',
gap: tokens.spacingHorizontalS,
alignItems: 'center',
+ flexWrap: 'wrap',
},
messagesContainer: {
flex: 1,
@@ -69,12 +85,19 @@ const useStyles = makeStyles({
flexDirection: 'column',
gap: tokens.spacingVerticalM,
backgroundColor: tokens.colorNeutralBackground1,
+ '@media (max-width: 480px)': {
+ padding: tokens.spacingVerticalM,
+ },
},
message: {
display: 'flex',
gap: tokens.spacingHorizontalM,
alignItems: 'flex-start',
maxWidth: '85%',
+ '@media (max-width: 640px)': {
+ maxWidth: '100%',
+ gap: tokens.spacingHorizontalS,
+ },
},
userMessage: {
alignSelf: 'flex-end',
@@ -91,6 +114,10 @@ const useStyles = makeStyles({
height: '40px',
borderRadius: tokens.borderRadiusCircular,
flexShrink: 0,
+ '@media (max-width: 480px)': {
+ width: '32px',
+ height: '32px',
+ },
},
userIcon: {
backgroundColor: tokens.colorBrandBackground,
@@ -165,14 +192,27 @@ const useStyles = makeStyles({
display: 'flex',
gap: tokens.spacingHorizontalM,
backgroundColor: tokens.colorNeutralBackground1,
+ '@media (max-width: 640px)': {
+ flexDirection: 'column',
+ padding: tokens.spacingVerticalM,
+ gap: tokens.spacingVerticalS,
+ },
},
inputField: {
flex: 1,
},
+ sendButton: {
+ '@media (max-width: 640px)': {
+ width: '100%',
+ },
+ },
emptyState: {
textAlign: 'center',
padding: tokens.spacingVerticalXXXL,
color: tokens.colorNeutralForeground3,
+ '@media (max-width: 480px)': {
+ padding: tokens.spacingVerticalXL,
+ },
},
errorCard: {
backgroundColor: tokens.colorPaletteRedBackground1,
@@ -386,6 +426,7 @@ export default function AgentChat() {
/>
}
onClick={handleSendMessage}
diff --git a/frontend/src/features/csvtickets/CSVTicketTable.jsx b/frontend/src/features/csvtickets/CSVTicketTable.jsx
index fa3c25c..45f0e35 100644
--- a/frontend/src/features/csvtickets/CSVTicketTable.jsx
+++ b/frontend/src/features/csvtickets/CSVTicketTable.jsx
@@ -46,6 +46,12 @@ import { getCSVTicket, getCSVTicketFields, getCSVTickets, getCSVTicketStats } fr
const useStyles = makeStyles({
container: {
padding: tokens.spacingVerticalL,
+ '@media (max-width: 768px)': {
+ padding: tokens.spacingVerticalM,
+ },
+ '@media (max-width: 480px)': {
+ padding: tokens.spacingVerticalS,
+ },
},
header: {
display: 'flex',
@@ -63,6 +69,10 @@ const useStyles = makeStyles({
},
statCard: {
minWidth: '120px',
+ flex: '1 1 180px',
+ '@media (max-width: 480px)': {
+ flexBasis: '100%',
+ },
},
filters: {
display: 'flex',
@@ -70,15 +80,38 @@ const useStyles = makeStyles({
alignItems: 'center',
flexWrap: 'wrap',
marginBottom: tokens.spacingVerticalM,
+ '@media (max-width: 640px)': {
+ alignItems: 'stretch',
+ gap: tokens.spacingVerticalS,
+ },
+ },
+ filterControl: {
+ minWidth: '180px',
+ flex: '1 1 220px',
+ '@media (max-width: 640px)': {
+ minWidth: 0,
+ width: '100%',
+ flexBasis: '100%',
+ },
+ },
+ resultsText: {
+ marginLeft: 'auto',
+ whiteSpace: 'nowrap',
+ '@media (max-width: 640px)': {
+ marginLeft: 0,
+ whiteSpace: 'normal',
+ },
},
tableWrapper: {
overflowX: 'auto',
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
boxShadow: tokens.shadow4,
+ WebkitOverflowScrolling: 'touch',
},
table: {
- width: '100%',
+ width: 'max-content',
+ minWidth: '100%',
borderCollapse: 'collapse',
fontSize: tokens.fontSizeBase200,
},
@@ -94,6 +127,9 @@ const useStyles = makeStyles({
':hover': {
backgroundColor: tokens.colorNeutralBackground3Hover,
},
+ '@media (max-width: 640px)': {
+ padding: `${tokens.spacingVerticalXS} ${tokens.spacingHorizontalS}`,
+ },
},
thContent: {
display: 'flex',
@@ -107,6 +143,10 @@ const useStyles = makeStyles({
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
+ '@media (max-width: 640px)': {
+ padding: `${tokens.spacingVerticalXS} ${tokens.spacingHorizontalS}`,
+ maxWidth: '220px',
+ },
},
tr: {
':hover': {
@@ -125,10 +165,18 @@ const useStyles = makeStyles({
alignItems: 'center',
padding: tokens.spacingVerticalM,
borderTop: `1px solid ${tokens.colorNeutralStroke1}`,
+ gap: tokens.spacingHorizontalM,
+ flexWrap: 'wrap',
+ '@media (max-width: 640px)': {
+ padding: tokens.spacingVerticalS,
+ },
},
paginationButtons: {
display: 'flex',
gap: tokens.spacingHorizontalS,
+ '@media (max-width: 480px)': {
+ width: '100%',
+ },
},
loading: {
display: 'flex',
@@ -154,6 +202,9 @@ const useStyles = makeStyles({
gridTemplateColumns: '1fr 1fr',
gap: tokens.spacingVerticalS,
marginTop: tokens.spacingVerticalM,
+ '@media (max-width: 640px)': {
+ gridTemplateColumns: '1fr',
+ },
},
detailField: {
display: 'flex',
@@ -481,6 +532,7 @@ export default function CSVTicketTable() {
{
@@ -497,6 +549,7 @@ export default function CSVTicketTable() {
{
@@ -509,7 +562,7 @@ export default function CSVTicketTable() {
-
+
Showing {tickets.length} of {total} tickets
@@ -596,7 +649,7 @@ export default function CSVTicketTable() {
{/* Ticket Detail Modal */}