Add settings page for tag-to-company mappings and auto-create Paperclip projects
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m22s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m22s
When a case is created, a Paperclip project is now automatically created in the correct company based on the appeal_subtype tag. Tag-to-company mappings are managed via a new Settings page that pulls companies from Paperclip DB. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1881,6 +1881,7 @@ kbd {
|
||||
<a href="#/compose" id="navCompose">כתיבה</a>
|
||||
<a href="#/skills" id="navSkills">Skills</a>
|
||||
<a href="#/diagnostics" id="navDiagnostics">מצב מערכת</a>
|
||||
<a href="#/settings" id="navSettings">הגדרות</a>
|
||||
<button class="theme-toggle" id="themeToggle" onclick="toggleTheme()" title="החלף ערכת צבעים (Shift+D)">
|
||||
<span id="themeIcon">🌙</span>
|
||||
</button>
|
||||
@@ -2405,6 +2406,45 @@ kbd {
|
||||
<div class="empty">טוען...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══ Page: Settings ══ -->
|
||||
<div class="page" id="page-settings">
|
||||
<div class="page-header">
|
||||
<h2>הגדרות</h2>
|
||||
</div>
|
||||
|
||||
<!-- Tag → Company Mappings -->
|
||||
<div class="card">
|
||||
<div class="card-header">שיוך תגי תיקים לחברות Paperclip</div>
|
||||
<div class="card-body">
|
||||
<p style="color:#888;font-size:0.85em;margin-bottom:16px">כל תג ערר (סוג תיק) משויך לחברה ב-Paperclip. כשנפתח תיק חדש, הפרויקט נוצר אוטומטית בחברה המתאימה לפי התג.</p>
|
||||
|
||||
<!-- Add new mapping -->
|
||||
<div style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin-bottom:24px;padding:16px;background:var(--bg-secondary,#f8f9fa);border-radius:8px">
|
||||
<div style="flex:1;min-width:160px">
|
||||
<label style="display:block;font-size:0.8em;color:#888;margin-bottom:4px">תג ערר</label>
|
||||
<input type="text" id="settingsNewTag" placeholder="לדוגמה: building_permit" style="width:100%;padding:8px;border:1px solid var(--border,#ddd);border-radius:6px;background:var(--bg-primary,#fff);color:var(--text-primary)">
|
||||
</div>
|
||||
<div style="flex:1;min-width:160px">
|
||||
<label style="display:block;font-size:0.8em;color:#888;margin-bottom:4px">תיאור בעברית</label>
|
||||
<input type="text" id="settingsNewTagLabel" placeholder="לדוגמה: רישוי ובנייה" style="width:100%;padding:8px;border:1px solid var(--border,#ddd);border-radius:6px;background:var(--bg-primary,#fff);color:var(--text-primary)">
|
||||
</div>
|
||||
<div style="flex:1.5;min-width:200px">
|
||||
<label style="display:block;font-size:0.8em;color:#888;margin-bottom:4px">חברה ב-Paperclip</label>
|
||||
<select id="settingsCompanySelect" style="width:100%;padding:8px;border:1px solid var(--border,#ddd);border-radius:6px;background:var(--bg-primary,#fff);color:var(--text-primary)">
|
||||
<option value="">טוען חברות...</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="addTagMapping()" style="white-space:nowrap">הוסף שיוך</button>
|
||||
</div>
|
||||
|
||||
<!-- Existing mappings table -->
|
||||
<div id="tagMappingsTable">
|
||||
<div class="empty">טוען...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal for pattern examples -->
|
||||
@@ -2514,6 +2554,11 @@ function handleRoute() {
|
||||
document.getElementById('navCompose').classList.add('active');
|
||||
subtitle = 'כתיבת החלטה';
|
||||
initComposePage();
|
||||
} else if (hash === '#/settings') {
|
||||
document.getElementById('page-settings').classList.add('active');
|
||||
document.getElementById('navSettings').classList.add('active');
|
||||
subtitle = 'הגדרות';
|
||||
loadSettingsPage();
|
||||
}
|
||||
|
||||
document.getElementById('pageSubtitle').textContent = subtitle;
|
||||
@@ -4974,6 +5019,163 @@ async function loadCorpusList() {
|
||||
container.innerHTML = `<div class="empty">שגיאה בטעינה: ${esc(e.message)}</div>`;
|
||||
}
|
||||
}
|
||||
// ── Settings Page ─────────────────────────────────────────────────
|
||||
let _settingsCompanies = [];
|
||||
|
||||
async function loadSettingsPage() {
|
||||
await Promise.all([loadPaperclipCompanies(), loadTagMappings()]);
|
||||
}
|
||||
|
||||
async function loadPaperclipCompanies() {
|
||||
const sel = document.getElementById('settingsCompanySelect');
|
||||
try {
|
||||
const res = await fetch(`${API}/settings/paperclip-companies`);
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
_settingsCompanies = await res.json();
|
||||
// Build options safely via DOM
|
||||
sel.textContent = '';
|
||||
const defaultOpt = document.createElement('option');
|
||||
defaultOpt.value = '';
|
||||
defaultOpt.textContent = '— בחר חברה —';
|
||||
sel.appendChild(defaultOpt);
|
||||
for (const c of _settingsCompanies) {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = c.id;
|
||||
opt.dataset.name = c.name;
|
||||
opt.textContent = c.name + (c.identifier ? ` (${c.identifier})` : '');
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
} catch (e) {
|
||||
sel.textContent = '';
|
||||
const opt = document.createElement('option');
|
||||
opt.value = '';
|
||||
opt.textContent = 'שגיאה: ' + e.message;
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTagMappings() {
|
||||
const container = document.getElementById('tagMappingsTable');
|
||||
try {
|
||||
const res = await fetch(`${API}/settings/tag-mappings`);
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
const mappings = await res.json();
|
||||
if (!mappings.length) {
|
||||
container.textContent = '';
|
||||
const empty = document.createElement('div');
|
||||
empty.className = 'empty';
|
||||
empty.textContent = 'אין שיוכים מוגדרים עדיין';
|
||||
container.appendChild(empty);
|
||||
return;
|
||||
}
|
||||
|
||||
// Group by company
|
||||
const byCompany = {};
|
||||
for (const m of mappings) {
|
||||
const key = m.company_id;
|
||||
if (!byCompany[key]) byCompany[key] = { company_name: m.company_name || m.company_id, tags: [] };
|
||||
byCompany[key].tags.push(m);
|
||||
}
|
||||
|
||||
const table = document.createElement('table');
|
||||
table.style.cssText = 'width:100%;border-collapse:collapse;font-size:0.9em';
|
||||
|
||||
const thead = table.createTHead();
|
||||
const headerRow = thead.insertRow();
|
||||
headerRow.style.borderBottom = '2px solid var(--border,#ddd)';
|
||||
for (const label of ['Company', 'Tag', 'Label', '']) {
|
||||
const th = document.createElement('th');
|
||||
th.style.cssText = 'text-align:right;padding:8px';
|
||||
if (label === '') th.style.width = '60px';
|
||||
th.textContent = label;
|
||||
headerRow.appendChild(th);
|
||||
}
|
||||
|
||||
const tbody = table.createTBody();
|
||||
for (const [companyId, group] of Object.entries(byCompany)) {
|
||||
for (let i = 0; i < group.tags.length; i++) {
|
||||
const m = group.tags[i];
|
||||
const tr = tbody.insertRow();
|
||||
tr.style.borderBottom = '1px solid var(--border,#eee)';
|
||||
|
||||
if (i === 0) {
|
||||
const tdCompany = tr.insertCell();
|
||||
tdCompany.style.cssText = 'padding:8px;font-weight:600;vertical-align:top';
|
||||
tdCompany.rowSpan = group.tags.length;
|
||||
tdCompany.textContent = group.company_name;
|
||||
}
|
||||
|
||||
const tdTag = tr.insertCell();
|
||||
tdTag.style.padding = '8px';
|
||||
const code = document.createElement('code');
|
||||
code.style.cssText = 'background:var(--bg-secondary,#f0f0f0);padding:2px 6px;border-radius:4px';
|
||||
code.textContent = m.tag;
|
||||
tdTag.appendChild(code);
|
||||
|
||||
const tdLabel = tr.insertCell();
|
||||
tdLabel.style.padding = '8px';
|
||||
tdLabel.textContent = m.tag_label || '—';
|
||||
|
||||
const tdAction = tr.insertCell();
|
||||
tdAction.style.padding = '8px';
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'btn-icon btn-icon-danger';
|
||||
btn.title = 'הסר שיוך';
|
||||
btn.textContent = '✕';
|
||||
btn.addEventListener('click', () => deleteTagMapping(m.id));
|
||||
tdAction.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
container.textContent = '';
|
||||
container.appendChild(table);
|
||||
} catch (e) {
|
||||
container.textContent = '';
|
||||
const empty = document.createElement('div');
|
||||
empty.className = 'empty';
|
||||
empty.textContent = 'שגיאה: ' + e.message;
|
||||
container.appendChild(empty);
|
||||
}
|
||||
}
|
||||
|
||||
async function addTagMapping() {
|
||||
const tag = document.getElementById('settingsNewTag').value.trim();
|
||||
const tagLabel = document.getElementById('settingsNewTagLabel').value.trim();
|
||||
const sel = document.getElementById('settingsCompanySelect');
|
||||
const companyId = sel.value;
|
||||
const companyName = sel.selectedOptions[0]?.dataset?.name || '';
|
||||
|
||||
if (!tag) { showToast('יש להזין תג', 'error'); return; }
|
||||
if (!companyId) { showToast('יש לבחור חברה', 'error'); return; }
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API}/settings/tag-mappings`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tag, tag_label: tagLabel, company_id: companyId, company_name: companyName }),
|
||||
});
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
showToast('שיוך נוסף בהצלחה');
|
||||
document.getElementById('settingsNewTag').value = '';
|
||||
document.getElementById('settingsNewTagLabel').value = '';
|
||||
sel.value = '';
|
||||
await loadTagMappings();
|
||||
} catch (e) {
|
||||
showToast('שגיאה: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTagMapping(id) {
|
||||
if (!confirm('להסיר שיוך זה?')) return;
|
||||
try {
|
||||
const res = await fetch(`${API}/settings/tag-mappings/${id}`, { method: 'DELETE' });
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
showToast('שיוך הוסר');
|
||||
await loadTagMappings();
|
||||
} catch (e) {
|
||||
showToast('שגיאה: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user