menubar 위치 이동
This commit is contained in:
@@ -5,6 +5,7 @@ import APITester from './components/APITester';
|
|||||||
import LoadTestManager from './components/LoadTestManager';
|
import LoadTestManager from './components/LoadTestManager';
|
||||||
import {monacoConfig} from '@/config/monaco.js';
|
import {monacoConfig} from '@/config/monaco.js';
|
||||||
import LoginDialog from '@/components/LoginDialog.jsx';
|
import LoginDialog from '@/components/LoginDialog.jsx';
|
||||||
|
import {Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarTrigger} from '@/components/ui/menubar.jsx';
|
||||||
|
|
||||||
window.MonacoEnvironment = monacoConfig;
|
window.MonacoEnvironment = monacoConfig;
|
||||||
|
|
||||||
@@ -18,6 +19,104 @@ const App = ({ options = { type: 'api', contextPath: '/' } }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const menuConfig = [
|
||||||
|
{
|
||||||
|
id: 'response',
|
||||||
|
label: '응답관리',
|
||||||
|
items: [
|
||||||
|
{id: 'response-list', label: '응답목록', action: 'response-list'},
|
||||||
|
{id: 'response-add', label: '응답추가', action: 'response-add'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'request',
|
||||||
|
label: '요청관리',
|
||||||
|
items: [
|
||||||
|
{id: 'collection-add', label: '컬렉션 추가', action: 'collection-add'},
|
||||||
|
{id: 'request-add', label: '요청 추가', action: 'request-add'},
|
||||||
|
{id: 'scenario-add', label: '시나리오 추가', action: 'scenario-add'},
|
||||||
|
{id: 'variables-show', label: '변수 보기', action: 'variables-show'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'queue',
|
||||||
|
label: '큐관리',
|
||||||
|
items: [
|
||||||
|
{id: 'queue-status', label: '큐상태', action: 'queue-status'},
|
||||||
|
{id: 'queue-settings', label: '큐설정', action: 'queue-settings'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'loadtest',
|
||||||
|
label: '부하테스트',
|
||||||
|
items: [
|
||||||
|
{id: 'load-test-new', label: '새 테스트', action: 'load-test-new'},
|
||||||
|
{id: 'load-test-history', label: '테스트 이력', action: 'load-test-history'},
|
||||||
|
{id: 'load-test-reports', label: '결과 리포트', action: 'load-test-reports'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'system',
|
||||||
|
label: '시스템관리',
|
||||||
|
items: [
|
||||||
|
{id: 'system-settings', label: '시스템설정', action: 'system-settings'},
|
||||||
|
{id: 'user-management', label: '사용자관리', action: 'user-management'},
|
||||||
|
{type: 'separator'},
|
||||||
|
{id: 'system-logs', label: '시스템로그', action: 'system-logs'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'account',
|
||||||
|
label: '계정',
|
||||||
|
items: [
|
||||||
|
{id: 'change-password', label: '비밀번호변경', action: 'change-password'},
|
||||||
|
{type: 'separator'},
|
||||||
|
{id: 'logout', label: '로그아웃', action: 'logout'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const MenuItem = ({item, onMenuClick}) => {
|
||||||
|
if (item.type === 'separator') {
|
||||||
|
return <MenubarSeparator/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenubarItem onClick={() => onMenuClick(item.action)}>
|
||||||
|
{item.label}
|
||||||
|
</MenubarItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClick = async (action) => {
|
||||||
|
// Handle menu item clicks
|
||||||
|
console.log('Menu action:', action);
|
||||||
|
switch (action) {
|
||||||
|
case 'request-add':
|
||||||
|
setShowAddApi(true);
|
||||||
|
break;
|
||||||
|
case 'collection-add':
|
||||||
|
setShowAddCollection(true);
|
||||||
|
break;
|
||||||
|
case 'scenario-add':
|
||||||
|
setShowAddScenario(true);
|
||||||
|
break;
|
||||||
|
case 'variables-show':
|
||||||
|
setShowVariableModal(true);
|
||||||
|
break;
|
||||||
|
case 'logout':
|
||||||
|
const success = await handleLogout();
|
||||||
|
if (success) {
|
||||||
|
window.location.href = "/actionLogout.do";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'change-password':
|
||||||
|
// Handle password change
|
||||||
|
break;
|
||||||
|
// Add other cases as needed
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const AppContent = ({ options, showLogin, setShowLogin }) => {
|
const AppContent = ({ options, showLogin, setShowLogin }) => {
|
||||||
const { isAuthenticated, setIsAuthenticated } = useAPI();
|
const { isAuthenticated, setIsAuthenticated } = useAPI();
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
@@ -59,6 +158,35 @@ const AppContent = ({ options, showLogin, setShowLogin }) => {
|
|||||||
return (
|
return (
|
||||||
<LoadTestProvider contextPath={options.contextPath}>
|
<LoadTestProvider contextPath={options.contextPath}>
|
||||||
<div className="flex flex-col h-screen bg-background">
|
<div className="flex flex-col h-screen bg-background">
|
||||||
|
<div className="fixed top-0 left-0 right-0 z-50 bg-background border-b">
|
||||||
|
<div className="flex items-center h-14">
|
||||||
|
<div className="px-4 py-2 border-r h-full flex items-center">
|
||||||
|
<img
|
||||||
|
src="/img/logo.png"
|
||||||
|
alt="testmaster"
|
||||||
|
className="h-8 w-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Menubar className="border-none flex-1">
|
||||||
|
{menuConfig.map((menu) => (
|
||||||
|
<MenubarMenu key={menu.id}>
|
||||||
|
<MenubarTrigger className="font-bold">
|
||||||
|
{menu.label}
|
||||||
|
</MenubarTrigger>
|
||||||
|
<MenubarContent>
|
||||||
|
{menu.items.map((item, index) => (
|
||||||
|
<MenuItem
|
||||||
|
key={item.id || `separator-${index}`}
|
||||||
|
item={item}
|
||||||
|
onMenuClick={handleMenuClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</MenubarContent>
|
||||||
|
</MenubarMenu>
|
||||||
|
))}
|
||||||
|
</Menubar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{options.type === 'api' ? (
|
{options.type === 'api' ? (
|
||||||
<APITester />
|
<APITester />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarTrigger} from '@/components/ui/menubar';
|
|
||||||
import MainContentArea from '@/components/MainContentArea.jsx';
|
import MainContentArea from '@/components/MainContentArea.jsx';
|
||||||
import {useAPI} from '@/providers/APIProvider.jsx';
|
import {useAPI} from '@/providers/APIProvider.jsx';
|
||||||
import AddCollectionDialog from '@/components/api-tester/AddCollectionDialog.jsx';
|
import AddCollectionDialog from '@/components/api-tester/AddCollectionDialog.jsx';
|
||||||
@@ -8,75 +7,6 @@ import AddScenarioDialog from '@/components/api-tester/AddScenarioDialog.jsx';
|
|||||||
import {useLoadTest} from '@/providers/LoadTestProvider.jsx';
|
import {useLoadTest} from '@/providers/LoadTestProvider.jsx';
|
||||||
import VariableModal from '@/components/api-tester/VariableModal.jsx';
|
import VariableModal from '@/components/api-tester/VariableModal.jsx';
|
||||||
|
|
||||||
const menuConfig = [
|
|
||||||
{
|
|
||||||
id: 'response',
|
|
||||||
label: '응답관리',
|
|
||||||
items: [
|
|
||||||
{id: 'response-list', label: '응답목록', action: 'response-list'},
|
|
||||||
{id: 'response-add', label: '응답추가', action: 'response-add'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'request',
|
|
||||||
label: '요청관리',
|
|
||||||
items: [
|
|
||||||
{id: 'collection-add', label: '컬렉션 추가', action: 'collection-add'},
|
|
||||||
{id: 'request-add', label: '요청 추가', action: 'request-add'},
|
|
||||||
{id: 'scenario-add', label: '시나리오 추가', action: 'scenario-add'},
|
|
||||||
{id: 'variables-show', label: '변수 보기', action: 'variables-show'},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'queue',
|
|
||||||
label: '큐관리',
|
|
||||||
items: [
|
|
||||||
{id: 'queue-status', label: '큐상태', action: 'queue-status'},
|
|
||||||
{id: 'queue-settings', label: '큐설정', action: 'queue-settings'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'loadtest',
|
|
||||||
label: '부하테스트',
|
|
||||||
items: [
|
|
||||||
{id: 'load-test-new', label: '새 테스트', action: 'load-test-new'},
|
|
||||||
{id: 'load-test-history', label: '테스트 이력', action: 'load-test-history'},
|
|
||||||
{id: 'load-test-reports', label: '결과 리포트', action: 'load-test-reports'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'system',
|
|
||||||
label: '시스템관리',
|
|
||||||
items: [
|
|
||||||
{id: 'system-settings', label: '시스템설정', action: 'system-settings'},
|
|
||||||
{id: 'user-management', label: '사용자관리', action: 'user-management'},
|
|
||||||
{type: 'separator'},
|
|
||||||
{id: 'system-logs', label: '시스템로그', action: 'system-logs'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'account',
|
|
||||||
label: '계정',
|
|
||||||
items: [
|
|
||||||
{id: 'change-password', label: '비밀번호변경', action: 'change-password'},
|
|
||||||
{type: 'separator'},
|
|
||||||
{id: 'logout', label: '로그아웃', action: 'logout'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const MenuItem = ({item, onMenuClick}) => {
|
|
||||||
if (item.type === 'separator') {
|
|
||||||
return <MenubarSeparator/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenubarItem onClick={() => onMenuClick(item.action)}>
|
|
||||||
{item.label}
|
|
||||||
</MenubarItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const APITester = () => {
|
const APITester = () => {
|
||||||
// API 모드와 시나리오 모드 상태를 관리
|
// API 모드와 시나리오 모드 상태를 관리
|
||||||
const [isApiMode, setIsApiMode] = useState(true);
|
const [isApiMode, setIsApiMode] = useState(true);
|
||||||
@@ -120,68 +50,8 @@ const APITester = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleMenuClick = async (action) => {
|
|
||||||
// Handle menu item clicks
|
|
||||||
console.log('Menu action:', action);
|
|
||||||
switch (action) {
|
|
||||||
case 'request-add':
|
|
||||||
setShowAddApi(true);
|
|
||||||
break;
|
|
||||||
case 'collection-add':
|
|
||||||
setShowAddCollection(true);
|
|
||||||
break;
|
|
||||||
case 'scenario-add':
|
|
||||||
setShowAddScenario(true);
|
|
||||||
break;
|
|
||||||
case 'variables-show':
|
|
||||||
setShowVariableModal(true);
|
|
||||||
break;
|
|
||||||
case 'logout':
|
|
||||||
const success = await handleLogout();
|
|
||||||
if (success) {
|
|
||||||
window.location.href = "/actionLogout.do";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'change-password':
|
|
||||||
// Handle password change
|
|
||||||
break;
|
|
||||||
// Add other cases as needed
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-screen">
|
<div className="flex flex-col h-screen">
|
||||||
{/* Fixed Menubar */}
|
|
||||||
<div className="fixed top-0 left-0 right-0 z-50 bg-background border-b">
|
|
||||||
<div className="flex items-center h-14">
|
|
||||||
<div className="px-4 py-2 border-r h-full flex items-center">
|
|
||||||
<img
|
|
||||||
src="/img/logo.png"
|
|
||||||
alt="testmaster"
|
|
||||||
className="h-8 w-auto"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Menubar className="border-none flex-1">
|
|
||||||
{menuConfig.map((menu) => (
|
|
||||||
<MenubarMenu key={menu.id}>
|
|
||||||
<MenubarTrigger className="font-bold">
|
|
||||||
{menu.label}
|
|
||||||
</MenubarTrigger>
|
|
||||||
<MenubarContent>
|
|
||||||
{menu.items.map((item, index) => (
|
|
||||||
<MenuItem
|
|
||||||
key={item.id || `separator-${index}`}
|
|
||||||
item={item}
|
|
||||||
onMenuClick={handleMenuClick}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</MenubarContent>
|
|
||||||
</MenubarMenu>
|
|
||||||
))}
|
|
||||||
</Menubar>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Main content area with top padding for menubar */}
|
{/* Main content area with top padding for menubar */}
|
||||||
<div className="flex-1 pt-14">
|
<div className="flex-1 pt-14">
|
||||||
|
|||||||
@@ -19,11 +19,10 @@ const MainContentArea = ({isApiMode, toggleMode}) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("keydown", handleKeyDown);
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||||
}, [toggleMode]);
|
}, [toggleMode]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-[calc(100vh-57px)] w-full overflow-hidden">
|
<div className="h-[calc(100vh-57px)] w-full overflow-hidden">
|
||||||
{isApiMode ? (
|
{isApiMode ? (
|
||||||
@@ -107,7 +106,7 @@ const APIMode = ({
|
|||||||
collectionName: collection.name,
|
collectionName: collection.name,
|
||||||
server: api.server || null,
|
server: api.server || null,
|
||||||
description: api.description || '',
|
description: api.description || '',
|
||||||
layout: api.layout || {},
|
layout: api.layout || {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const existingIndex = apiRequests.findIndex(
|
const existingIndex = apiRequests.findIndex(
|
||||||
@@ -132,35 +131,35 @@ const APIMode = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarProvider cookieName="sidebar-right:state" shortcut="/">
|
<SidebarProvider cookieName="sidebar-right:state" shortcut="/">
|
||||||
<div className="api-mode flex flex-1 h-[calc(100vh-57px)]">
|
<div className="api-mode flex flex-1 h-[calc(100vh-57px)]">
|
||||||
<div className="navigation-sidebar min-w-[0px] border-r bg-gray-100">
|
<div className="navigation-sidebar min-w-[0px] border-r bg-gray-100">
|
||||||
<APINavigation
|
<APINavigation
|
||||||
contextPath="/"
|
contextPath="/"
|
||||||
collections={collections} // Pass collections to APINavigation
|
collections={collections} // Pass collections to APINavigation
|
||||||
side="left"
|
side="left"
|
||||||
onApiSelect={handleOpenApi}
|
onApiSelect={handleOpenApi}
|
||||||
onNewCollection={() => {
|
onNewCollection={() => {
|
||||||
// Handle new collection creation
|
// Handle new collection creation
|
||||||
}}
|
}}
|
||||||
isApiMode={isApiMode}
|
isApiMode={isApiMode}
|
||||||
onToggleMode={onToggleMode}
|
onToggleMode={onToggleMode}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="editor flex-1 h-[calc(100vh-57px)] overflow-hidden">
|
||||||
|
{apiRequests.length === 0 ? (
|
||||||
|
renderFallback() // Render fallback when no tabs exist
|
||||||
|
) : (
|
||||||
|
<APITabs
|
||||||
|
apiRequests={apiRequests}
|
||||||
|
currentIndex={currentIndex}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onCloseTab={handleCloseTab}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="editor flex-1 h-[calc(100vh-57px)] overflow-hidden">
|
</SidebarProvider>
|
||||||
{apiRequests.length === 0 ? (
|
|
||||||
renderFallback() // Render fallback when no tabs exist
|
|
||||||
) : (
|
|
||||||
<APITabs
|
|
||||||
apiRequests={apiRequests}
|
|
||||||
currentIndex={currentIndex}
|
|
||||||
onTabChange={handleTabChange}
|
|
||||||
onCloseTab={handleCloseTab}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SidebarProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user