Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/internal/handler/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func Signup(c echo.Context) error {

// 로컬 모드에서는 회원가입 미지원
return c.JSON(http.StatusServiceUnavailable, map[string]interface{}{
"error": "현재 환경에서는 회원가입을 지원하지 않습니다.",
"error": "Sign-up is not supported in this environment.",
})
}

Expand Down
24 changes: 12 additions & 12 deletions conf/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
services:
mc-infra-connector:
version: 0.9.4
baseurl: http://mciam.onecloudcon.com:1024/spider
baseurl: http://spider_url:1024/spider
auth:
type: basic
username:
password:
mc-iam-manager:
version: 0.2.11
baseurl: http://mciam.onecloudcon.com:5000
baseurl: http://mciam.onecloudcon.com:5006
auth:
type: bearer
mc-infra-manager:
version: 0.12.9
baseurl: http://mciam.onecloudcon.com:1323/tumblebug
baseurl: http://52.79.163.111:1323/tumblebug
auth:
type: basic
username: default
Expand All @@ -28,39 +28,39 @@ services:
type: bearer
mc-observability:
version: main
baseurl: http://mciam.onecloudcon.com:18080
baseurl: http://observability_url:18080
auth:
mc-application-manager:
version: main
baseurl: http://mciam.onecloudcon.com:18084
baseurl: http://localhost:18084
auth:
mc-application-manager-fe:
version: main
baseurl: http://mciam.onecloudcon.com:18084
baseurl: http://application_manager_fe_url:18084
auth:
mc-workflow-manager:
version: main
baseurl: http://mciam.onecloudcon.com:18083
baseurl: http://workflow_url:18083
auth:
mc-workflow-manager-fe:
version: main
baseurl: http://mciam.onecloudcon.com:18083
baseurl: http://workflow_manager_fe_url:18083
auth:
mc-cost-optimizer:
version: main
baseurl: http://mciam.onecloudcon.com:18082
baseurl: http://cost_optimizer_url:18082
auth: null
mc-cost-optimizer-fe:
version: main
baseurl: http://mciam.onecloudcon.com:7780
baseurl: http://cost_optimizer_fe_url:7780
auth: null
mc-data-manager:
version: main:20240923
baseurl: http://mciam.onecloudcon.com:3300
baseurl: http://localhost:3300
auth:
mc-data-manager-fe:
version: main
baseurl: http://mciam.onecloudcon.com:3300
baseurl: http://data_manager_fe_url:3300
auth:
serviceActions:
mc-infra-connector:
Expand Down
2 changes: 1 addition & 1 deletion conf/webconsole_menu_resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ menus:
parentid: organizations
displayname: Approvals
restype: menu
isaction: false
isaction: true
priority: 2
menunumber: 1230

Expand Down
12 changes: 6 additions & 6 deletions front/assets/js/pages/auth/signup.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,22 @@ function validateSignupForm(email, password, firstName, lastName) {

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!email || !emailRegex.test(email)) {
showFieldError("email", "유효한 이메일 주소를 입력해 주세요.");
showFieldError("email", "Please enter a valid email address.");
isValid = false;
}

if (!password || password.length < 8) {
showFieldError("password", "비밀번호는 8자 이상이어야 합니다.");
showFieldError("password", "Password must be at least 8 characters.");
isValid = false;
}

if (!firstName || firstName.length < 1) {
showFieldError("firstName", "이름을 입력해 주세요.");
showFieldError("firstName", "Please enter your first name.");
isValid = false;
}

if (!lastName || lastName.length < 1) {
showFieldError("lastName", "성을 입력해 주세요.");
showFieldError("lastName", "Please enter your last name.");
isValid = false;
}

Expand Down Expand Up @@ -92,11 +92,11 @@ document.addEventListener("DOMContentLoaded", function() {
if (res.data && res.data.success === true) {
showSuccessState(res.data.redirectUrl);
} else {
showError((res.data && res.data.error) || "가입 처리 중 오류가 발생했습니다.");
showError((res.data && res.data.error) || "An error occurred during registration.");
}
} catch (error) {
console.error("Signup error:", error);
showError("가입 처리 중 오류가 발생했습니다.");
showError("An error occurred during registration.");
} finally {
signupBtn.disabled = false;
}
Expand Down
10 changes: 5 additions & 5 deletions front/assets/js/pages/operation/analytics/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* dashboard.js — 커스터마이징 모니터링 대시보드 메인 로직
* dashboard.js — Customizable monitoring Dashboard main logic
*/

import { GridStack } from 'gridstack';
Expand Down Expand Up @@ -133,7 +133,7 @@ $(document).on('change', '#resource-ns-select', async function () {

$(document).on('change', '#resource-mci-select', async function () {
var nsId = $('#resource-ns-select').val(), mciId = $(this).val();
var $vmSel = $('#resource-vm-select').empty().append('<option value="">선택</option>');
var $vmSel = $('#resource-vm-select').empty().append('<option value="">Select</option>');
if (!nsId || !mciId) return;
try {
var mciData = await webconsolejs['common/api/services/mci_api'].getMci(nsId, mciId);
Expand Down Expand Up @@ -170,8 +170,8 @@ function addWidgetToGrid(widgetId, widgetDef, config) {
'<h3 class="card-title" style="font-size:0.85rem;"><i class="' + widgetDef.icon + '" style="color:' + widgetDef.color + '"></i> ' +
widgetDef.name + '<small class="text-muted ms-2">' + (config.vmId || '') + '</small></h3>' +
'<div class="card-actions">' +
'<button class="btn btn-ghost-secondary btn-icon btn-sm widget-config-btn" data-widget-id="' + widgetId + '" title="설정"><i class="ti ti-settings"></i></button>' +
'<button class="btn btn-ghost-danger btn-icon btn-sm widget-remove-btn" data-widget-id="' + widgetId + '" title="삭제"><i class="ti ti-x"></i></button>' +
'<button class="btn btn-ghost-secondary btn-icon btn-sm widget-config-btn" data-widget-id="' + widgetId + '" title="Settings"><i class="ti ti-settings"></i></button>' +
'<button class="btn btn-ghost-danger btn-icon btn-sm widget-remove-btn" data-widget-id="' + widgetId + '" title="Delete"><i class="ti ti-x"></i></button>' +
'</div></div>' +
'<div class="card-body p-2" style="min-height:0;overflow:hidden;"><div id="' + chartId + '" style="width:100%;height:100%;"></div></div>' +
'</div></div></div>';
Expand Down Expand Up @@ -286,7 +286,7 @@ function updateEmptyState() {
function showToast(type, message) {
var bg = type === 'success' ? 'bg-success' : type === 'warning' ? 'bg-warning' : 'bg-danger';
var $t = $('<div class="toast show position-fixed bottom-0 end-0 m-3" role="alert" style="z-index:9999;">' +
'<div class="toast-header ' + bg + ' text-white"><strong class="me-auto">대시보드</strong>' +
'<div class="toast-header ' + bg + ' text-white"><strong class="me-auto">Dashboard</strong>' +
'<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button></div>' +
'<div class="toast-body">' + message + '</div></div>');
$('body').append($t);
Expand Down
40 changes: 20 additions & 20 deletions front/assets/js/pages/operation/manage/importvm.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ document.addEventListener("DOMContentLoaded", function () {
btn.id = 'import-vm-btn';
btn.textContent = 'Import VM';
btn.disabled = !_nsId;
btn.title = _nsId ? 'CSP 미관리 VM 임포트' : '프로젝트를 먼저 선택하세요';
btn.title = _nsId ? 'Import Unmanaged VMs from CSP' : 'Select a project first';
btn.onclick = () => openImportVmModal();
btnList.appendChild(btn);
}
Expand All @@ -32,7 +32,7 @@ document.addEventListener("DOMContentLoaded", function () {

export async function openImportVmModal() {
_nsId = webconsolejs["common/api/services/workspace_api"].getCurrentProject()?.NsId;
if (!_nsId) { alert('프로젝트를 먼저 선택하세요.'); return; }
if (!_nsId) { alert('Select a project first.'); return; }

_currentStep = 1;
_selectedVMs = [];
Expand All @@ -54,7 +54,7 @@ export async function openImportVmModal() {
export async function nextStep() {
if (_currentStep === 1) {
const checked = Array.from(document.querySelectorAll('.import-vm-check:checked'));
if (checked.length === 0) { alert('Import할 VM을 선택하세요.'); return; }
if (checked.length === 0) { alert('Please select VMs to import.'); return; }

const connectionName = document.getElementById('import-vm-connection').value;
_selectedVMs = checked.map(cb => ({
Expand Down Expand Up @@ -93,7 +93,7 @@ function showStep(step) {
});

document.getElementById('import-vm-modal-title').textContent =
['', 'VM Import (1/3 — 대상 VM 선택)', 'VM Import (2/3 — 의존 자원 상태)', 'VM Import (3/3 — Target MCI 설정)'][step];
['', 'VM Import (1/3 — Select Target VM)', 'VM Import (2/3 — Dependent Resource Status)', 'VM Import (3/3 — Configure Target MCI)'][step];

document.getElementById('import-vm-prev-btn').classList.toggle('d-none', step === 1);
document.getElementById('import-vm-next-btn').classList.toggle('d-none', step === 3);
Expand All @@ -104,7 +104,7 @@ function showStep(step) {

export async function loadCspVMs() {
const connectionName = document.getElementById('import-vm-connection').value;
if (!connectionName) { alert('Connection을 선택하세요.'); return; }
if (!connectionName) { alert('Please select a Connection.'); return; }

document.getElementById('import-vm-step1-loading').classList.remove('d-none');
document.getElementById('import-vm-step1-list').classList.add('d-none');
Expand All @@ -113,7 +113,7 @@ export async function loadCspVMs() {
const cspVMs = await importApi().getCspVMs(connectionName);
renderVMTable(cspVMs, connectionName);
} catch (err) {
showToast(TOAST_TYPES.ERROR, 'VM 목록 조회 실패: ' + (err.message || ''));
showToast(TOAST_TYPES.ERROR, 'Failed to load VM list: ' + (err.message || ''));
} finally {
document.getElementById('import-vm-step1-loading').classList.add('d-none');
}
Expand All @@ -136,7 +136,7 @@ function renderVMTable(vms, connectionName) {
<td>${vm.name || vm.id}</td>
<td>${vm.instanceType || '-'}</td>
<td><code>${vm.id || '-'}</code></td>
<td><span class="badge bg-warning-lt">● 미관리</span></td>
<td><span class="badge bg-warning-lt">● Unmanaged</span></td>
`;
tbody.appendChild(tr);
}
Expand All @@ -152,7 +152,7 @@ function renderVMTable(vms, connectionName) {

async function loadDepResources() {
const container = document.getElementById('import-vm-dep-table');
container.innerHTML = '<div class="text-center py-2"><div class="spinner-border spinner-border-sm"></div> 의존 자원 확인 중...</div>';
container.innerHTML = '<div class="text-center py-2"><div class="spinner-border spinner-border-sm"></div> Checking dependent resources...</div>';

try {
const [registeredVNets, registeredSGs, registeredSshKeys] = await Promise.all([
Expand Down Expand Up @@ -192,23 +192,23 @@ async function loadDepResources() {
}

if (rows.length === 0) {
container.innerHTML = '<div class="text-muted">의존 자원 정보를 확인할 수 없습니다. (CSP 조회 결과 미제공)</div>';
container.innerHTML = '<div class="text-muted">Cannot check dependent resource info. (No CSP query result provided)</div>';
} else {
container.innerHTML = `
<table class="table table-sm">
<thead><tr><th>자원 유형</th><th>CSP ID</th><th>상태</th></tr></thead>
<thead><tr><th>Resource Type</th><th>CSP ID</th><th>Status</th></tr></thead>
<tbody>${rows.join('')}</tbody>
</table>`;
}
} catch (err) {
container.innerHTML = `<div class="alert alert-warning">의존 자원 상태 확인 실패. Import는 계속 진행할 수 있습니다.</div>`;
container.innerHTML = `<div class="alert alert-warning">Failed to check dependent resource status. Import can still proceed.</div>`;
}
}

function depRow(type, id, registered) {
const badge = registered
? '<span class="badge bg-success-lt">✓ 이미 등록됨</span>'
: '<span class="badge bg-warning-lt">자동 등록 예정</span>';
? '<span class="badge bg-success-lt">✓ Already Registered</span>'
: '<span class="badge bg-warning-lt">Will be auto-registered</span>';
return `<tr><td>${type}</td><td><code>${id}</code></td><td>${badge}</td></tr>`;
}

Expand All @@ -228,7 +228,7 @@ function capitalize(s) { return s.charAt(0).toUpperCase() + s.slice(1); }

async function loadMciRefList() {
const select = document.getElementById('import-vm-mci-ref');
select.innerHTML = '<option value="">기존 MCI 선택 (이름 참조)</option>';
select.innerHTML = '<option value="">Select existing MCI (for name reference)</option>';
try {
const mciList = await importApi().getMciListSimple(_nsId);
mciList.forEach(mci => {
Expand All @@ -250,7 +250,7 @@ export function toggleMciMode(mode) {

export async function executeImportVMs() {
const mciName = document.getElementById('import-vm-mci-name').value.trim();
if (!mciName) { alert('MCI 이름을 입력하세요.'); return; }
if (!mciName) { alert('Please enter an MCI name.'); return; }

const spinner = document.getElementById('import-vm-spinner');
const btn = document.getElementById('import-vm-execute-btn');
Expand Down Expand Up @@ -281,7 +281,7 @@ export async function executeImportVMs() {

showToast(
failCount > 0 ? TOAST_TYPES.WARNING : TOAST_TYPES.SUCCESS,
`VM ${successCount}개 Import 완료 (MCI: ${mciName})${failCount > 0 ? `, ${failCount}개 실패` : ''}`
`${successCount} VMs imported (MCI: ${mciName})${failCount > 0 ? `, ${failCount} failed` : ''}`
);

bootstrap.Modal.getInstance(document.getElementById('import-vm-modal'))?.hide();
Expand All @@ -293,11 +293,11 @@ export async function executeImportVMs() {
}

} catch (err) {
const errMsg = err.response?.data?.message || err.message || '알 수 없는 오류';
const errMsg = err.response?.data?.message || err.message || 'Unknown error';
if (err.response?.status === 409) {
showToast(TOAST_TYPES.ERROR, `MCI 이름 "${mciName}"이 이미 사용 중입니다. 다른 이름을 입력하세요.`);
showToast(TOAST_TYPES.ERROR, `MCI name "${mciName}" is already in use. Please enter a different name.`);
} else {
showToast(TOAST_TYPES.ERROR, 'VM Import 실패: ' + errMsg);
showToast(TOAST_TYPES.ERROR, 'VM import failed: ' + errMsg);
}
} finally {
spinner.classList.add('d-none');
Expand All @@ -309,7 +309,7 @@ export async function executeImportVMs() {

async function loadConnectionSelect(selectId) {
const select = document.getElementById(selectId);
select.innerHTML = '<option value="">선택하세요</option>';
select.innerHTML = '<option value="">Select</option>';
try {
const result = await webconsolejs["common/api/http"].commonAPIPost("/api/mc-iam-manager/ListCspAccounts", {});
const accounts = result?.data?.responseData?.items || [];
Expand Down
2 changes: 1 addition & 1 deletion front/assets/js/pages/operation/manage/mci.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ export async function getSelectedMciData() {
if (mciResp.status.code != 200) {
webconsolejs["common/utils/toast"].showToast(
webconsolejs["common/utils/toast"].TOAST_TYPES.ERROR,
`MCI 조회 실패: ${mciResp.status.message || window.currentMciId}`
`MCI query failed: ${mciResp.status.message || window.currentMciId}`
);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ async function loadCostOptimizer() {

if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) {
document.getElementById("costIframe").innerHTML =
'<div class="alert alert-warning m-3">Workspace와 Project를 선택해 주세요.</div>';
'<div class="alert alert-warning m-3">Please select a Workspace and Project.</div>';
return;
}

var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-cost-optimizer-fe");
if (!host) {
document.getElementById("costIframe").innerHTML =
'<div class="alert alert-warning m-3">mc-cost-optimizer-fe 서비스 URL을 찾을 수 없습니다.<br>' +
'Settings &gt; Environment &gt; Cloud SPs &gt; Cloud Overview 에서 mc-cost-optimizer-fe URL을 등록해 주세요.</div>';
'<div class="alert alert-warning m-3">mc-cost-optimizer-fe service URL not found.<br>' +
'Please register the mc-cost-optimizer-fe URL in Settings &gt; Environment &gt; Cloud SPs &gt; Cloud Overview.</div>';
return;
}
// IFRAME_TARGET_IS_HOST=true 환경에서 :port 형식으로 오던 값에 browser origin을 붙이던 로직.
Expand Down
6 changes: 3 additions & 3 deletions front/assets/js/pages/operation/plugins/datamanager.iframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ async function loadDataManager() {

if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) {
document.getElementById("targetIframe").innerHTML =
'<div class="alert alert-warning m-3">Workspace와 Project를 선택해 주세요.</div>';
'<div class="alert alert-warning m-3">Please select a Workspace and Project.</div>';
return;
}

var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-data-manager-fe");
if (!host) {
document.getElementById("targetIframe").innerHTML =
'<div class="alert alert-warning m-3">mc-data-manager-fe 서비스 URL을 찾을 수 없습니다.<br>' +
'Settings &gt; Environment에서 mc-data-manager-fe URL을 등록해 주세요.</div>';
'<div class="alert alert-warning m-3">mc-data-manager-fe service URL not found.<br>' +
'Please register the mc-data-manager-fe URL in Settings &gt; Environment.</div>';
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ async function loadSoftwareManager() {

if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) {
document.getElementById("targetIframe-sofrwareCatalog").innerHTML =
'<div class="alert alert-warning m-3">Workspace와 Project를 선택해 주세요.</div>';
'<div class="alert alert-warning m-3">Please select a Workspace and Project.</div>';
return;
}

var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-application-manager-fe");
if (!host) {
document.getElementById("targetIframe-sofrwareCatalog").innerHTML =
'<div class="alert alert-warning m-3">mc-application-manager-fe 서비스 URL을 찾을 수 없습니다.<br>' +
'Settings &gt; Environment에서 mc-application-manager-fe URL을 등록해 주세요.</div>';
'<div class="alert alert-warning m-3">mc-application-manager-fe service URL not found.<br>' +
'Please register the mc-application-manager-fe URL in Settings &gt; Environment.</div>';
return;
}

Expand Down
Loading
Loading