feat: expand live chat and work server tools

This commit is contained in:
2026-04-30 11:40:02 +09:00
parent 42ae640470
commit 2df0ba30cb
112 changed files with 15241 additions and 996 deletions

View File

@@ -88,6 +88,7 @@ function parseRoute(pathname: string): {
first === 'schedule' ||
first === 'history' ||
first === 'automation-type' ||
first === 'automation-context' ||
first === 'server-command')
) {
return {
@@ -155,8 +156,16 @@ function getIsMobileViewport() {
return window.matchMedia('(max-width: 768px)').matches;
}
function resolveSidebarCollapsedForViewport(isMobileViewport: boolean, topMenu: TopMenuKey) {
if (!isMobileViewport) {
function getIsSidebarOverlayViewport(topMenu: TopMenuKey) {
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
return false;
}
return window.matchMedia(topMenu === 'chat' ? '(max-width: 1180px)' : '(max-width: 768px)').matches;
}
function resolveSidebarCollapsedForViewport(isSidebarOverlayViewport: boolean, topMenu: TopMenuKey) {
if (!isSidebarOverlayViewport) {
return false;
}
@@ -208,7 +217,10 @@ export function MainLayout() {
const routeState = useMemo(() => parseRoute(location.pathname), [location.pathname]);
const [isMobileViewport, setIsMobileViewport] = useState(() => getIsMobileViewport());
const [sidebarCollapsed, setSidebarCollapsed] = useState(() =>
resolveSidebarCollapsedForViewport(getIsMobileViewport(), routeState.topMenu),
resolveSidebarCollapsedForViewport(getIsSidebarOverlayViewport(routeState.topMenu), routeState.topMenu),
);
const [isSidebarOverlayViewport, setIsSidebarOverlayViewport] = useState(() =>
getIsSidebarOverlayViewport(routeState.topMenu),
);
const [contentExpanded, setContentExpanded] = useState(false);
const [sidebarOpenKeys, setSidebarOpenKeys] = useState<string[]>(
@@ -218,7 +230,7 @@ export function MainLayout() {
'working' | 'release-pending-main' | 'automation-failed' | null
>(routeState.planMenu === 'release' ? 'release-pending-main' : null);
const [planQuickFilterRequestKey, setPlanQuickFilterRequestKey] = useState(routeState.planMenu === 'release' ? 1 : 0);
const { componentSampleEntries, widgetSampleEntries, componentSamples, widgetSamples, docsDocuments, savedLayouts, setSavedLayouts, docFolders } = layoutData;
const { componentSampleEntries, widgetSampleEntries, componentSamples, widgetSamples, docsDocuments, savedLayouts, savedLayoutsReady, setSavedLayouts, docFolders } = layoutData;
const { chatUnreadCount } = useUnreadCounts();
useEffect(() => {
@@ -240,8 +252,22 @@ export function MainLayout() {
}, []);
useEffect(() => {
setSidebarCollapsed(resolveSidebarCollapsedForViewport(isMobileViewport, routeState.topMenu));
}, [isMobileViewport, routeState.topMenu]);
const mediaQuery = window.matchMedia(routeState.topMenu === 'chat' ? '(max-width: 1180px)' : '(max-width: 768px)');
const updateViewport = () => {
setIsSidebarOverlayViewport(mediaQuery.matches);
};
updateViewport();
mediaQuery.addEventListener('change', updateViewport);
return () => {
mediaQuery.removeEventListener('change', updateViewport);
};
}, [routeState.topMenu]);
useEffect(() => {
setSidebarCollapsed(resolveSidebarCollapsedForViewport(isSidebarOverlayViewport, routeState.topMenu));
}, [isSidebarOverlayViewport, routeState.topMenu]);
useEffect(() => {
setSidebarOpenKeys(resolveSidebarOpenKeys(routeState.topMenu, hasAccess, routeState.planMenu, routeState.chatMenu));
@@ -256,10 +282,10 @@ export function MainLayout() {
useEffect(() => {
const savedLayoutId = resolveSavedLayoutIdFromMenuKey(routeState.playMenu);
if (savedLayoutId && !savedLayouts.some((record) => record.id === savedLayoutId)) {
if (savedLayoutId && savedLayoutsReady && !savedLayouts.some((record) => record.id === savedLayoutId)) {
navigate(buildPlayPath('layout'), { replace: true });
}
}, [navigate, routeState.playMenu, savedLayouts]);
}, [navigate, routeState.playMenu, savedLayouts, savedLayoutsReady]);
useEffect(() => {
if (!isRestrictedTopMenu(routeState.topMenu, hasAccess)) {
@@ -407,6 +433,7 @@ export function MainLayout() {
componentSamples,
widgetSamples,
savedLayouts,
savedLayoutsReady,
setSavedLayouts,
searchOptions,
}}
@@ -427,21 +454,21 @@ export function MainLayout() {
}}
onChangeTopMenu={(menu) => {
navigate(resolveTopMenuPath(menu, currentDocsFolder));
setSidebarCollapsed(resolveSidebarCollapsedForViewport(isMobileViewport, menu));
setSidebarCollapsed(resolveSidebarCollapsedForViewport(getIsSidebarOverlayViewport(menu), menu));
}}
onOpenPlanQuickFilter={(filter) => {
const targetPlanMenu = resolvePlanQuickFilterMenu(filter);
setActivePlanQuickFilter(filter);
setPlanQuickFilterRequestKey((previous) => previous + 1);
navigate(buildPlansPath(targetPlanMenu));
setSidebarCollapsed(isMobileViewport);
setSidebarCollapsed(resolveSidebarCollapsedForViewport(getIsSidebarOverlayViewport('plans'), 'plans'));
scrollToElement(PLAN_MENU_ANCHOR_IDS[targetPlanMenu] ?? 'plan-menu-all');
}}
/>
)}
<Layout>
{contentExpanded || (isMobileViewport && sidebarCollapsed) ? null : (
{contentExpanded || (isSidebarOverlayViewport && sidebarCollapsed) ? null : (
<MainSidebar
activeTopMenu={routeState.topMenu}
hasAccess={hasAccess}
@@ -461,13 +488,13 @@ export function MainLayout() {
onOpenKeysChange={setSidebarOpenKeys}
onSelectApiMenu={(key) => {
navigate(buildApisPath(key as ApiSectionKey));
if (isMobileViewport) {
if (isSidebarOverlayViewport) {
setSidebarCollapsed(true);
}
}}
onSelectDocsMenu={(key) => {
navigate(buildDocsPath(key));
if (isMobileViewport) {
if (isSidebarOverlayViewport) {
setSidebarCollapsed(true);
}
}}
@@ -475,20 +502,20 @@ export function MainLayout() {
setActivePlanQuickFilter(key === 'release' ? 'release-pending-main' : null);
setPlanQuickFilterRequestKey((previous) => previous + 1);
navigate(buildPlansPath(key));
if (isMobileViewport) {
if (isSidebarOverlayViewport) {
setSidebarCollapsed(true);
}
}}
onSelectChatMenu={(key) => {
navigate(buildChatPath(key));
if (isMobileViewport) {
if (isSidebarOverlayViewport) {
setSidebarCollapsed(true);
}
}}
onSelectPlayMenu={(key) => {
const savedLayoutId = resolveSavedLayoutIdFromMenuKey(key);
navigate(savedLayoutId ? buildSavedLayoutPath(savedLayoutId) : buildPlayPath(key as 'layout'));
if (isMobileViewport) {
if (isSidebarOverlayViewport) {
setSidebarCollapsed(true);
}
}}
@@ -498,7 +525,7 @@ export function MainLayout() {
/>
)}
{isMobileViewport && !sidebarCollapsed ? null : (
{isSidebarOverlayViewport && !sidebarCollapsed ? null : (
<MainContent contentExpanded={contentExpanded} onToggleContentExpanded={() => setContentExpanded((previous) => !previous)}>
<Outlet />
</MainContent>