@@ -90,11 +90,11 @@
diff --git a/apps/ui/html/workspace-setup.html b/apps/ui/html/workspace-setup.html
index dc53806..522dad8 100644
--- a/apps/ui/html/workspace-setup.html
+++ b/apps/ui/html/workspace-setup.html
@@ -23,7 +23,7 @@
-
+
diff --git a/apps/ui/index.html b/apps/ui/index.html
index 5428888..edc156b 100644
--- a/apps/ui/index.html
+++ b/apps/ui/index.html
@@ -21,7 +21,7 @@
-
+
Crank
@@ -37,7 +37,7 @@
Your workspaces
@@ -79,7 +79,7 @@
Operator
Admin · acme-workspace
-
+
Settings
@@ -95,11 +95,11 @@
diff --git a/apps/ui/js/auth.js b/apps/ui/js/auth.js
index 5f94034..ca4bb46 100644
--- a/apps/ui/js/auth.js
+++ b/apps/ui/js/auth.js
@@ -22,11 +22,11 @@
}
function loginUrl() {
- return (window.APP_BASE || '') + 'html/login.html';
+ return (window.CrankRoutes && window.CrankRoutes.login) || '/login';
}
function homeUrl() {
- return (window.APP_BASE || '') + 'index.html';
+ return (window.CrankRoutes && window.CrankRoutes.home) || '/';
}
function clearUserMirror() {
diff --git a/apps/ui/js/catalog.js b/apps/ui/js/catalog.js
index d4c6f16..f0791f4 100644
--- a/apps/ui/js/catalog.js
+++ b/apps/ui/js/catalog.js
@@ -356,7 +356,8 @@ document.addEventListener('alpine:init', function() {
},
editOperation(operation) {
- window.location.href = (window.APP_BASE || '') + 'html/wizard/?mode=edit&operationId=' + encodeURIComponent(operation.id);
+ window.location.href = ((window.CrankRoutes && window.CrankRoutes.wizard) || '/wizard/')
+ + '?mode=edit&operationId=' + encodeURIComponent(operation.id);
},
async deleteOperation(id) {
@@ -428,7 +429,7 @@ document.addEventListener('alpine:init', function() {
},
handleNewOperation() {
- window.location.href = (window.APP_BASE || '') + 'html/wizard/';
+ window.location.href = (window.CrankRoutes && window.CrankRoutes.wizard) || '/wizard/';
},
handleLogout() {
diff --git a/apps/ui/js/config.js b/apps/ui/js/config.js
index 6021737..699747c 100644
--- a/apps/ui/js/config.js
+++ b/apps/ui/js/config.js
@@ -1,20 +1,15 @@
-/**
- * config.js — auto-detects base paths based on current page location.
- * Must be loaded before workspace.js and other navigation-using scripts.
- */
(function() {
- var p = window.location.pathname;
- // html/wizard/ is two levels deep from root
- if (/\/html\/wizard\//.test(p)) {
- window.APP_BASE = '../../';
- window.DATA_URL = '../../data/';
- // html/*.html is one level deep from root
- } else if (/\/html\//.test(p)) {
- window.APP_BASE = '../';
- window.DATA_URL = '../data/';
- // root level (index.html)
- } else {
- window.APP_BASE = '';
- window.DATA_URL = 'data/';
- }
+ window.APP_BASE = '/';
+ window.DATA_URL = '/data/';
+ window.CrankRoutes = {
+ home: '/',
+ login: '/login',
+ agents: '/agents',
+ apiKeys: '/api-keys',
+ logs: '/logs',
+ usage: '/usage',
+ settings: '/settings',
+ workspaceSetup: '/workspace-setup',
+ wizard: '/wizard/'
+ };
}());
diff --git a/apps/ui/js/nav.js b/apps/ui/js/nav.js
index 50e544a..37f0d65 100644
--- a/apps/ui/js/nav.js
+++ b/apps/ui/js/nav.js
@@ -84,7 +84,7 @@
if (dropdown) {
dropdown.style.display = 'none';
}
- window.location.href = (window.APP_BASE || '') + 'html/settings.html#profile';
+ window.location.href = ((window.CrankRoutes && window.CrankRoutes.settings) || '/settings') + '#profile';
});
});
@@ -93,7 +93,7 @@
if (dropdown) {
dropdown.style.display = 'none';
}
- window.location.href = (window.APP_BASE || '') + 'html/settings.html';
+ window.location.href = (window.CrankRoutes && window.CrankRoutes.settings) || '/settings';
});
});
}
diff --git a/apps/ui/js/wizard.js b/apps/ui/js/wizard.js
index b82ae3e..5c9cc18 100644
--- a/apps/ui/js/wizard.js
+++ b/apps/ui/js/wizard.js
@@ -189,14 +189,14 @@ document.addEventListener('DOMContentLoaded', async function() {
var backToCatalog = document.getElementById('back-to-catalog');
if (backToCatalog) {
backToCatalog.addEventListener('click', function() {
- window.location.href = (window.APP_BASE || '') + 'index.html';
+ window.location.href = (window.CrankRoutes && window.CrankRoutes.home) || '/';
});
}
var closeBtn = document.querySelector('.progress-close');
if (closeBtn) {
closeBtn.addEventListener('click', function() {
- window.location.href = (window.APP_BASE || '') + 'index.html';
+ window.location.href = (window.CrankRoutes && window.CrankRoutes.home) || '/';
});
}
diff --git a/apps/ui/js/workspace-setup.js b/apps/ui/js/workspace-setup.js
index ce1ad09..edcf822 100644
--- a/apps/ui/js/workspace-setup.js
+++ b/apps/ui/js/workspace-setup.js
@@ -330,7 +330,7 @@ async function submitForm() {
setFormDirty(false);
if (workspaceFormState.isCreateMode) {
- window.location.href = (window.APP_BASE || '') + 'html/workspace-setup.html';
+ window.location.href = (window.CrankRoutes && window.CrankRoutes.workspaceSetup) || '/workspace-setup';
return;
}
diff --git a/apps/ui/js/workspace.js b/apps/ui/js/workspace.js
index 2f726ea..1b3b90b 100644
--- a/apps/ui/js/workspace.js
+++ b/apps/ui/js/workspace.js
@@ -117,7 +117,7 @@ function renderWorkspaceList() {
' ';
}).join('') +
'
' +
- '
' +
+ ' ' +
' ' +
'Workspace settings' +
' ';
diff --git a/apps/ui/nginx.conf b/apps/ui/nginx.conf
index 14b118a..a14db78 100644
--- a/apps/ui/nginx.conf
+++ b/apps/ui/nginx.conf
@@ -1,10 +1,96 @@
server {
listen 3000;
server_name _;
+ absolute_redirect off;
root /usr/share/nginx/html;
index index.html;
+ location = / {
+ try_files /index.html =404;
+ }
+
+ location = /index.html {
+ return 302 /;
+ }
+
+ location = /login {
+ try_files /html/login.html =404;
+ }
+
+ location = /agents {
+ try_files /html/agents.html =404;
+ }
+
+ location = /api-keys {
+ try_files /html/api-keys.html =404;
+ }
+
+ location = /logs {
+ try_files /html/logs.html =404;
+ }
+
+ location = /usage {
+ try_files /html/usage.html =404;
+ }
+
+ location = /settings {
+ try_files /html/settings.html =404;
+ }
+
+ location = /workspace-setup {
+ try_files /html/workspace-setup.html =404;
+ }
+
+ location = /wizard {
+ return 302 /wizard/;
+ }
+
+ location = /wizard/ {
+ try_files /html/wizard/index.html =404;
+ }
+
+ location ~ ^/wizard/(.+)$ {
+ rewrite ^/wizard/(.+)$ /html/wizard/$1 break;
+ try_files $uri =404;
+ }
+
+ location = /html/login.html {
+ return 302 /login;
+ }
+
+ location = /html/agents.html {
+ return 302 /agents;
+ }
+
+ location = /html/api-keys.html {
+ return 302 /api-keys;
+ }
+
+ location = /html/logs.html {
+ return 302 /logs;
+ }
+
+ location = /html/usage.html {
+ return 302 /usage;
+ }
+
+ location = /html/settings.html {
+ return 302 /settings;
+ }
+
+ location = /html/workspace-setup.html {
+ return 302 /workspace-setup$is_args$args;
+ }
+
+ location = /html/wizard/ {
+ return 302 /wizard/$is_args$args;
+ }
+
+ location = /html/wizard/index.html {
+ return 302 /wizard/;
+ }
+
location / {
try_files $uri $uri/ /index.html;
}
diff --git a/docs/alpine-ui-integration-plan.md b/docs/alpine-ui-integration-plan.md
index 9adb9b9..73bad74 100644
--- a/docs/alpine-ui-integration-plan.md
+++ b/docs/alpine-ui-integration-plan.md
@@ -2,7 +2,7 @@
## 1. Назначение документа
-Этот документ фиксирует, как переносимый Alpine UI из `apps/ui` должен подключаться к реальному backend.
+Этот документ фиксирует, как Alpine UI в `apps/ui` подключается к реальному backend.
Его задача:
@@ -13,12 +13,11 @@
## 2. Текущее состояние
-Сейчас `apps/ui` уже заменен на Alpine.js UI, перенесенный из `test-ui`.
+Сейчас `apps/ui` уже является основной Alpine.js UI-кодовой базой.
Важно:
-- `apps/ui` теперь является основной UI-кодовой базой;
-- `test-ui` остается fallback-источником и не должен использоваться как рабочая папка интеграции;
+- `apps/ui` является единственной рабочей UI-кодовой базой;
- новый UI пока опирается на `localStorage`, mock JSON и локальные сценарии;
- backend уже поддерживает `workspace`, `operations`, `agents`, `platform access`, `logs`, `usage`, но не все UI-flow закрыты полностью.
diff --git a/docs/as-is-to-be.md b/docs/as-is-to-be.md
index 653515d..c0f3c08 100644
--- a/docs/as-is-to-be.md
+++ b/docs/as-is-to-be.md
@@ -2,7 +2,7 @@
## 1. Назначение документа
-Этот документ фиксирует переход от текущего состояния проекта к целевой продуктовой модели, которую задает `test-ui`.
+Этот документ фиксирует переход от текущего состояния проекта к целевой продуктовой модели, отраженной в текущем Alpine UI.
## 2. As Is
diff --git a/docs/backend-gap-plan.md b/docs/backend-gap-plan.md
index 1083d3d..d17513c 100644
--- a/docs/backend-gap-plan.md
+++ b/docs/backend-gap-plan.md
@@ -2,7 +2,7 @@
## 1. Назначение документа
-Этот документ превращает `test-ui` и `docs/as-is-to-be.md` в конкретный backend-план.
+Этот документ превращает целевой Alpine UI и `docs/as-is-to-be.md` в конкретный backend-план.
Его задача:
@@ -16,7 +16,7 @@
- новая функциональность наращивается слоями сверху;
- сначала вводятся tenant boundary и agent publishing;
- потом access layer и observability;
-- перенос `test-ui` в `apps/ui` делается после фиксации backend-контрактов.
+- UI развивается в `apps/ui` после фиксации backend-контрактов.
## 3. Что сохраняем без переписывания
@@ -331,7 +331,7 @@
### Wave 5. UI integration
- заменить mock data реальными API
-- перенести `test-ui` в `apps/ui`
+- развивать и полировать Alpine UI в `apps/ui`
- пройти e2e сценарии
## 11. Что делаем следующим шагом
diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md
index 4234251..2513522 100644
--- a/docs/implementation-plan.md
+++ b/docs/implementation-plan.md
@@ -2,7 +2,7 @@
## 1. Назначение документа
-Этот документ фиксирует порядок перехода от текущего состояния проекта к целевой модели, заданной `test-ui`.
+Этот документ фиксирует порядок перехода от текущего состояния проекта к целевой Alpine UI модели.
Принцип:
@@ -101,7 +101,7 @@ DoD:
Цель:
-- перенести `test-ui` в `apps/ui` и подключить его к реальному backend.
+- довести `apps/ui` до полной работы на реальном backend.
DoD:
diff --git a/docs/operations-workspace-contracts.md b/docs/operations-workspace-contracts.md
index f617b85..7499244 100644
--- a/docs/operations-workspace-contracts.md
+++ b/docs/operations-workspace-contracts.md
@@ -9,9 +9,9 @@
Документ нужен как промежуточный слой между:
-- целевым UI в `test-ui`;
+- текущим Alpine UI в `apps/ui`;
- `docs/backend-gap-plan.md`;
-- будущей реализацией `admin-api`.
+- реализацией `admin-api`.
## 2. Общие правила