feat: server-driven configurator settings via qt_settings
Replaces hardcoded JS category filters and config-type buttons with server-pushed settings synced from qt_settings (MariaDB) → local_qt_settings (SQLite). - new table local_qt_settings (AutoMigrate) — synced after component sync - GET /api/configurator-settings returns config_types, tab_config, always_visible_tabs, required_categories with hardcoded fallbacks - new-config modal: type buttons rendered from server data (Сервер/СХД static fallback) - configurator: TAB_CONFIG and category filter driven by server; required-category badge on tabs - SyncQtSettings wired into SyncComponents and SyncAll handlers (non-fatal on old server) - bible-local/server-contract-qt-settings.md — contract for server-side agent - page titles: OFS → QFS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
{{define "title"}}Мои конфигурации - OFS{{end}}
|
||||
{{define "title"}}QFS Мои конфигурации{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="space-y-4">
|
||||
@@ -55,12 +55,12 @@
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Тип оборудования</label>
|
||||
<div class="inline-flex rounded-lg border border-gray-200 overflow-hidden w-full">
|
||||
<button type="button" id="type-server-btn" onclick="setCreateType('server')"
|
||||
<div id="config-type-buttons" class="inline-flex rounded-lg border border-gray-200 overflow-hidden w-full">
|
||||
<button type="button" data-type="server" onclick="setCreateType('server')"
|
||||
class="flex-1 py-2 text-sm font-medium bg-blue-600 text-white">
|
||||
Сервер
|
||||
</button>
|
||||
<button type="button" id="type-storage-btn" onclick="setCreateType('storage')"
|
||||
<button type="button" data-type="storage" onclick="setCreateType('storage')"
|
||||
class="flex-1 py-2 text-sm font-medium bg-white text-gray-700 hover:bg-gray-50 border-l border-gray-200">
|
||||
СХД
|
||||
</button>
|
||||
@@ -532,18 +532,51 @@ async function cloneConfig() {
|
||||
}
|
||||
|
||||
let createConfigType = 'server';
|
||||
let _cfgSettings = null;
|
||||
|
||||
async function loadCfgSettings() {
|
||||
if (_cfgSettings) return _cfgSettings;
|
||||
try {
|
||||
const r = await fetch('/api/configurator-settings');
|
||||
if (r.ok) _cfgSettings = await r.json();
|
||||
} catch(e) { /* use hardcoded fallback */ }
|
||||
return _cfgSettings;
|
||||
}
|
||||
|
||||
function renderConfigTypeButtons(types) {
|
||||
if (!types || !types.length) return;
|
||||
const el = document.getElementById('config-type-buttons');
|
||||
if (!el) return;
|
||||
el.innerHTML = types
|
||||
.sort((a, b) => (a.display_order || 0) - (b.display_order || 0))
|
||||
.map((t, i) => {
|
||||
const borderClass = i > 0 ? 'border-l border-gray-200' : '';
|
||||
return `<button type="button" data-type="${t.code}" onclick="setCreateType('${t.code}')"
|
||||
class="flex-1 py-2 text-sm font-medium ${borderClass} bg-white text-gray-700 hover:bg-gray-50">
|
||||
${t.name_ru || t.code}
|
||||
</button>`;
|
||||
}).join('');
|
||||
// activate first type
|
||||
const firstCode = types[0].code;
|
||||
createConfigType = firstCode;
|
||||
setCreateType(firstCode);
|
||||
}
|
||||
|
||||
function setCreateType(type) {
|
||||
createConfigType = type;
|
||||
document.getElementById('type-server-btn').className = 'flex-1 py-2 text-sm font-medium ' +
|
||||
(type === 'server' ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 hover:bg-gray-50 border-l border-gray-200');
|
||||
document.getElementById('type-storage-btn').className = 'flex-1 py-2 text-sm font-medium border-l border-gray-200 ' +
|
||||
(type === 'storage' ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 hover:bg-gray-50');
|
||||
document.querySelectorAll('#config-type-buttons button').forEach(btn => {
|
||||
const active = btn.dataset.type === type;
|
||||
btn.className = 'flex-1 py-2 text-sm font-medium ' +
|
||||
(active
|
||||
? 'bg-blue-600 text-white border-l border-gray-200'
|
||||
: 'bg-white text-gray-700 hover:bg-gray-50 border-l border-gray-200');
|
||||
});
|
||||
}
|
||||
|
||||
function openCreateModal() {
|
||||
createConfigType = 'server';
|
||||
setCreateType('server');
|
||||
loadCfgSettings().then(s => renderConfigTypeButtons(s && s.config_types));
|
||||
document.getElementById('opportunity-number').value = '';
|
||||
document.getElementById('create-project-input').value = '';
|
||||
document.getElementById('create-modal').classList.remove('hidden');
|
||||
|
||||
Reference in New Issue
Block a user